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

接着上篇,这里想分享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 extends RecyclerAdapter {

    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

你可能感兴趣的:(我是如何搭建Android快速开发框架的之UI篇(中))