美文网首页安卓控件android开发技巧Android iOS开发知识库
我是如何搭建Android快速开发框架的之UI篇(中)

我是如何搭建Android快速开发框架的之UI篇(中)

作者: droidlover | 来源:发表于2016-12-13 16:03 被阅读2319次

    接着上篇,这里想分享ListAdapter、RecyclerView的封装。众所周知,ListAdapter以及RecyclerView都是列表控件,Google更推荐大家使用RecyclerView。关于RecyclerView的基本使用,不在本篇的讨论范围内。

    ListAdapter

    ListAdapter作为ListView的数据适配器,为ListView提供数据源。在我们的频繁使用中,发现:对Adapter的编写主要集中在几部分:

    • 实现getView(int position, View convertView, ViewGroup parent)方法
    • 数据集合的增删修改,频繁手动调用 notifyDataSetChange()方法

    而在getView()方法中,我们通常会做这么几件事:

    • 设置布局文件
    • 数据与控件的绑定
    • 控件事件注册

    转化成代码:

     if (convertView == null) {
           convertView = View.inflate(context, getLayoutId(), null);
           holder = new ViewHolder(convertView);
           convertView.setTag(holder);
       } else {
           holder =  convertView.getTag();
       }
       
       bindItem();      //绑定数据
       setEvent();      //绑定事件
       
       return convertView;
    

    由于Adapter可多个itemType,因此封装的时候缤纷两路,RecyclerAdapter的封装也是如此。

    Step1 封装XListAdapter,作为所有Adapter的基类,子类可实现getView()方法

    XListAdapter中主要实现了数据集的增删修改常用操作事件绑定接口 等功能。

    + addData()
    + setData()
    + clearData
    + addElement()
    + removeElement()
    + getColor()
    + getDrawable()
    + visible()
    + gone()
    + invisible()
    ...
    

    Step2 封装SimpleListAdapter,实现单viewType的需求

    核心如下:

     @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            H holder = null;
            T item = data.get(position);
    
            if (convertView == null) {
                convertView = View.inflate(context, getLayoutId(), null);
                holder = newViewHolder(convertView);
    
                convertView.setTag(holder);
            } else {
                holder = (H) convertView.getTag();
            }
    
            convert(holder, item, position);
    
            return convertView;
        }
    

    子类则摆脱了这段魔鬼一样的代码,只需要实现这三个方法:

    protected abstract H newViewHolder(View convertView); //创建viewHolder
    
    protected abstract int getLayoutId();       //设置布局资源id
    
    protected abstract void convert(H holder, T item, int position);    //数据绑定与事件绑定
    

    Step3 事件绑定接口

    为了方便事件的统一处理,我抽象了一个抽象类ListItemCallback

     public void onItemClick(int position, T model, int tag) {}         //单击
    
     public void onItemLongClick(int position, T model, int tag) {}     //长按
    

    参数:

    • position : 就是getView中的position,位置
    • model : 绑定的数据实体
    • tag : 事件标识,自己定义

    a. 为什么定义的是抽象类,而不是接口?

    因为接口中的方法需要全部实现,而抽象类可以选择性的override,显然,我们通常只需要重写onItemClick方法

    b. 如何使用呢?

    holder.itemView.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             if (getCallback() != null) {
                 getCallback().onItemClick(position, item, TAG_VIEW);
             }
         }
     });
    

    c. 为什么我不选择很常见的SparseArray那种封装的CommonAdapter

    因为我不喜欢那种编码style,建议将Adapter单独类

    RecyclerView

    RecyclerView的封装一般体现在:

    • 下拉刷新、上拉加载更多
    • header、footer
    • divider
    • ...

    鉴于此,我之前搞了个ARecyclerView,主要有这些特性:

    • ARecyclerView继承自RecyclerView,它就是一个封装了常见功能的RecyclerView,而不是继承FrameLayout
    • ARecyclerView中实现了Header、Footer,header和Footer可以有多个
    • ARecyclerView的每一个header、footer的viewType是不同的,而大部分开源库的header、footer的viewtype是相同的,其直接后果是界面卡顿
    • ARecyclerView可以做出几乎任何的界面效果,可以取代ScrollView,你只需要使用header或者footer
    • ARecyclerView中实现了上拉加载更多,可以自定义加载更多的效果,只需要实现LoadMoreUIHandler接口即可
    • ARecyclerView并未实现下拉刷新功能,您可以选择SwipeRefreshLayout或者其他的下拉刷新viewGroup包裹,即你可以自由选择下拉刷新功能的实现。
    • 为了方便自定义使用,特别集成了XRecyclerContentLayout控件,你可以根据业务进行扩展,XRecyclerContentLayout只是一个示例,当然也可以满足绝大部分需求了

    由于其实现相对复杂,推荐大家可以去看看源码,app mudule中是完整的实例

    XDroid中,我新增了SimpleRecAdapter,应对单itemType的需求。具体思想和ListAdapter很相似

    public abstract class SimpleRecAdapter<T, F extends RecyclerView.ViewHolder> extends RecyclerAdapter<T, F> {
    
        public SimpleRecAdapter(Context context) {
            super(context);
        }
    
        @Override
        public F onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(), parent, false);
            return newViewHolder(view);
        }
    
        public abstract F newViewHolder(View itemView);
    
        public abstract int getLayoutId();
    
    }
    

    T 是item的实体类,F是ViewHolder的实体类

    下一篇会谈谈ContentLayout的实现过程。

    XDroid项目是我在两年的开发中积累的一个Android快速开发框架,目前包含UI层、缓存、图片加载、日志、路由、Api请求、事件订阅、工具类等。下一步会进行mvp、rx全家桶、retrofit、权限适配等工作。欢迎大家提出宝贵意见,指正不足。

    最后附上链接: https://github.com/limedroid/XDroid

    相关文章

      网友评论

      • 过期的薯条:深有同感,每次新项目都是copy,就项目,一点一点搬运过来,超级麻烦。不知道楼主是怎么写 的。
      • 波波一起飞:你这里的 路由 指的是什么?
      • 波波一起飞:先全部看完你的文章先,接着看代码,不过直接看XDroidMvp这个,新项目希望能用上
      • AR7_:就冲你回答别人问题那么积极,加油。
      • a6f1773c3198:要坚持更新呦
      • d07e1834a502:我对着你的代码自己写了一遍,加深自己的整体框架搭建的思想,很感谢,给新手机会
        droidlover:@哪天幸福醒来 一起努力。。期待进步
      • 765406b5a6a3:我想开发一款商城的app,应该怎么使用
        droidlover:@钺飓风 那些东西是在config.gradle文件中定义的,你可以看看那个文件,对了还需要在工程gradle中引用:apply from: "conf.gradle" 具体的可参考我的demo
        eirunye:里面的
        compileSdkVersion rootProject.ext.android.compileSdkVersion
        buildToolsVersion rootProject.ext.android.buildToolsVersion

        defaultConfig {
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        }
        会报着个错误,如何修改呢?
        droidlover:@的哈时间到了
        step1

        clone 'XDroid'库到本地:

        git clone https://github.com/limedroid/XDroid.git
        step2

        将library作为依赖库,在您的app module 中 添加如下依赖:

        compile project(':library')
        step3

        修改XDroidConf配置类,主要针对log、cache、router、imageloader。若采用默认配置,此步骤可略过.

        具体的可以参考app里面的写法

      本文标题:我是如何搭建Android快速开发框架的之UI篇(中)

      本文链接:https://www.haomeiwen.com/subject/hjkbmttx.html