RecyclerView相关类
类名 | 说明 |
RecyclerView.Adapter | 托管数据集合,为每个Item创建视图 |
RecyclerView.ViewHolder | 承载Item视图的子视图 |
RecyclerView.LayoutManager | 负责Item视图的布局 |
RecyclerView.ItemDecoration | 为每个Item视图添加子视图,在Demo中被用来绘制Divider |
RecyclerView.ItemAnimator | 负责添加、删除数据时的动画效果 |
1.ViewHolder
关于ViewHolder,Google早就推荐开发者使用,但也只是建议。但是现在,RecyclerView.Adapter最终要求开发者必须使用ViewHolder。如果你还对ViewHolder不了解,请阅读Android training session。
Demo通过继承RecyclerView.ViewHolder来实现自定义:
- public class MyViewHolder extends ViewHolder implements OnClickListener,OnLongClickListener{
- public ImageView iv;
- public TextView tv;
- private MyItemClickListener mListener;
- private MyItemLongClickListener mLongClickListener;
- public MyViewHolder(View rootView,MyItemClickListener listener,MyItemLongClickListener longClickListener) {
- super(rootView);
- iv = (ImageView)rootView.findViewById(R.id.item_iv);
- tv = (TextView)rootView.findViewById(R.id.item_tv);
- this.mListener = listener;
- this.mLongClickListener = longClickListener;
- rootView.setOnClickListener(this);
- rootView.setOnLongClickListener(this);
- }
- /**
- * 点击监听
- */
- @Override
- public void onClick(View v) {
- if(mListener != null){
- mListener.onItemClick(v,getPosition());
- }
- }
- /**
- * 长按监听
- */
- @Override
- public boolean onLongClick(View arg0) {
- if(mLongClickListener != null){
- mLongClickListener.onItemLongClick(arg0, getPosition());
- }
- return true;
- }
- }
2.RecyclerView.Adapter
Adapter负责扮演两个角色:不仅为底部数据提供支持而且还负责为数据创建合适的视图。Adapter适用在Android很多控件,例如ListView、AutoCompleteTextView等。
继承RecyclerView.Adapter需要实现以下三个方法:
- public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType)
- public void onBindViewHolder(ViewHolder holder,int position)
- public int getItemCount()
Demo中的Adapter:
- public class MyAdapter extends Adapter<MyViewHolder> {
- private List<MyItemBean> mData;
- private MyItemClickListener mItemClickListener;
- private MyItemLongClickListener mItemLongClickListener;
- public MyAdapter(List<MyItemBean> data){
- this.mData = data;
- }
- @Override
- public int getItemCount() {
- return mData.size();
- }
- @Override
- public void onBindViewHolder(MyViewHolder holder, int position) {
- MyItemBean bean = mData.get(position);
- holder.tv.setText(bean.tv);
- }
- @Override
- public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent,false);
- MyViewHolder vh = new MyViewHolder(itemView,mItemClickListener,mItemLongClickListener);
- return vh;
- }
- }
onCreateViewHolder中负责为Item创建视图,onBindViewHolder负责将数据绑定到Item的视图上。
3.RecyclerView.LayoutManager
LayoutManager是RecyclerView中最有意思的类。该类负责将每个Item视图在RecylerView中的布局。目前Google提供了LayoutManager的一个子类:LinearLayoutManager。LinearLayoutManager提供了横向和竖向两种布局,Demo就是使用LinearLayoutManger的横向布局实现的。
如果要自定义LayoutManager,需要实现一个abstract方法
- public LayoutParams generateDefaultLayoutParams()
Demo中为RecylerView添加LinearLayoutManager的片段:
- MyLayoutManager manager = new MyLayoutManager(this);
- manager.setOrientation(LinearLayout.HORIZONTAL);//默认是LinearLayout.VERTICAL
- mRecyclerView.setLayoutManager(manager);
LinearLayoutManager提供了如下几个方法来帮助开发者获取屏幕上的顶部item和底部item:
- findFirstVisibleItemPosition()
- findFirstCompletelyVisibleItemPosition()
- findLastVisibleItemPosition()
- findLastCompletelyVisibleItemPosition()
4.RecyclerView.ItemDecoration
通过ItemDecoration可以使各个Item在视觉上相互分开,其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的,开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。
继承ItemDecoration需要实现以下三个方法:
- public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
- public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)
LayoutManager会调用getItemOffset方法来计算每个Item的Decoration合适的尺寸。
Demo中自定义了一个ItemDecoration来实现ListView的Divider效果:
- public class MyDecoration extends ItemDecoration {
- private static final int[] ATTRS = new int[]{
- android.R.attr.listDivider
- };
- private Drawable mDivider;
- public MyDecoration(Context ctx){
- final TypedArray a = ctx.obtainStyledAttributes(ATTRS);
- mDivider = a.getDrawable(0);
- }
- @Override
- public void onDraw(Canvas c, RecyclerView parent, State state) {
- int top = parent.getPaddingTop();
- int bottom = parent.getHeight() - parent.getPaddingBottom();
- int childCount = parent.getChildCount();
- for(int i=0;i < childCount;i++){
- View child = parent.getChildAt(i);
- RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams();
- int left = child.getRight() + layoutParams.rightMargin;
- int right = left + mDivider.getIntrinsicWidth();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
- }
- }
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
- State state) {
- outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
- }
- }
5.RecyclerView.ItemAnimatior
当Item有以下三种操作时ItemAnimatior会为RecyclerView提供动画效果:
- 删除某一个Item
- 添加一个新的Item
- 移动某个Item
Google提供了一个名为DefaultItemAnimator的默认ItemAnimator供开发者使用。如果开发者不为RecyclerView设置ItemAnimator,RecyclerView也会使用默认的DefaultItemAnimator。
显然,为了让动画效果起效,开发者必须通知Adapter数据有改变。之前我们使用Adapter时会调用notifyDataSetChanged()来通知Adapter数据改变并更新视图,现在RecyclerView,Adapter提供了许多notifyXyz()方法,例如Demo中使用了以下两个方法:
- public final void notifyItemInserted(int position)
- public final void notifyItemRemoved(int position)
参考资料:
A First Glance at Android’s RecyclerView