http://winuxxan.blog.51cto.com/2779763/533289
Android的Launcher界面功能菜单是一个列表,当应用程序较多时,可以向下滑动查看其它,如下图。那能不能将功能菜单做成横向拖动,并且分屏的效果呢?
本文对该问题进行研究,要达到的目标如下:
1、可以实现应用程序的分屏显示,当一屏放不下时,放入另一个屏。
2、屏与屏之间切换为横向。
3、屏与屏之间切换时有动画效果,一个屏退出,一个屏出现。
本文的方法暂时没有解决屏幕切换随着手的移动而逐渐切换的问题,但是本文的屏幕切换可以采用手势的方式。
分屏和横向显示不是很难解决的问题,关键问题在于动画效果的实现。由于在屏幕切换时两个屏同时发生动画,一个退出,一个进入,因此至少要同时存在两个View。实际上Android已经为我们考虑了这种情况。ViewSwitcher就是专门针对这种情况而设计的。
ViewSwitcher内部保存了两个View,通过我们的控制可以显示前一个和后一个,并且我们可以设置在切换中两个View的动画。View的生成为ViewFactory生成。该类还是比较简单的,需要详细研究参考google文档和源代码。
多的不说,上代码吧。
首先我们模拟一下功能菜单的数据部分,也就是分几个屏,每个屏有哪些应用之类的东西。注释较多,不多解释。
- /**
- * 该类模拟了功能菜单的数据部分
- */
- public class MenuData {
- /**该常量代表每一屏能够容纳的应用程序数目*/
- public static final int NUMBER_IN_ONE_SCREEN = 9;
- /**该类代表每个应用程序的数据部分*/
- public static class DataItem {
- public String dataName; //应用程序名称
- public Drawable drawable; //应用程序图标
- }
- /**该类代表了一个屏的所有应用程序*/
- public static class MenuDataOneScreen {
- ArrayList<DataItem> mDataItems = new ArrayList<DataItem>();
- }
- /**该数据时该类的主要部分,所有屏的列表,实际上该类就是代表了所有的屏*/
- ArrayList<MenuDataOneScreen> mScreens = new ArrayList<MenuDataOneScreen>();
- /**对该类进行赋予数据*/
- public void setMenuItems(ArrayList<DataItem> dataItems) {
- int screenNum = dataItems.size() / NUMBER_IN_ONE_SCREEN;
- int remain = dataItems.size() % NUMBER_IN_ONE_SCREEN;
- screenNum += remain == 0 ? 0 : 1;
- int pos = 0;
- for (int i = 0; i < screenNum; i++) {
- MenuDataOneScreen screen = new MenuDataOneScreen();
- for (int j = 0; j < NUMBER_IN_ONE_SCREEN; j++) {
- if (pos <= dataItems.size() - 1) {
- screen.mDataItems.add(dataItems.get(pos));
- pos++;
- }
- }
- mScreens.add(screen);
- }
- }
- /**获取屏的数目*/
- public int getScreenNumber() {
- return mScreens.size();
- }
- /**根据屏的索引,获取某个屏的数据*/
- public MenuDataOneScreen getScreen(int screenIndex) {
- return mScreens.get(screenIndex);
- }
- }
然后,我们重载ViewFactory类,定义我们如何生成View,生成什么样的View。
- public class SlideViewFactory implements ViewFactory{
- LayoutInflater mInflater;
- public SlideViewFactory(Context context) {
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
- /**这个函数就是得到我们要生成的View,这里实际上直接从布局得到,
- *我们定义的是一个GridView ,一个GridView用于显示一屏的应用程序*/
- public View makeView() {
- return mInflater.inflate(R.layout.slidelistview, null);
- }
- }
从上面的代码我们可以看出,我们生成的View实际是一个GridView,GridView要想和数据关联,则需要一个Adapter,因此我们下面定义该Adapter:
- public class OneScreenListAdapter extends BaseAdapter{
- private MenuDataOneScreen mScreen;
- private LayoutInflater mInflater;
- public OneScreenListAdapter(Context context) {
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
- /**这里将数据赋予Adapter*/
- public void setScreenData(MenuDataOneScreen screenData) {
- mScreen = screenData;
- }
- public int getCount() {
- return mScreen.mDataItems.size();
- }
- public Object getItem(int position) {
- return mScreen.mDataItems.get(position);
- }
- public long getItemId(int position) {
- return position;
- }
- /**该函数中将数据和View进行关联*/
- public View getView(int position, View convertView, ViewGroup parent) {
- View view = convertView;
- if (convertView == null) {
- view = mInflater.inflate(R.layout.labelicon, null);
- }
- ImageView imageView = (ImageView) view.findViewById(R.id.imageview);
- TextView textView = (TextView) view.findViewById(R.id.textview);
- imageView.setImageDrawable(mScreen.mDataItems.get(position).drawable);
- textView.setText(mScreen.mDataItems.get(position).dataName);
- return view;
- }
- }
下面是继承ViewSwitcher的部分,用来实现两个屏的切换。
- /**该部分是ViewSwitcher的重载,用该类实现两个屏的切换和切换的动画实现*/
- public class SlideMenuSwitcher extends ViewSwitcher{
- private MenuData mMenuData;
- private int mCurrentScreen;
- private Context mContext;
- public SlideMenuSwitcher(Context context, AttributeSet attrs) {
- super(context, attrs);
- setFactory(new SlideViewFactory(context));
- // setAnimateFirstView(false);
- mContext = context;
- }
- /**通过该方法将数据赋值进去,并且将初始的屏显示出来*/
- public void setData(ArrayList<DataItem> dataItems) {
- mMenuData = new MenuData();
- mMenuData.setMenuItems(dataItems);
- mCurrentScreen = mMenuData.getScreenNumber() / 2;
- GridView listView = (GridView) getCurrentView();
- OneScreenListAdapter adapter = new OneScreenListAdapter(mContext);
- adapter.setScreenData(mMenuData.getScreen(mCurrentScreen));
- listView.setAdapter(adapter);
- }
- /**该方法用于显示下一屏*/
- public void showNextScreen() {
- if (mCurrentScreen < mMenuData.getScreenNumber() - 1) {
- mCurrentScreen++;
- setInAnimation(mContext, R.anim.slide_in_right);
- setOutAnimation(mContext, R.anim.slide_out_left);
- } else {
- return;
- }
- setViewData(mCurrentScreen);
- showNext();
- }
- /**该方法用于显示上一屏*/
- public void showPreviousScreen() {
- if (mCurrentScreen > 0) {
- mCurrentScreen--;
- setInAnimation(mContext, R.anim.slide_in_left);
- setOutAnimation(mContext, R.anim.slide_out_right);
- } else {
- return;
- }
- setViewData(mCurrentScreen);
- showPrevious();
- }
- private void setViewData(int index) {
- GridView listView = (GridView) getNextView();
- OneScreenListAdapter adapter = new OneScreenListAdapter(mContext);
- adapter.setScreenData(mMenuData.getScreen(index));
- listView.setAdapter(adapter);
- }
- }
我们将在一个Activity中,将我们做好的东西实现。首先在布局中将我们写的SlideMenuSwitcher。
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <com.winuxxan.SlideMenu.SlideMenuSwitcher
- android:id="@+id/slide_view"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- />
- <Button
- android:id="@+id/button_prev"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:text="<--"
- />
- <Button
- android:id="@+id/button_next"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:text="-->"
- />
- </RelativeLayout>
最后,实现我们的Activity:
- public class SlideMenuActivity extends Activity {
- /** Called when the activity is first created. */
- SlideMenuSwitcher switcher;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- switcher = (SlideMenuSwitcher) findViewById(R.id.slide_view);
- switcher.setData(makeItems()); //将24个应用程序赋值到swithcer中。
- findViewById(R.id.button_next).setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- switcher.showNextScreen(); //点击右边按钮,显示下一屏,当然可以采用手势
- }
- });
- findViewById(R.id.button_prev).setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- switcher.showPreviousScreen(); //点击左边按钮,显示上一屏,当然可以采用手势
- }
- });
- }
- /**模拟24个应用程序*/
- private ArrayList<DataItem> makeItems() {
- ArrayList<DataItem> items = new ArrayList<DataItem>();
- for (int i = 0; i < 24; i++) {
- String label = "" + i;
- Drawable drawable = getResources().getDrawable(R.drawable.icon);
- DataItem item = new DataItem();
- item.dataName = label;
- item.drawable = drawable;
- items.add(item);
- }
- return items;
- }
- }
好了,运行我们的应用程序,看下,效果是否是我们想要的?(动画效果没法抓图)