美文网首页程序员Android开发Android开发经验谈
ListView 与 RecyclerView 你应该弄懂的都在

ListView 与 RecyclerView 你应该弄懂的都在

作者: 冬日毛毛雨 | 来源:发表于2020-11-27 21:36 被阅读0次

    好文推荐
    作者:JonesYang
    转载:https://juejin.cn/post/6899614958632812557#heading-3

    ListView 相关


    ListView 是什么?(上古神器)不,是不是该问 RecyclerView 是什么?(也是上古神器?在它的替代品出来之前最好别这样称呼)趁着这段时间,我想我也应该把这些乱七八糟的东西整理一下。

    OK,不演了,ListView 和 RecyclerView 都是用来展示列表数据了。相比与 ListView ,RecyclerView 更加强大,下面先说 ListView。

    ListView 适配器

    关于 ListView 先简单看一下它的适配器代码:

    public class ListViewAdapter extends BaseAdapter {
    
        //用于加载 item
        private LayoutInflater mInflater;
        //通过构造函数 把 Context 传递进来
        public ListViewAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
        }
    
        /**
         * 获取的数据存储在这个集合中,一般来说这个集合中存储了子项的 item
         */
        private List mList = new ArrayList();
    
        /**
         * @return 返回集合的大小
         */
        @Override
        public int getCount() {
            return mList.size();
        }
    
        /**
         * @param position
         * @return 返回具体的 item
         */
        @Override
        public Object getItem(int position) {
            return mList.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        /**
         * 作用:加载 子项 item 的布局
         *
         * @param position    item 的位置
         * @param convertView item 进行复用,避免一个 item 发生多次加载的情况
         * @param parent      父容器,根据具体的情况而定
         * @return item
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null){
                convertView = mInflater.inflate(R.layout.activity_detail,parent,false);
            }
            //对 item 进行复用,返回 convertView
            return convertView;
        }
    }
    

    ListView 的优化

    可以看到,基本上每一个 item 都需要在 getView() 中加载,如果 item 的数量过多,就会产生性能问题,影响用户体验。这个时候我们就需要使用 ViewHolder(开发者自定义类),这是 ListViewAdapter 的内部类,它的代码如下:

     /**
         * 作用:加载 子项 item 的布局
         *
         * @param position    item 的位置
         * @param convertView item 进行复用,避免一个 item 发生多次加载的情况
         * @param parent      父容器,根据具体的情况而定
         * @return item
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null){
                holder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.activity_detail,parent,false);
                convertView.setTag(holder);
            } else {
                如果 convertView 不为空,直接进行复用
                holder = (ViewHolder) convertView.getTag();
            }
            //对 item 进行复用,返回 convertView
            return convertView;
        }
        //这是一个内部类
        private class ViewHolder{
            //获取 item 的控件都定义在这里
        }
    

    好了,关于 ListView 就到这里了,下面总结两个关键点:

    • 自定义 ListViewAdapter ,继承 BaseAdapter。
    • 自定义 ViewHolder 和 convertView 一起完成复用优化工作。

    RecyclerView 相关


    下面开始写 RecyclerView ,先把 RecyclerView 的关键点总结在这里。其实和 ListView 是差不多的,主要有两条:

    • RecyclerViewAdapter 继承 Recyclerview.Adapter ,其内部类 ViewHolder 继承 RecyclerView.ViewHolder。
    • 设置布局管理器,控制布局效果

    RecyclerView 适配器

    先看下面 RecyclerView 适配器的代码:

    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
    
        /**
         * 这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。
         * 该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,
         * 当然这个ViewHolder需要我们自己去编写。
         *
         * @param parent
         * @param viewType
         * @return viewHolder
         */
        @NonNull
        @Override
        public RecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return null;
        }
    
        /**
         * 这个方法主要用于适配渲染数据到View中,
         * 方法提供给你了一viewHolder而不是原来的convertView
         *
         * @param holder
         * @param position
         */
        @Override
        public void onBindViewHolder(@NonNull RecyclerViewAdapter.ViewHolder holder, int position) {
            //在这里更新 UI
        }
    
        /**
         * @return 返回 item 的数量
         */
        @Override
        public int getItemCount() {
            return 0;
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    }
    

    从基础使用上看,我们明显可以看出,RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:

    • ViewHolder 的编写规范化了。
    • RecyclerView 复用 item 的工作 Google 全帮你搞定了,不需要再像 ListView 那样自己调用 setTag()。
    • RecyclerView 需要设置 KayoutManager

    如何在 Activity 中使用 RecyclerView

    接下来看一下如何在 Activity 中使用 RecyclerView :(ListView 大致相同)

            //1、设置布局管理器
            LinearLayoutManager manager = new LinearLayoutManager(this);
            RecyclerView recyclerView = findViewById(R.id.detail_rv);
            recyclerView.setLayoutManager(manager);
            //2、设置适配器
            RecyclerViewAdapter adapter = new RecyclerViewAdapter();
            recyclerView.setAdapter(adapter);
    

    RecyclerView 的布局管理器

    关于 RecyclerView ,还得再说一下它的布局管理器,RecyclerView 提供了三种布局管理器可供选择:

    • LinerLayoutManager 以垂直或者水平列表方式展示
    • GridLayoutManager 以网格方式展示item
    • StaggeredGridLayoutManager 以瀑布流方式展示Item

    之所以说 RecyclerView 更加强大,也正是因为 RecyclerView 提供了多种布局管理器,只需在 Activity 中进行设置即可。另外,关于布局管理器的一些API如下:

        canScrollHorizontally();//能否横向滚动
        canScrollVertically();//能否纵向滚动
        scrollToPosition(int position);//滚动到指定位置
    
        setOrientation(int orientation);//设置滚动的方向
        getOrientation();//获取滚动方向
    
        findViewByPosition(int position);//获取指定位置的Item View
        findFirstCompletelyVisibleItemPosition();//获取第一个完全可见的Item位置
        findFirstVisibleItemPosition();//获取第一个可见Item的位置
        findLastCompletelyVisibleItemPosition();//获取最后一个完全可见的Item位置
        findLastVisibleItemPosition();//获取最后一个可见Item的位置
    

    RecyclerView 的分割线

    我们可以为 REcyclerview 的 item 绘制分割线,用系统已经定义好的分割线:

    //添加分割线
    myRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    

    同样,我们也可以定义自己的分割线,实现不同的效果:
    自定义间隔样式需要继承RecyclerView.ItemDecoration类,该类是个抽象类,官方目前并没有提供默认的实现类,主要有三个方法。

    • onDraw(Canvas c, RecyclerView parent, State state),在Item绘制之前被调用,该方法主要用于绘制间隔样式。
    • onDrawOver(Canvas c, RecyclerView parent, State state),在Item绘制之前被调用,该方法主要用于绘制间隔样式。
    • getItemOffsets(Rect outRect, View view, RecyclerView parent, State state),设置item的偏移量,偏移的部分用于填充间隔样式,即设置分割线的宽、高;在RecyclerView的onMesure()中会调用该方法

    喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗~

    相关文章

      网友评论

        本文标题:ListView 与 RecyclerView 你应该弄懂的都在

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