美文网首页
RecyclerView的关键用法总结, 张鸿洋大神的课后笔记

RecyclerView的关键用法总结, 张鸿洋大神的课后笔记

作者: fc82bb084ee7 | 来源:发表于2018-03-29 15:57 被阅读127次
    课程学习笔记

    张鸿洋大神的课程, 明日之星-RecyclerView
    https://www.imooc.com/learn/424

    代码直接看张鸿洋大神的blog即可: https://blog.csdn.net/lmj623565791/article/details/45059587
    详细的代码可以看: https://github.com/carrys17/RecyclerViewTest

    为什么叫做RecyclerView

    RecyclerView在功能上和ListView是相似的, 那么为什么把它的名字起名叫做RecyclerView呢? 有没有想过这个问题?
    以ListView为例, 它使用的Adapter通常是继承自BaseAdapter. 在它的核心方法 getView() 中, 有经验的开发人员都知道要使用ViewHolder的模式, 避免反射layout file, 來提高代码的执行效率.
    但我们也知道, 在ListView中, 并没有强制要求开发者必须使用ViewHolder的模式. 这就造成了使用ListView的话, 如果开发者的经验不足, 可能会写出一些效率低的ListView代码出来.

    而RecyclerView使用的Adapter, 并不是继承自BaseAdapter, 而是RecyclerView自己的內部类, RecyclerView.Adapter

    public abstract static class Adapter<VH extends ViewHolder> {
    
    }
    
    

    这里的ViewHolder, 也是RecyclerView自己的内部类, RecyclerView.ViewHolder

    public abstract static class ViewHolder {
    }
    
    

    这样, 如果要使用RecyclerView的话, 就等于强制要求开发人员必须使用ViewHolder的模式, 保证了代码的执行效率. 这就是RecyclerView, 即"回收View"这个名字的由来.

    相比ListView来说最大的好处.
    1. 是强制开发人员使用ViewHolder的模式, 保证代码的执行效率.
    2. 动态的改变布局样式, 在ListView, GridView, 瀑布流这几种样式之间, 可以非常方便的进行动态切换.
    简洁的代码

    HomeAdaper.java

    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.RecyclerView.ViewHolder;
    
        class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
        {
    
            @Override
            public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
            {
                MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                        HomeActivity.this).inflate(R.layout.item_home, parent,
                        false));
                return holder;
            }
    
    
            @Override
            public void onBindViewHolder(MyViewHolder holder, int position)
            {
                holder.tv.setText(mDatas.get(position));
            }
    
            @Override
            public int getItemCount()
            {
                return mDatas.size();
            }
    
            class MyViewHolder extends ViewHolder
            {
    
                TextView tv;
    
                public MyViewHolder(View view)
                {
                    super(view);
                    tv = (TextView) view.findViewById(R.id.id_num);
                }
            }
        }
    
    

    这里的onCreateViewHolder()和onBindViewHolder(), 实际上就是把ListView BaseAdapter中的getView()的实现, 强制分解成了2步来完成.
    onCreateViewHolder()的目的是, 获取到每个item的view 对象.
    onBindViewHolder()的目的是, 给每个item view 去绑定数据.

    public class HomeActivity extends Activity
    {
    
        private RecyclerView mRecyclerView;
        private List<String> mDatas;
        private HomeAdapter mAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_single_recyclerview);
    
            initData();
            mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
            mRecyclerView.setAdapter(mAdapter = new HomeAdapter());
    
        }
    
        protected void initData()
        {
            mDatas = new ArrayList<String>();
            for (int i = 'A'; i < 'z'; i++)
            {
                mDatas.add("" + (char) i);
            }
        }
    }
    
    
    如何设置具体的布局样式, 重点是如何实现瀑布流的效果.

    //设置为线性布局, 样子就和普通的ListView一样了.

    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    

    //设置为gridView的样式, eg. 下面这样设置就是每行展示4个小宫格.

    mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
    

    //设置为瀑布流的效果, 直接使用StaggeredGridLayoutManager就行. eg. 下面这样设置, 就是每行展示4个小宫格.

    //瀑布流的实现本质就是给每个item view都设置一个随机的高度值,
    //然后再使用StaggeredGridLayoutManager, 这样就实现了瀑布流的效果.
    mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));
    

    设置随机高度值的代码在这里:
    在onBindViewHolder()中, 也就是在给每个item view 绑定数据时, 给每个item view设置一个新的随机的高度值.

    public class StaggeredAdapter extends MyViewAdapter{
    
    
        private List<Integer>mHeights;
    
        public StaggeredAdapter(Context context, List<String>datas){
            super(context,datas);
    
            mHeights = new ArrayList<>();
            for (int i = 0; i<mDatas.size();i++){
                //高度取值在100~400px之间的一个随机值.
                mHeights.add((int) (100+Math.random()*300));
            }
        }
    
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.mItemTX.setText(mDatas.get(position));
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            lp.height = mHeights.get(position);
    
            //在这里, 从新设置每个item view的高度值, 给它设置一个随机值.
            holder.itemView.setLayoutParams(lp);
    
    
            setUpItemEvent(holder);
        }
    
    
    
    }
    
    
    
    如何设置每行item view 之间的分割线的样式

    我们可以通过该方法添加分割线:

    mRecyclerView.addItemDecoration()
    

    该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类.
    github上有一些现成的实现类, eg. DividerItemDecoration

    public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    }
    

    这个类实现的是一个颜色渐变的分割线的效果.

    具体的实现就先不看了, 用到的时候再说.

    如何设置每个 item增加、删除时的动画

    ItemAnimator也是一个抽象类,好在系统为我们提供了一种默认的实现类, DefaultItemAnimator.
    github上有一些ItemAnimator的实现类, 实现了更好的动画效果, 可以这里找到.
    https://github.com/gabrielemariotti/RecyclerViewItemAnimators

    // 设置item动画
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    
    public void addData(int position) {
            mDatas.add(position, "Insert One");
            notifyItemInserted(position);
        }
    
        public void removeData(int position) {
                mDatas.remove(position);
            notifyItemRemoved(position);
        }
    

    有一点细节要注意, 这里更新数据集不是用adapter.notifyDataSetChanged()而是
    notifyItemInserted(position)与notifyItemRemoved(position)
    否则没有动画效果。

    如何给RecyclerView设置item onClick listener 和 onLongClickListener.

    RecyclerView.Adapter 中并没有提供一个默认的ClickListener和LongClickListener.
    因此需要自己去写一个接口.

        public interface OnItemClickLitener
        {
            void onItemClick(View view, int position);
            void onItemLongClick(View view , int position);
        }
    
    class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
    {
    
    //...
        public interface OnItemClickLitener
        {
            void onItemClick(View view, int position);
            void onItemLongClick(View view , int position);
        }
    
        private OnItemClickLitener mOnItemClickLitener;
    
        public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
        {
            this.mOnItemClickLitener = mOnItemClickLitener;
        }
    
        @Override
        public void onBindViewHolder(final MyViewHolder holder, final int position)
        {
            holder.tv.setText(mDatas.get(position));
    
            // 如果用户设置了回调对象进来,则设置点击事件
            if (mOnItemClickLitener != null)
            {
                // 在这里给item view设置点击回调.
                holder.itemView.setOnClickListener(new OnClickListener()
                {
                    @Override
                    public void onClick(View v)
                    {
                        int pos = holder.getLayoutPosition();
                        mOnItemClickLitener.onItemClick(holder.itemView, pos);
                    }
                });
    
                holder.itemView.setOnLongClickListener(new OnLongClickListener()
                {
                    @Override
                    public boolean onLongClick(View v)
                    {
                        int pos = holder.getLayoutPosition();
                        mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                        return false;
                    }
                });
            }
        }
    //...
    }
    
    一点意外的收获

    大神讲课用的是eclipse, 里面有个log filter 挺好用的, 我在android studio的插件库中找到了个logviewer, 也可以实现类似的效果.
    logviewer的用法总结到简书的文章中去了.

    ---DONE.---

    相关文章

      网友评论

          本文标题:RecyclerView的关键用法总结, 张鸿洋大神的课后笔记

          本文链接:https://www.haomeiwen.com/subject/olnmcftx.html