Bootstrap

android recyclerView adapter 的 itemType的使用

  • RecyclerView出来已经很久了。我对于之的使用,也仅限于当成ListVieworGridView的使用。最近项目中有一个需求刚好需要用到多种item的展示。
  • 我之前使用RecyclerViewadapter 全部使用的是hongyang/base-adapter。非常的方便。而且也提供多种item的展示的功能。但是………我并没有找到正确的使用方式。于是这回就用到了原生的RecyclerView.Adapter来实现多种itemType


  • 我的项目中,用到的是两种item。为了以后查找方便,就记录在这里了。

public class LockAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<LockInfo> dataList;
    private final Context mContext;
    private boolean canClick;
    private int lockCount;
    private int unLockCount;
    private int mUnLockCountPos;
    private int mLockCountPos;

    public void setCanClick(boolean canClick) {
        this.canClick = canClick;
        notifyDataSetChanged();
    }


    public int getUnLockCountPos() {
        return mUnLockCountPos;
    }

    public int getLockCount() {
        return lockCount;
    }

    public int getUnLockCount() {
        return unLockCount;
    }

    public LockAdapter(@NonNull Context context, @NonNull List<LockInfo> dataList) {
        this.mContext = context;
        this.dataList = dataList;
        lockCount = Observable.fromIterable(dataList).filter(it -> it.locked)
                .toList().blockingGet().size() - 1;
        unLockCount = dataList.size() - 1 - (lockCount + 1);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == 0) {
            // default item
            View view = LayoutInflater.from(mContext)
                    .inflate(R.layout.item_app_list_layout, parent, false);

            return new NormalVH(view);

        } else if (viewType == 1) {
            // first item
            View view = LayoutInflater.from(mContext)
                    .inflate(R.layout.item_app_list_first_layout, parent, false);
            return new FirstVH(view);
        } else {
            return null;
        }
    }


    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        int adapterPosition = viewHolder.getAdapterPosition();
        LockInfo info = dataList.get(adapterPosition);
        if (viewHolder instanceof NormalVH) {
            NormalVH holder = (NormalVH) viewHolder;
            holder.ivIcon.setImageDrawable(info.appIcon);
            holder.cbChecked.setChecked(info.locked);
            holder.cbChecked.setEnabled(canClick);
            holder.itemView.setEnabled(canClick);
            holder.tvPackageName.setText(info.packageName);
            if (canClick) {
                holder.itemView.setOnClickListener(v -> {
                    info.locked = !info.locked;
                    if (info.locked) {
                        lockCount += 1;
                        unLockCount -= 1;
                    } else {
                        lockCount -= 1;
                        unLockCount += 1;
                    }
                    notifyItemChanged(adapterPosition);
                    notifyItemChanged(mLockCountPos);
                    notifyItemChanged(mUnLockCountPos);
                    EventBus.getDefault().post(new ChangeEvent(lockCount, unLockCount));
                });
            }
        } else if (viewHolder instanceof FirstVH) {
            FirstVH holder = (FirstVH) viewHolder;
            if (info.locked) {
                this.mLockCountPos = adapterPosition;
                holder.tvFirst.setText(mContext.getString(R.string.has_locked_count, lockCount));
            } else {
                this.mUnLockCountPos = adapterPosition;
                holder.tvFirst.setText(mContext.getString(R.string.un_locked_count, unLockCount));
            }
        }
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    private static class NormalVH extends RecyclerView.ViewHolder {

        private final View itemView;
        private final ImageView ivIcon;

        private final TextView tvPackageName;
        private final CheckBox cbChecked;

        NormalVH(View itemView) {
            super(itemView);
            this.itemView = itemView;
            ivIcon = (ImageView) itemView.findViewById(R.id.item_app_list_iv);
            tvPackageName = (TextView) itemView.findViewById(R.id.item_app_list_tv_name);
            cbChecked = (CheckBox) itemView.findViewById(R.id.item_app_list_cb);
        }
    }

    private static class FirstVH extends RecyclerView.ViewHolder {

        private final TextView tvFirst;

        FirstVH(View itemView) {
            super(itemView);
            tvFirst = (TextView) itemView.findViewById(R.id.item_app_list_first_tv);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (dataList.get(position).first) {
            return 1;
        } else {
            return super.getItemViewType(position);
        }
    }

    public void updateData(@NonNull List<LockInfo> update) {
        this.dataList = update;
        notifyDataSetChanged();
    }
}
  • 其实也是看到这篇文字之后,才知道怎么弄的。
  • 强调一下,多个itemType时,需要注意的地方:

    • Adapter需要直接继承RecyclerView.Adapter<RecyclerView.ViewHolder>,并且不要改变泛型类。
    • 重写int getItemViewType(int position)方法,第一种item默认返回super.getItemViewType(position);,也就是0,第二种item再返回一个不同的值,我这里给的是1.(第三种,也是一样,我这里没有实现)
    • 有几种item就写几个RecyclerView.ViewHolder,我这里是两个,于是我写了两个,分别是private static class NormalVH extends RecyclerView.ViewHolder{...}private static class FirstVH extends RecyclerView.ViewHolder {...}这两个。
    • onCreateViewHolder()方法中,分别判断当前用的是哪一种ViewHolder,比如我这里:
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == 0) {
            // default item
            View view = LayoutInflater.from(mContext)
                    .inflate(R.layout.item_app_list_layout, parent, false);
    
            return new NormalVH(view);
    
        } else if (viewType == 1) {
            // first item
            View view = LayoutInflater.from(mContext)
                    .inflate(R.layout.item_app_list_first_layout, parent, false);
            return new FirstVH(view);
        } else {
            return null;
        }
    }
    • onBindViewHolder()方法中,也是一样,要根据不同的ViewHolder做不同的绑定view的操作。比如我这里:
      @Override
      public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
          int adapterPosition = viewHolder.getAdapterPosition();
          LockInfo info = dataList.get(adapterPosition);
          if (viewHolder instanceof NormalVH) {
              NormalVH holder = (NormalVH) viewHolder;
              holder.ivIcon.setImageDrawable(info.appIcon);
              holder.cbChecked.setChecked(info.locked);
              holder.cbChecked.setEnabled(canClick);
              holder.itemView.setEnabled(canClick);
              holder.tvPackageName.setText(info.packageName);
              if (canClick) {
                  holder.itemView.setOnClickListener(v -> {
                      info.locked = !info.locked;
                      if (info.locked) {
                          lockCount += 1;
                          unLockCount -= 1;
                      } else {
                          lockCount -= 1;
                          unLockCount += 1;
                      }
                      notifyItemChanged(adapterPosition);
                      notifyItemChanged(mLockCountPos);
                      notifyItemChanged(mUnLockCountPos);
                      EventBus.getDefault().post(new ChangeEvent(lockCount, unLockCount));
                  });
              }
          } else if (viewHolder instanceof FirstVH) {
              FirstVH holder = (FirstVH) viewHolder;
              if (info.locked) {
                  this.mLockCountPos = adapterPosition;
                  holder.tvFirst.setText(mContext.getString(R.string.has_locked_count, lockCount));
              } else {
                  this.mUnLockCountPos = adapterPosition;
                  holder.tvFirst.setText(mContext.getString(R.string.un_locked_count, unLockCount));
              }
          }
      }
  • 主要的需要注意的地方就是这几点了。
  • 另外,这个代码如果直接拷过去是一定没有办法运行的。主要是讲一下实现过程。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;