屬于RecyclerView的萬能適配器Adapter和ViewHolder

CamillaKail 8年前發布 | 150K 次閱讀 Android開發 移動開發

來自: http://blog.csdn.net/tellh/article/details/50670458


前言

昨天開始接觸江湖口碑很好的RecyclerView,事實上,我已經被她的強大所征服了!資源回收,數據綁定,布局顯示,分割線,Item動畫多個模塊高度解耦,靈活優雅。其實,RecyclerView在使用上已經是相當簡單了(個人覺得),但仍有很多代碼是可以加以封裝的。今天受簡書上一篇博文的啟發,作為寫代碼喜歡優(tou)雅(lan)的人,想到了一種封裝方式,打造萬能適配器,供大家食用。

正統模式:

public class SimplerItemAdapter extends RecyclerView.Adapter<SimplerItemAdapter.SimpleItemViewHolder > {

private List <String> items;

public SimplerItemAdapter (@NonNull List<String> dateItems ) { this.items = (dateItems != null ? dateItems : new ArrayList<String>()); }

@Override public SimpleItemViewHolder onCreateViewHolder (ViewGroup viewGroup, int viewType) { View itemView = LayoutInflater.from( viewGroup.getContext ()).inflate(R.layout .item, viewGroup, false ); return new SimpleItemViewHolder(itemView); }

@Override public void onBindViewHolder (SimpleItemViewHolder viewHolder, int position) { viewHolder.textView .setText(items.get (position)); }

@Override public int getItemCount () { return (this.items != null) ? this .items. size() : 0 ; }

protected final static class SimpleItemViewHolder extends RecyclerView.ViewHolder { protected TextView textView ;

public SimpleItemViewHolder (View itemView) {
  super(itemView);
  this.textView = (TextView) itemView.findViewById (R. id.text);
}

} }</pre>

  • 首先,
    @Override public int getItemCount () {
    return (this.items != null) ? this .items. size() : 0 ;
    }
    這段代碼完全可以封裝起來的。
  • onCreatedViewHolder()方法作用是綁定item視圖,可以進一步封裝,給子類提供一個getLayoutItemId的抽象方法,這樣就可以簡化成一行代碼了。
  • 因此我們發現,這個adapter的核心代碼在與onBindViewHolder()中,作用是將數據跟視圖(ViewHolder)綁定,可以給子類提供一個bindData()抽象方法。
  • 當然了,使用泛型也是極好的,拓廣了adapter的使用范圍。
  • 添加點擊事件的監聽也可以封裝到萬能adapter中,子類就不用再寫item點擊事件處理代碼了
  • </ul>

    封裝后的Adapter

    public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
        protected final List<T> mData;
        protected final Context mContext;
        protected LayoutInflater mInflater;
        private OnItemClickListener mClickListener;
        private OnItemLongClickListener mLongClickListener;

    public BaseRecyclerAdapter(Context ctx, List<T> list) {
        mData = (list != null) ? list : new ArrayList<T>();
        mContext = ctx;
        mInflater = LayoutInflater.from(ctx);
    }
    
    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final RecyclerViewHolder holder = new RecyclerViewHolder(mContext,
                mInflater.inflate(getItemLayoutId(viewType), parent, false));
        if (mClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mClickListener.onItemClick(holder.itemView, holder.getLayoutPosition());
                }
            });
        }
        if (mLongClickListener != null) {
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    mLongClickListener.onItemLongClick(holder.itemView, holder.getLayoutPosition());
                    return true;
                }
            });
        }
        return holder;
    }
    
    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, int position) {
        bindData(holder, position, mData.get(position));
    }
    
    @Override
    public int getItemCount() {
        return mData.size();
    }
    
    public void add(int pos, T item) {
        mData.add(pos, item);
        notifyItemInserted(pos);
    }
    
    public void delete(int pos) {
        mData.remove(pos);
        notifyItemRemoved(pos);
    }
    
    public void setOnItemClickListener(OnItemClickListener listener) {
        mClickListener = listener;
    }
    
    public void setOnItemLongClickListener(OnItemLongClickListener listener) {
        mLongClickListener = listener;
    }
    
    abstract public int getItemLayoutId(int viewType);
    
    abstract public void bindData(RecyclerViewHolder holder, int position, T item);
    
    public interface OnItemClickListener {
        public void onItemClick(View itemView, int pos);
    }
    
    public interface OnItemLongClickListener {
        public void onItemLongClick(View itemView, int pos);
    }
    

    }</pre>

    Super ViewHolder!

    其實,這還沒完呢!重頭戲在ViewHolder上!RecyclerView強制我們使用ViewHolder模式,然而缺不可避免地要寫findViewById代碼,有沒有辦法不寫這樣的代碼呢?甚至連ViewHolder都不寫呢?當然可以!

    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
        private SparseArray<View> mViews;//集合類,layout里包含的View,以view的id作為key,value是view對象
        private Context mContext;//上下文對象

    public RecyclerViewHolder(Context ctx, View itemView) {
        super(itemView);
        mContext = ctx;
        mViews = new SparseArray<View>();
    }
    
    private <T extends View> T findViewById(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = itemView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }
    
    public View getView(int viewId) {
        return findViewById(viewId);
    }
    
    public TextView getTextView(int viewId) {
        return (TextView) getView(viewId);
    }
    
    public Button getButton(int viewId) {
        return (Button) getView(viewId);
    }
    
    public ImageView getImageView(int viewId) {
        return (ImageView) getView(viewId);
    }
    
    public ImageButton getImageButton(int viewId) {
        return (ImageButton) getView(viewId);
    }
    
    public EditText getEditText(int viewId) {
        return (EditText) getView(viewId);
    }
    
    public RecyclerViewHolder setText(int viewId, String value) {
        TextView view = findViewById(viewId);
        view.setText(value);
        return this;
    }
    
    public RecyclerViewHolder setBackground(int viewId, int resId) {
        View view = findViewById(viewId);
        view.setBackgroundResource(resId);
        return this;
    }
    
    public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener) {
        View view = findViewById(viewId);
        view.setOnClickListener(listener);
        return this;
    }
    

    }</pre>

    該類的核心方法是private T findViewById(int viewId),核心成員變量是private SparseArray mViews; 不信可以不寫一句ViewHolder代碼?接下來看看用法。

    實踐用法

    添加Adapter僅需短短的幾行代碼:

    Adapter = new BaseRecyclerAdapter<String>(this,mDataList) {
                @Override
                public int getItemLayoutId(int viewType) {
                    return R.layout.item;
                }
                @Override
                public void bindData(RecyclerViewHolder holder, int position,String item) {
                    //調用holder.getView(),getXXX()方法根據id得到控件實例,進行數據綁定即可
                    holder.setText(R.id.tv_num,item)
                            .getTextView(R.id.tv_title,item).setText(item);
                }
            };

    完整代碼:

        private void init() {
            recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            mDataList = new ArrayList<>();
            for (int i = 0; i <= 100; i++) {
                mDataList.add(String.valueOf(i));
            }
            //設置item動畫
            recyclerView.setItemAnimator(new DefaultItemAnimator());
            mAdapter = new BaseRecyclerAdapter<String>(this,mDataList) {
                @Override
                public int getItemLayoutId(int viewType) {
                    return R.layout.item;
                }
                @Override
                public void bindData(RecyclerViewHolder holder, int position,String item) {
                    //調用holder.getView(),getXXX()方法根據id得到控件實例,進行數據綁定即可
                    holder.setText(R.id.tv_num,item)
                            .getTextView(R.id.tv_title,item).setText(item);
                }
            };
            recyclerView.setAdapter(mAdapter);
            //添加item點擊事件監聽
            ((BaseRecyclerAdapter)mAdapter).setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(View itemView, int pos) {
                    Toast.makeText(AdapterTestActivity.this, "click " + pos, Toast.LENGTH_SHORT).show();
                }
            });
            ((BaseRecyclerAdapter)mAdapter).setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
                @Override
                public void onItemLongClick(View itemView, int pos) {
                    Toast.makeText(AdapterTestActivity.this, "long click " + pos, Toast.LENGTH_SHORT).show();
                }
            });
            //設置布局樣式LayoutManager
            recyclerView.setLayoutManager(new LinearLayoutManager(AdapterTestActivity.this, LinearLayoutManager.VERTICAL, false));
    // recyclerView.addItemDecoration(new ItemDividerDecoration(MainActivity.this, OrientationHelper.VERTICAL));

    }</pre> 
    

    如果覺得有什么不妥之處或建議,敬請指教!
    完整項目代碼已上傳至Github。—Github跳轉

    see also:
    Listview的Adapter應該這樣寫

    </div>

 本文由用戶 CamillaKail 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!