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) {