【Android基础】RecyclerView的设计艺术

来源:互联网 发布:我想开个网络棋牌室 编辑:程序博客网 时间:2024/06/06 03:43

总览

RecyclerView 和 ListView GridView之类比起来 可谓集大成者,通过开放更加功能强大的接口,以一挡十。有如下几点:

强制绑定ViewHolder ——Adapter

ListView的view复用可是需要RD自己封装ViewHolder来实现,而这里强制了ViewHolder的存在,来看看它是怎么做到的吧?

回忆一下ListView的视图循环利用

 @Override   public View getView(int position, View convertView, ViewGroup parent) {              System.out.println("getView " + position + " " + convertView);              ViewHolder holder = null;              if (convertView == null) {                  convertView = mInflater.inflate(R.layout.item1, null);                  holder = new ViewHolder();                  holder.textView = (TextView)convertView.findViewById(R.id.text);                  convertView.setTag(holder);              } else {                  holder = (ViewHolder)convertView.getTag();              }              holder.textView.setText(mData.get(position));              return convertView;  }  ....public static class ViewHolder {          public TextView textView;  } 

这里写图片描述
Recycler组件提供了convertView ,至于你要不要利用它去复用,那就是你的事情了,新手常常会踩一下这个坑。

RecyclerView怎么做到呢?

当我们继承

RecyclerView.Adapter<VH extends ViewHolder>

去写adapter时候,要覆写的方法如下:

@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        /**         * 之前listview 的viewHolder是非强制的优化措施,在这里已经被融入到基础框架中了         * 来扩大View的重用性,只有在需要创建viewHolder的时候才会被调用,减少对findviewbyId的调用次数         **/        View item = mInflater.inflate(R.layout.layout_recyclerview_item, null);        return new MyViewHolder(item);}@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {        /**         *  这里是 数据更新到view的地方。         *  我觉的叫做 onBindViewHolder 不妥,ViewHolder只是一个增加view复用的工具而已         *  onUpdateView 还差不多。         *  其实干的事情就是根据position来找到对应的数据,然后将数据更新到ViewHolder所hold的view中。         */        //根据position找到数据        String num = mDatas.get(position);        //更新数据到ViewHolder所hold的view中        holder.tv.setText(num);}...class MyViewHolder extends RecyclerView.ViewHolder {        TextView tv;        public MyViewHolder(View itemView) {            super(itemView);            /**            * findViewById 拿到ViewHolder去做掉,封装性更好            **/            tv = (TextView) itemView.findViewById(R.id.id_num);        }}  

RecyclerView之下:

  • 无需关心ViewHolder的创建时机 在被通知创建ViewHolder的时候创建ViewHolder,无需自己判断convertView是否为空

  • 无需关心ViewHolder的存储,获取 在被通知要更新View的时候更新View,但是这个时候它递过来的是ViewHolder,我们不用去从view.getTag中去拿

  • 你无法忘记使用ViewHolder,因为它是RecyclerView所必须使用到的类。

解决了列表布局的多样性需求——LayoutManager

RecyclerView.LayoutManager吧,这是一个抽象类,好在系统提供了3个实现类:

  • LinearLayoutManager 现行管理器,支持横向、纵向。
  • GridLayoutManager 网格布局管理器
  • StaggeredGridLayoutManager 瀑布就式布局管理器

解决了装饰列表项多样性需求——ItemDecoration

典型的就是:分割线

public static abstract class ItemDecoration {        public void onDraw(Canvas c, RecyclerView parent, State state)      {            onDraw(c, parent);        }        @Deprecated        public void onDraw(Canvas c, RecyclerView parent) {        }        public void onDrawOver(Canvas c, RecyclerView parent, State state) {            onDrawOver(c, parent);        }        @Deprecated        public void onDrawOver(Canvas c, RecyclerView parent) {        }        @Deprecated        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {            outRect.set(0, 0, 0, 0);        }        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),                    parent);        }    }

onDraw

  • 在该方法里可以绘制用来装饰每个item的图。
  • 不只是分隔线,可以是任何用来装饰item的图。
  • 该方法会在每个item绘制之前绘制,所以它有可能会被item的图所覆盖。
  • 那怎么知道我应该在哪块区域绘制呢?根据每个item的位置来计算绘制的位置

onDrawOver

  • 和onDraw类同,但是该方法会在每个item绘制之后绘制

getItemOffsets

  • 类似padding ,margin, 拿分隔线来说,每增加一个分隔线都会对原来的item的布局产生影响,每个item相对之前都会产生一定的偏移量了。
    如下,垂直列表中,增加分隔线对每个item高度上偏移量影响。
 @Override    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());    }

解决了列表项的动画多样性需求——ItemAnimator

目前官方只提供了:DefaultItemAnimator
github也开源了一些动画:
https://github.com/gabrielemariotti/RecyclerViewItemAnimators/tree/master

UML设计图

这里写图片描述

Demo

https://github.com/jason2code/MyAndroidDemos/tree/master/app/src/main/java/com/android/demos/jason/myandroiddemos/uiRecyclerView

参考

Android RecyclerView 使用完全解析 体验艺术般的控件
ListView中convertView和ViewHolder的工作原理

0 0
原创粉丝点击