• 打造属于自己的安卓Metro界面


    前言:

    各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客快哭了,哪里有女王哪里就有压迫呀有木有!好了闲话少说,上一篇博客(Android Metro风格的Launcher开发系列第二篇)说到Launcher主体框架用ViewPager来实现,这一篇博客咱们来说说每一个page的具体实现。

    PagerAdapter:

            Launcher主体ViewPager实现就引出了PagerAdapter,PagerAdapter是android.support.v4包中的类,它的子类有FragmentPagerAdapter, FragmentStatePagerAdapter,这两个adapter都是Fragment的适配器,这里因为没有用到Fragment所以这里不讲,我只讲PagerAdapter。关于PageAapter的描述,Google官网原文是这样的:Base class providing the adapter to populate pages inside of a ViewPager.  You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter or FragmentStatePagerAdapter,大致就是说PagerAdapter是ViewPager提供的一个适配器,方便我们对ViewPager的每一个View进行控制。我的PagerAdapter是这样实现的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    public  class  LauncherAdapter extends PagerAdapter {
         private  ArrayList<PageViewItem> mViews;
      
         public  LauncherAdapter(ArrayList<PageViewItem> views) {
             mViews = views;
         }
      
         @Override
         public  void  destroyItem(View arg0,  int  arg1, Object arg2) {
             ((ViewPager) arg0).removeView(mViews.get(arg1));
         }
      
         @Override
         public  void  finishUpdate(View arg0) {
         }
      
         @Override
         public  int  getCount() {
             if  (mViews != null) {
                 return  mViews.size();
             }
             return  0;
         }
      
         public  View getCurrentView( int  currentID) {
             return  mViews.get(currentID);
         }
      
         @Override
         public  Object instantiateItem(View arg0,  int  arg1) {
             ((ViewPager) arg0).addView(mViews.get(arg1));
             return  mViews.get(arg1);
         }
      
         @Override
         public  boolean isViewFromObject(View arg0, Object arg1) {
             return  (arg0 == arg1);
         }
      
         @Override
         public  void  restoreState(Parcelable arg0, ClassLoader arg1) {
         }
      
         @Override
         public  Parcelable saveState() {
             return  null;
         }
      
    }

    PageViewItem:

            PagerAdapter的getCurrentView方法返回的每一个view都是自定义View,为什么要自定义呢?因为在每一个图标获取焦点放大的时候会与旁边的图标有重叠部分,ViewPager每一页view都是一个FrameLayout,在绘制view的时候是按照一定的顺序绘制的,就会遇到焦点view放大后显示的效果是被旁边的view压了一部分,如果不改变view绘制顺序就不能避免这个问题。

    如上图所示,图一显示效果就是焦点view放大,改变绘制顺序的实现效果。改变绘制顺序其实就是重写ViewGroup的getChildDrawingOrder(int childCount, int i)方法,每一次绘制时,最后返回focusview所在的viewgroup中的index就行了。

    CellView:

     如上图所示,每一个正方形的view我在这里叫做CellView,它也是一个自定义的view,自定义主要是为了实现:

    1、获取焦点时放大和丢掉焦点时缩小效果,这里是应用了属性动画,ViewPropertyAnimator可以通过View的animate()方法获取的,具体动画实现如下:

    1
    2
    3
    4
      mPropertyAnimator.scaleX((width + mScaleX) / width)
                             .scaleY((height + mScaleY) / height).setDuration(duration)
                             .setInterpolator( new  DecelerateInterpolator())
                             .start();

    2、在xml文件灵活配置一些CellView的属性,比如点击打开的应用,呈现的ICON获取地址,焦点x、y的放大值等,CellView对应的属性定义attrs.xml文件如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version= "1.0"  encoding= "utf-8" ?>
    <resources>
      
         <declare-styleable name= "Launcher_ScaleView" >
             <attr name= "parentID"  format= "integer"  />
             <attr name= "resUrl"  format= "string"  />
             <attr name= "resType"  format= "integer"  />
             <attr name= "isRightEdge"  format= "boolean"  />
             <attr name= "isLeftEdge"  format= "boolean"  />
             <attr name= "isTopEdge"  format= "boolean"  />
             <attr name= "isBottomEdge"  format= "boolean"  />
             <attr name= "scaleX"  format= "integer"  />
             <attr name= "scaleY"  format= "integer"  />
             <attr name= "packageName"  format= "string"  />
             <attr name= "activityName"  format= "string"  />
             <attr name= "intentKey"  format= "string"  />
             <attr name= "intentValue"  format= "string"  />
             <attr name= "focusType"  format= "integer"  />
         </declare-styleable>
      
    </resources>

    3、实现在用遥控器移动焦点时不会焦点错乱,在开发遥控器应用时一个很大的问题就是焦点在移动时焦点错乱,基本上应用UI bug至少有一半时焦点bug,这个应用我为了防止焦点错乱定义了CellView的边界属性,上面的xml文件中isXXEdge就是,这样在焦点移动到边界时可以进行Page之间的切换和其他处理,防止焦点在进入每一个page时出现错乱。

        下面来看一下实现的具体效果:

    总结:以上就是Metro风格Launcher实现,我用了三篇博客来讲解这个应用,所有效果的实现都是自己摸索的,应该还有更好的实现方法,大家可以多多交流提出自己的看法,也可以关注我的微信号coder_online,以上谢谢!

      第一时间获得博客更新提醒,以及更多技术信息分享,欢迎关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或搜索微信号coder_online即可关注,我们可以在线交流。

                                                

  • 相关阅读:
    vs2015+opencv3.3.1 +Eigen 3.3.4 c++实现 薄膜插值 泊松图像编辑(v=0||Δf=0)
    vs2015+opencv3.3.1 实现 c++ 双边滤波器(Bilateral Filter)
    vs2015+opencv3.3.1 实现 c++ 彩色高斯滤波器(Gaussian Smoothing, Gaussian Blur, Gaussian Filter)
    vs2015+opencv3.3.1 实现 c++ 灰度高斯滤波器
    vs2015+opencv3.3.1 实现 c++ 直方图均衡化
    函数形参为基类数组,实参为继承类数组,下存在的问题------c++程序设计原理与实践(进阶篇)
    函数返回值string与返回值bool区别------c++程序设计原理与实践(进阶篇)
    (c++11)随机数------c++程序设计原理与实践(进阶篇)
    实现求解线性方程(矩阵、高斯消去法)------c++程序设计原理与实践(进阶篇)
    Centos ATI 显卡安装,“LCD 信号超出范围” 解决方法
  • 原文地址:https://www.cnblogs.com/lonelyonline/p/4404861.html
Copyright © 2020-2023  润新知