前言
昨天開始接觸江湖口碑很好的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() : ;
}
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);
}
}
}
- 首先,
這段代碼完全可以封裝起來的。@Override public int getItemCount () { return (this.items != null) ? this .items. size() : 0 ; }
- onCreatedViewHolder()方法作用是綁定item視圖,可以進一步封裝,給子類提供一個getLayoutItemId的抽象方法,這樣就可以簡化成一行代碼了。
- 是以我們發現,這個adapter的核心代碼在與onBindViewHolder()中,作用是将資料跟視圖(ViewHolder)綁定,可以給子類提供一個bindData()抽象方法。
- 當然了,使用泛型也是極好的,拓廣了adapter的使用範圍。
- 添加點選事件的監聽也可以封裝到萬能adapter中,子類就不用再寫item點選事件處理代碼了
封裝後的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);
}
}
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;
}
}
該類的核心方法是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 = ; i <= ; 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));
}
如果覺得有什麼不妥之處或建議,敬請指教!
完整項目代碼已上傳至Github。—Github跳轉。
see also:
Listview的Adapter應該這樣寫