【干货】Android真正的“万能”Adapter

96
FullStack
0.7 2016.04.13 21:49* 字数 579

最近看到不少封装Adapter的库,但是都感觉不够方便。今天给大家介绍一个真正的“万能”Adapter(源码地址),精髓就在于一个Adapter同时适用于RecyclerView、ListView、GridView、Spinner等。

源码结构图.png

主要特性

  • 减少大量代码!减少大量代码!减少大量代码!(重说三)
  • 支持header和footer。
  • 支持RecyclerView的item点击事件。
  • 隐藏ViewHolder相关的所有代码。
  • 一个SuperAdapter同时支持BaseAdapterRecyclerView.Adapter
  • 封装Adapter数据源变动操作。
  • item加载动画。

如何使用

如果是个简单布局的Adapter,可以简写为如下示例代码:

public class SingleAdapter extends SuperAdapter<MockModel> {
    public SingleAdapter(Context context, List<MockModel> list, int layoutResId) {
        super(context, list, layoutResId);
    }

    @Override
    public void onBind(SuperViewHolder holder, int viewType, int position, MockModel item) {
        holder.setText(R.id.tv_name, item);
    }
}

可以看出除了构造方法,只需要重写一个onBind()方法就够了。
然后在Activity(or Fragment)中调用:

mSingleAdapter = new RecyclerSingleAdapter(context, list, R.layout.your_item);  
recyclerView.setAdapter(mSingleAdapter);

其中SuperViewHolder为通用的holder封装类,提供了一系列的便捷方法(ChainSetter),而且可以链式调用,如:

ChainSetter部分方法.png

还可以使用getView(int viewId)来确定一个item的view:

@Override
public void onBind(SuperViewHolder holder, int viewType, int position, String item) {
    holder.setText(R.id.tv_name, item);
    ImageView img = holder.getView(R.id.iv_portrait);
    img.setImageResource(resId);
}

当然也支持多item布局,需要提供一个IMulItemViewType<T>接口:

public class MultipleAdapter extends SuperAdapter<MockModel> {
    public MultipleAdapter(Context context, List<MockModel> list, IMulItemViewType<MockModel> multiItemViewType) {
        super(context, list, multiItemViewType);
    }

    @Override
    public void onBind(SuperViewHolder holder, int viewType, int position, MockModel item) {
        switch (viewType) {
            case 0:
                holder.setText(R.id.tv_name, item.getName());
                break;
            case 1:
                holder.setText(R.id.tv_name, item.getName());
                holder.setImageResource(R.id.iv_portrait, R.mipmap.ic_launcher);
                holder.setText(R.id.tv_age, String.valueOf(item.getAge()));
                break;
        }
    }
}

然后调用(注意构造方法的参数与单布局的区别):

multiAdapter = new MultipleAdapter(getContext(), list, new IMulItemViewType<MockModel>() {
                @Override
                public int getItemViewType(int position, MockModel mockModel) {
                    if (position % 2 == 0) {
                        return 0;
                    }
                    return 1;
                }

                @Override
                public int getLayoutId(int viewType) {
                    if (viewType == 0) {
                        return R.layout.item_type1;
                    }
                    return R.layout.item_type2;
                }

                @Override
                public int getViewTypeCount() {
                    return 2;
                }
            });
recyclerView.setAdapter(mMultiAdapter);

如果使用的是RecyclerView,在使用多布局时,还可以使用SimpleMulItemViewType类(继承自IMulItemViewType),因为getViewTypeCount()方法仅在使用ListView、GridView等控件时是必须提供的:

mAdapter = new MultipleAdapter(getContext(), models, new SimpleMulItemViewType<MockModel>() {
    @Override
    public int getItemViewType(int position, MockModel mockModel) {
        if (position % 2 == 0) {
            return 0;
        }
        return 1;
    }

    @Override
    public int getLayoutId(int viewType) {
        if (viewType == 0) {
            return R.layout.item_type1;
        }
        return R.layout.item_type2;
    }
});
recyclerView.setAdapter(mAdapter);

如果不想在创建Adapter时提供IMulItemViewType接口,也可以在Adapter中重写offerMultiItemViewType()方法:

@Override
protected IMulItemViewType<MockModel> offerMultiItemViewType() {
    return new IMulItemViewType<MockModel>() {
        @Override
        public int getViewTypeCount() {
                return 2;
        }

        @Override
        public int getItemViewType(int position, MockModel mockModel) {
            if (position % 2 == 0) {
                return 0;
            }
            return 1;
        }

        @Override
        public int getLayoutId(int viewType) {
            if (viewType == 0) {
                return R.layout.item_type1;
            }
            return R.layout.item_type2;
        }
    };
}

然后在创建Adapter时提供null
multiAdapter = new MultipleAdapter(context, list, null);


开启加载动画:
adapter.openLoadAnimation();
你也可以指定动画时常和类型:
adapter.openLoadAnimation(long duration, new SlideInBottomAnimation());
默认的加载动画只执行一次,如果你想每次显示item的时候都执行,可以设置
adapter.setOnlyOnce(false);
当然实现自定义的动画也很简单,可以通过实现BaseAnimation接口来创建你心仪的动画。


至于header和footer的使用,就更简单啦!adapter.addHederView(view)就可以添加一个Header了,你可以使用的全部api如下:

Header和Footer相关的api.png

最后再贴一遍源码地址,欢迎提交代码、bug以及讨论 :) 能分享到自己的朋友圈就更好啦 _ ……

QQ群:271849001(新)

qq交流群.png

感谢base-adapter-helper项目提供的灵感。

转载请联系作者

Android