android RecyclerView 使用完全解析 替代ListView(一)

来源:互联网 发布:ar涂色 源码 编辑:程序博客网 时间:2024/05/17 03:39

RecyclerView是什么?

RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持。

在开发RecyclerView时充分考虑了扩展性,因此用它可以创建想到的任何种类的的布局。但在使用上也稍微有些不便。这就是Android——要完成一件事情总不是那么容易。

如果使用RecyclerView,你需要了解以下三个元素:
- RecyclerView.Adapter
- LayoutManager
- ItemAnimator

RecyclerView.Adapter

RecyclerView包含了一种新型适配器。它与现在使用的适配器类似,但也稍有不同,例如它需要使用ViewHolder。使用时需要重写两个主要方法:一个用来展现视图和它的持有者,而另一个用来把数据绑定到视图上。这么做的好处是,第一种方法只有当我们真正需要创建一个新视图时才被调用,不需要检查它是否已经被回收。
这个适配器需要实现3个方法:
  - onCreateViewHolder()
  - onBindViewHolder()
  - getItemCount()
  
代码如下:

public class TestAdapter extends RecyclerView.Adapter {    RecycleViewHolder.RecyclerViewOnitem onItemListener;    public void setOnItemListener(RecycleViewHolder.RecyclerViewOnitem l) {        this.onItemListener = l;    }    private Context mContext;    private ArrayList<String> lists;    public TestAdapter(Context context, ArrayList<String> lists) {        this.lists = lists;        mContext = context;    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyeler_adapter, null);        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);        view.setLayoutParams(lp);        return new RecycleViewHolder(view);    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        RecycleViewHolder holders = (RecycleViewHolder) holder;        holders.position = position;        holders.data.setText(lists.get(position));        holders.postView.setText("第" + position + "个");        holders.setOnItemListener(onItemListener);    }    @Override    public int getItemCount() {        if (lists != null) {            return lists.size();        }        return 0;    }    /**     *需要继承 RecyclerView.ViewHolder     因为RecyclerView帮我们封装了Holder,所以我们自己写的ViewHolder就需要继承RecyclerView.ViewHolder,只有这样,RecyclerView才能帮你去管理这个ViewHolder类。     **/    public static class RecycleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {        // item View        public View rootView;        private TextView data;        private TextView postView;        private int position = -1;        public RecycleViewHolder(View itemView) {            super(itemView);            rootView = itemView;            data = (TextView) rootView.findViewById(R.id.data);            postView = (TextView) rootView.findViewById(R.id.position);            rootView.setOnClickListener(this);        }        @Override        public void onClick(View v) {            if (null != onItemListener) {                onItemListener.onItemView(rootView, position);            }        }        public interface RecyclerViewOnitem {            void onItemView(View parent, int postion);        }        private RecyclerViewOnitem onItemListener;        public void setOnItemListener(RecyclerViewOnitem l) {            this.onItemListener = l;        }    }}

我们从前用用的适配器BaseAdapter 部分代码:

    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder holder;        if(convertView == null){            holder = new ViewHolder();            convertView = this.inflater.inflate(R.layout.list_item,null);            holder.text_data = (TextView) convertView.findViewById(R.id.items_text);            convertView.setTag(holder);        }else{             holder = (ViewHolder)convertView.getTag();        }        holder.text_data.setText(datas.get(position));        return convertView;    }    class ViewHolder{        TextView text_data;    }
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)和以上代码的Line3-11行public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)方法和以上代码的Line12行既然getView方法的渲染数据部分的代码相当于onBindViewHolder(),所以如果调用RecyclerView.Adapter notifyDataSetChanged()方法,应该也会重新调用onBindViewHolder()方法才对吧?实验后,果然如此!

除了notifyDataSetChanged()这个方法之外,新的Adapter还提供了其他的方法,如下

        public final void notifyDataSetChanged()        public final void notifyItemChanged(int position)        public final void notifyItemRangeChanged(int positionStart, int itemCount)        public final void notifyItemInserted(int position)         public final void notifyItemMoved(int fromPosition, int toPosition)        public final void notifyItemRangeInserted(int positionStart, int itemCount)        public final void notifyItemRemoved(int position)        public final void notifyItemRangeRemoved(int positionStart, int itemCount) 

基本上看到方法的名字就知道这个方法是干嘛的了,

第一个方法没什么好讲的,跟以前一样。

notifyItemChanged(int position),position数据发生了改变,那调用这个方法,就会回调对应position的onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。

public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。

public final void notifyItemInserted(int position),这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。

public final void notifyItemMoved(int fromPosition, int toPosition),这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新
public final void notifyItemRangeInserted(int positionStart, int itemCount),显然是批量添加。
public final void notifyItemRemoved(int position),第position个被删除的时候刷新,同样会有动画。
public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。
这些方法分析完之后,我们来实现一个点击一个按钮,新增一条数据,长按一个item,删除一条数据的场景。

LayoutManager (需要实现 不要丢失)

这个类决定视图被放在画面中哪个位置,但这只是它的众多职责之一。它可以管理滚动和循环利用。
这一点就可以看出它有多复杂。管理器可以模拟列表视图(包括横向和纵向),但没有页眉和页尾。

为LayoutManager编写子类不太适合新手,我们需要依靠社区来发掘RecyclerView的全部潜力。与这个例子一起,在短时间内我会上传一个GridView控件的实现。

我认为这背后的关键是要仿照LinearLayoutManager的代码创建一个BaseLayoutManager,并且基于此进行扩展。或许support-v7的最终版本会提供更多、更好的实现。

ItemAnimator

ItemAnimator会根据适配器上收到的通知动画显示视图组的修改。基本上,它会自动显示添加和移除条目动画。这也不是一个简单的类,但我们发现DefaultItemAnimator已经可以运行得很好了。

RecyclerView设置

所以最后,如果想要初始化一个运行的RecyclerView,你需要做这样的事情:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);recyclerView.setHasFixedSize(true);recyclerView.setAdapter(new MyRecyclerAdapter(createMockList(), R.layout.item));recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setItemAnimator(new DefaultItemAnimator());

setHasFixedSize()方法用来使RecyclerView保持固定的大小,该信息被用于自身的优化。

0 0
原创粉丝点击