使用RecyclerView避免创建很多Adapter,使用注解
2018-01-16 本文已影响65人
C盘无限大
正常使用RecyclerView使用到类有:数据类bean、数据绑定ViewHolder、布局绑定Adapter。
因为数据类型不同或者布局不同导致显示新列表时都要定义一次bean、ViewHolder和Adapter,在这里试试通过注解绑定ViewHolder,去除重复定义Adapter这步。
定义绑定ViewHolder注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HolderClass {
Class<?> value();
}
绑定布局注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HolderLayoutRes {
int value();
}
在定义ViewHolder基类,实现一些常用View方法:
public class CommonHolder<T> extends RecyclerView.ViewHolder{
@IntDef({View.VISIBLE, View.INVISIBLE, View.GONE})
@Retention(RetentionPolicy.SOURCE)
private @interface Visibility {}
private SparseArray<View> mViews;
protected T mData;
public CommonHolder(View itemView) {
super(itemView);
mViews = new SparseArray<>();
}
protected void bindData(T data){
this.mData = data;
}
public CommonHolder setVisibility(@IdRes int id, @Visibility int visible){
getView(id).setVisibility(visible);
return this;
}
public CommonHolder setBackgroundColor(@IdRes int id, @ColorInt int color) {
getView(id).setBackgroundColor(color);
return this;
}
public CommonHolder setBackgroundResource(@IdRes int id, @ColorRes int color) {
getView(id).setBackgroundResource(color);
return this;
}
/*######################### TextView #########################*/
public CommonHolder setText(@IdRes int id, @StringRes int strRes) {
((TextView) getView(id)).setText(strRes);
return this;
}
public CommonHolder setText(@IdRes int id, String strRes) {
((TextView) getView(id)).setText(strRes);
return this;
}
public CommonHolder setTextColor(@IdRes int id, @ColorInt int color) {
((TextView) getView(id)).setTextColor(color);
return this;
}
public CommonHolder setTextSize(@IdRes int id, @DimenRes int size){
((TextView) getView(id)).setTextSize(TypedValue.COMPLEX_UNIT_PX, itemView.getResources().getDimensionPixelSize(size));
return this;
}
public CommonHolder setTextSize(@IdRes int id, float size){
((TextView) getView(id)).setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
return this;
}
public CommonHolder setTextface(@IdRes int id, Typeface typeface){
((TextView) getView(id)).setTypeface(typeface);
return this;
}
/*######################### ImageView #########################*/
public CommonHolder setImageDrawable(@IdRes int id, Drawable drawable){
((ImageView) getView(id)).setImageDrawable(drawable);
return this;
}
public CommonHolder setImageResource(@IdRes int id, @DrawableRes int drawable){
((ImageView) getView(id)).setImageResource(drawable);
return this;
}
public CommonHolder setImageBitmap(@IdRes int id, Bitmap bitmap){
((ImageView) getView(id)).setImageBitmap(bitmap);
return this;
}
public CommonHolder setImageBitmap(@IdRes int id, ImageView.ScaleType type){
((ImageView) getView(id)).setScaleType(type);
return this;
}
/*######################### CheckBox #########################*/
public CommonHolder setCheck(@IdRes int id, boolean check){
((CheckBox) getView(id)).setChecked(check);
return this;
}
public CommonHolder toggle(@IdRes int id){
((CheckBox) getView(id)).toggle();
return this;
}
public <T extends View> T getView(@IdRes int id){
T view = (T) mViews.get(id);
if (view == null) {
view = (T) itemView.findViewById(id);
mViews.put(id, view);
}
return view;
}
}
重新定义Adapter的最大原因是因为每个布局使用的ViewHolder不一样,所以这里使用构造器创建每个布局的ViewHolder:
public class TestAdapter<T, H extends CommonHolder<T>> extends RecyclerView.Adapter<H>{
private static List<LayoutBeanHolder> layoutBeanHolders = new ArrayList<>();
protected List<T> mListData;
public TestAdapter(List<T> mListData) {
this.mListData = mListData;
}
public TestAdapter() {
this.mListData = new ArrayList<>();
}
@Override
public H onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
Class holder = indexHolder(viewType);
H commonHolder = null;
if (holder != null) {
try {
//这里用构造器创建实例
Constructor constructor = holder.getConstructor(View.class);
commonHolder = (H) constructor.newInstance(view);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
if (commonHolder == null) {
commonHolder = (H) new CommonHolder<>(view);
}
return commonHolder;
}
@Override
public void onBindViewHolder(H holder, int position) {
holder.bindData(mListData.get(position));
}
/**
* 获取bean中的布局,以布局id为ViewType
*/
@Override
public int getItemViewType(int position) {
Class<?> clazz = mListData.get(position).getClass();
int layout = indexLayoutRes(clazz);
if (layout != -1) {
return layout;
}
HolderLayoutRes annotation = clazz.getAnnotation(HolderLayoutRes.class);
if (annotation != null) {
layout = annotation.value();
HolderClass viewHolderClass = clazz.getAnnotation(HolderClass.class);
if (viewHolderClass != null) {
layoutBeanHolders.add(new LayoutBeanHolder(clazz, viewHolderClass.value(), layout));
} else {
layoutBeanHolders.add(new LayoutBeanHolder(clazz, layout));
}
return layout;
} else {
throw new IllegalArgumentException("class : " + clazz +" no ViewHolderLayoutRes");
}
}
/**
* 根据布局id获取绑定的ViewHolder
*/
private Class<?> indexHolder(int layoutRes){
for (LayoutBeanHolder holder : layoutBeanHolders) {
if (layoutRes == holder.layoutRes) {
return holder.holderClass;
}
}
return null;
}
/**
* 根据item类型获取布局id
*/
private int indexLayoutRes(Class<?> beanClass){
for (LayoutBeanHolder holder : layoutBeanHolders) {
if (beanClass.equals(holder.beanClass)) {
return holder.layoutRes;
}
}
return -1;
}
@Override
public int getItemCount() {
return mListData.size();
}
/**
* 布局、viewHolder、bean绑定
*/
private static class LayoutBeanHolder {
private Class<?> beanClass;
private Class<?> holderClass;
private int layoutRes;
private LayoutBeanHolder(Class<?> beanClass, int layoutRes) {
this.beanClass = beanClass;
this.layoutRes = layoutRes;
}
private LayoutBeanHolder(Class<?> beanClass, Class<?> holderClass, int layoutRes) {
this.beanClass = beanClass;
this.holderClass = holderClass;
this.layoutRes = layoutRes;
}
}
}
最后我测试了一下:
public class AdapterActivity extends AppCompatActivity{
private RecyclerView mRecyclerView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adapter);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
final List<Object> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new BeanA("我是Aitem-"+i));
}
TestAdapter adapter = new TestAdapter<>(list);
mRecyclerView.setAdapter(adapter);
}
@HolderLayoutRes(R.layout.item_layout_1)
@HolderClass(HolderA.class)
public static class BeanA{
String test;
public BeanA(String test) {
this.test = test;
}
}
public static class HolderA extends CommonHolder<BeanA> {
public HolderA(View itemView) {
super(itemView);
}
@Override
protected void bindData(BeanA data) {
super.bindData(data);
setText(R.id.view1, data.test);
}
}
}
不知道这样好不好,希望大家留言给给建议,如果可以我会补充TestAdapter封装列表加载状态及头尾View。