Android Metro风格的Launcher开发系列第三篇



前言:

各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客快哭了,哪里有女王哪里就有压迫呀有木有!好了闲话少说,上一篇博客(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. public class LauncherAdapter extends PagerAdapter {  
  2.     private ArrayList<PageViewItem> mViews;  
  3.   
  4.     public LauncherAdapter(ArrayList<PageViewItem> views) {  
  5.         mViews = views;  
  6.     }  
  7.   
  8.     @Override  
  9.     public void destroyItem(View arg0, int arg1, Object arg2) {  
  10.         ((ViewPager) arg0).removeView(mViews.get(arg1));  
  11.     }  
  12.   
  13.     @Override  
  14.     public void finishUpdate(View arg0) {  
  15.     }  
  16.   
  17.     @Override  
  18.     public int getCount() {  
  19.         if (mViews != null) {  
  20.             return mViews.size();  
  21.         }  
  22.         return 0;  
  23.     }  
  24.   
  25.     public View getCurrentView(int currentID) {  
  26.         return mViews.get(currentID);  
  27.     }  
  28.   
  29.     @Override  
  30.     public Object instantiateItem(View arg0, int arg1) {  
  31.         ((ViewPager) arg0).addView(mViews.get(arg1));  
  32.         return mViews.get(arg1);  
  33.     }  
  34.   
  35.     @Override  
  36.     public boolean isViewFromObject(View arg0, Object arg1) {  
  37.         return (arg0 == arg1);  
  38.     }  
  39.   
  40.     @Override  
  41.     public void restoreState(Parcelable arg0, ClassLoader arg1) {  
  42.     }  
  43.   
  44.     @Override  
  45.     public Parcelable saveState() {  
  46.         return null;  
  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. mPropertyAnimator.scaleX((width + mScaleX) / width)  
  2.                        .scaleY((height + mScaleY) / height).setDuration(duration)  
  3.                        .setInterpolator(new DecelerateInterpolator())  
  4.                        .start();  
 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. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <declare-styleable name="Launcher_ScaleView">  
  5.         <attr name="parentID" format="integer" />  
  6.         <attr name="resUrl" format="string" />  
  7.         <attr name="resType" format="integer" />  
  8.         <attr name="isRightEdge" format="boolean" />  
  9.         <attr name="isLeftEdge" format="boolean" />  
  10.         <attr name="isTopEdge" format="boolean" />  
  11.         <attr name="isBottomEdge" format="boolean" />  
  12.         <attr name="scaleX" format="integer" />  
  13.         <attr name="scaleY" format="integer" />  
  14.         <attr name="packageName" format="string" />  
  15.         <attr name="activityName" format="string" />  
  16.         <attr name="intentKey" format="string" />  
  17.         <attr name="intentValue" format="string" />  
  18.         <attr name="focusType" format="integer" />  
  19.     </declare-styleable>  
  20.   
  21. </resources>  
<?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即可关注,我们可以在线交流。

                                                          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android_tv_metro是一款安卓版TV Metro框架和服务器API。API和数据结构专辑和显示项目:Metro风格是由两个元素构成专辑可以包含多张专辑和显示项目显示项目可以被定义为视频,游戏,应用程序,音乐等您可以从显示项目中删除你自己的游戏/应用/视频详细条目主页也被定义为专辑。API风格API描述http://host/v1/ns/type/?id=res_id NS:命名空间,资源类型类型:项目或项目列表ID:后端服务器系统的资源ID详细信息http://host/game(video/app)/item?id=12346 return item list专辑http://host/game(video/app)/album?id=6464 return album类别http://host/game(video/app)/category?id=123456 return album注意:专辑和类别接近同一概念。选项卡“应用程序/游戏”选项卡“视频”选项卡“视频类别”首页JSON定义首页JSON示例服务器API定义请看:https://github.com/XiaoMi/android_tv_metro/raw/master/server/TVMarketAPI.md首页显示数据{    "data": [        {            "items": [display items],            "images": {},            "name": "TAB 1",            "id": "recommend",            "type": "album",            "ns": "video"        },        {            "items": [display item],            "images": {},            "name": "TAB 2",            "id": "recommend",            "type": "album",            "ns": "video"        }    ] }显示项目:{    "target": {        "type": "item"    },    "images": {        "back": {            "url": "",            "ani": {},            "pos": {}        }    },    "name": "Display Name)",    "times": {        "updated": 1409202939,        "created": 1409202939    },    "_ui": {        "layout": {            "y": 2,            "x": 3,            "w": 1,            "h": 1        },        "type": "metro_cell_banner"    },    "id": "987722",    "type": "item",    "ns": "video" }专辑{ "data": [     {         "items": [display items],         "images": { },         "name":"game tab name",         "times": {             "updated": 0,             "created": 0         },         "_ui": {             "type": "metro"         },         "id": "recommend",         "type": "album",         "ns": "game"     },     {         "items": [display items],         "images": { },         "name": "game tab Name",         "times": {             "updated": 0,             "created": 0         },         "_ui": {             "type": "metro"         },         "id": "categories",         "type": "album",         "ns": "game"     },     {         "items": [dispay items],         "images": { },         "name": "video tab name",         "times": {             "updated": 0,             "created": 0         },         "_ui": {             "type": "metro"         },         "id": "recommend",         "type": "album",         "ns": "video"     },     {         "items": [display items],         "images": { },         "name": "video tab name",         "times": {             "updated": 0,             "created": 0         },         "_ui": {             "type": "metro"         },         "id": "categories",         "type": "album",         "ns": "video"     } ], "preload": {     "images": [] }, "update_time": 0 }显示项目{ "target": {     "type": "item" }, "images": {     "text": {         "url": "",         "ani": {},         "pos": {}     },     "icon": {         "url": "",         "ani": {},         "pos": {}     },     "back": {         "url": "http://xxx/fffff.png",         "ani": {},         "pos": {}     },     "spirit": {         "url": "",         "ani": {},         "pos": {}     } }, "name": "name", "times": {     "updated": 1404466152,     "created": 1404454443 }, "_ui": {     "type": "metro_cell_banner",     "layout": {         "y": 1,         "x": 1,         "w": 1,         "h": 2     } }, "id": "180", "type": "item", "ns": "game" }TV Metro库和APIandroid库:提供一个建立sw540dp metro布局的框架。API:服务器API和数据结构。该框架能够帮助您轻松构建一个TV metro UI风格的应用程序。至于具体的业务数据定义,你需要自己处理。android库:用于专辑的RecommendCardView Card浏览GenericSubjectLoader Loader(选项卡是专辑的一个实例)如何集成Android库?你只需要继承MainActivity并执行选项卡装载。请参阅TVMetroSample应用如何运行自己的服务器?1.定义你的主页数据2.执行您的详细资料/列表API下载测试APK下载测试APK,你可以在Android平板或电视运行点击下载设计文档:https://github.com/XiaoMi/android_tv_metro/raw/master/design/app_api.ppt 标签:Android
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值