RecyclerView基础详解

一.简介

RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比ListView更好。原理与ListView原理是类似的:都是仅仅维护少量的View并且可以展示大量的数据集。RecyclerView用以下两种方式简化了数据的展示和处理:

 

1.使用LayoutManager来确定每一个item的排列方式。

2.为增加和删除项目提供默认的动画效果。

 

你也可以定义你自己的LayoutManager和添加删除动画,RecyclerView项目结构如下:


 

Adapter:使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器,作用是将数据与每一个item的界面进行绑定。

 

LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。回收或重用一个View的时候,LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法(与ListView原理类似)。

 

 

 

 

 

 

 

二.基础使用Demo

 

1.配置Gradle

implementation 'com.android.support:recyclerview-v7:28.0.0'

 

 

2.Activity布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@color/colorPrimary"
        android:orientation="horizontal"
        android:weightSum="3"
        tools:ignore="MissingConstraints">

        <TextView
            android:id="@+id/activity_recyclerview_textview1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="添加数据"
            android:textColor="#FFFFFF">

        </TextView>

        <View
            android:layout_width="0.5dp"
            android:layout_height="match_parent"
            android:background="#FFFFFF">

        </View>

        <TextView
            android:id="@+id/activity_recyclerview_textview2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="删除数据"
            android:textColor="#FFFFFF">

        </TextView>

        <View
            android:layout_width="0.5dp"
            android:layout_height="match_parent"
            android:background="#FFFFFF">

        </View>

        <TextView
            android:id="@+id/activity_recyclerview_textview3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:text="更新数据"
            android:textColor="#FFFFFF">

        </TextView>

    </LinearLayout>

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/activity_recyclerview_srl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="20dp">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/activity_recyclerview_recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </androidx.recyclerview.widget.RecyclerView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</LinearLayout>

 

 

3.Activity

public class RecyclerViewActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView mRecyclerView;
    private RecycleViewAdapter mRecycleViewAdapter;
    private List<RecyclerViewBean> mList;
    private TextView mAddTextView;
    private TextView mDelTextView;
    private TextView mUpdateTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);
        initView();
    }

    /**
     * 初始化各种View
     */

    private void initView() {
        mAddTextView = findViewById(R.id.activity_recyclerview_textview1);
        mDelTextView = findViewById(R.id.activity_recyclerview_textview2);
        mUpdateTextView = findViewById(R.id.activity_recyclerview_textview3);
        mAddTextView.setOnClickListener(this);
        mDelTextView.setOnClickListener(this);
        mUpdateTextView.setOnClickListener(this);
        mRecyclerView = findViewById(R.id.activity_recyclerview_recyclerView);
        mList = getList();
        //1.设置LinearLayoutManager ListView
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //2.设置固定大小
        mRecyclerView.setHasFixedSize(true);
        //3.设置Adapter
        mRecycleViewAdapter = new RecycleViewAdapter(this, mList);
        mRecyclerView.setAdapter(mRecycleViewAdapter);
        //4.RecyclerView点击事件
        onRecyclerViewClick();
        //5.RecyclerView滚动事件
        addOnScrollListener();
    }

    /**
     * RecyclerView点击事件
     */

    private void onRecyclerViewClick() {
        mRecycleViewAdapter.setRecyclerViewItemClick(new IRecyclerViewItemClick() {
            @Override
            public void onItemClick(View view, int position) {
                Log.d("RecyclerViewActivity", "RecyclerView点击 position----:" + position);
                Log.d("RecyclerViewActivity", "RecyclerView点击 title----:" + mList.get(position).getTitle());
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Log.d("RecyclerViewActivity", "RecyclerView长按 position----:" + position);
                Log.d("RecyclerViewActivity", "RecyclerView长按 title----:" + mList.get(position).getTitle());
            }
        });
    }

    /**
     * 滚动监听
     */

    private void addOnScrollListener() {
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case SCROLL_STATE_SETTLING://滚动

                        break;
                    case SCROLL_STATE_DRAGGING://拖动

                        break;
                    case SCROLL_STATE_IDLE://空闲

                        break;
                    default://其他
                        break;
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });
    }

    /**
     * 初始化集合数据
     */

    private List<RecyclerViewBean> getList() {

        List<RecyclerViewBean> list = new ArrayList<>();

        RecyclerViewBean listViewBean1 = new RecyclerViewBean();
        listViewBean1.setAva("");
        listViewBean1.setTitle("张三");

        RecyclerViewBean listViewBean2 = new RecyclerViewBean();
        listViewBean2.setAva("");
        listViewBean2.setTitle("韦德");

        RecyclerViewBean listViewBean3 = new RecyclerViewBean();
        listViewBean3.setAva("");
        listViewBean3.setTitle("保罗");

        for (int i = 0; i < 10; i++) {
            list.add(listViewBean1);
            list.add(listViewBean2);
            list.add(listViewBean3);
        }

        return list;
    }

    /**
     * 各种点击事件
     */

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.activity_recyclerview_textview1) {//添加数据
            RecyclerViewBean recyclerViewBean = new RecyclerViewBean();
            recyclerViewBean.setTitle("添加的数据");
            mRecycleViewAdapter.addData(recyclerViewBean, 2);
        } else if (id == R.id.activity_recyclerview_textview2) {//删除数据
            mRecycleViewAdapter.removeData(2);
        } else if (id == R.id.activity_recyclerview_textview3) {//更新数据
            RecyclerViewBean recyclerViewBean = mList.get(3);
            recyclerViewBean.setTitle("单条数据更新");
            mRecycleViewAdapter.updateData(recyclerViewBean, 3);
        }
    }
}

 

 

4.Adapter

public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder> {

    private IRecyclerViewItemClick mClick;

    public void setRecyclerViewItemClick(IRecyclerViewItemClick click) {
        mClick = click;
    }

    private List<RecyclerViewBean> mList;
    private LayoutInflater mInflater;

    public RecycleViewAdapter(Context context, List<RecyclerViewBean> list) {
        mList = list;
        mInflater = LayoutInflater.from(context);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(mList.get(position).getTitle());

        //Item点击事件
        holder.itemView.setOnClickListener(v -> {
            if (null != mClick) {
                mClick.onItemClick(v, position);
            }
        });

        //Item长按事件
        holder.itemView.setOnLongClickListener(v -> {
            if (null != mClick) {
                mClick.onItemLongClick(v, position);
            }
            return true;
        });
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    /**
     * ViewHolder类
     */

    static class ViewHolder extends RecyclerView.ViewHolder {

        private TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.recyclerview_item_textview);
        }
    }

    /**
     * 刷新数据 全量
     */

    public void updateData(List<RecyclerViewBean> list) {
        if (null == list || list.size() == 0) return;
        mList = list;
        notifyDataSetChanged();
    }

    /**
     * 添加数据
     */

    public void addData(RecyclerViewBean recyclerViewBean, int position) {
        mList.add(position, recyclerViewBean);//集合中添加数据
        notifyItemInserted(position);//Adapter添加数据 内部调用notifyItemRangeInserted(position, 1)
        notifyItemRangeChanged(position, mList.size());//Adapter数据变化范围 不添加此行代码 也能添加 但是点击时可能错乱
    }

    /**
     * 删除数据
     */

    public void removeData(int position) {
        mList.remove(position);//集合中删除数据
        notifyItemRemoved(position);//Adapter删除数据 内部调用notifyItemRangeRemoved(position, 1)
        notifyItemRangeChanged(position, mList.size());//Adapter数据变化范围 不添加此行代码点 也能删除 但是击时可能错乱
    }

    /**
     * 更新数据
     * 这种方式更新一个Item其实是有问题的 尤其是列表中数据比较多时,可能会造成Item错乱
     */

    public void updateData(RecyclerViewBean recyclerViewBean, int position) {
        mList.set(position, recyclerViewBean);//集合中更新数据
        notifyItemChanged(position);//Adapter更新数据 内部调用notifyItemRangeChanged(position, 1)
    }

}

 

 

5. Item布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="90dp">

        <ImageView
            android:id="@+id/recyclerview_item_imageview"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginStart="10dp"
            android:scaleType="fitXY"
            android:src="@color/colorPrimary"/>

        <TextView
            android:id="@+id/recyclerview_item_textview"
            android:layout_width="wrap_content"
            android:layout_height="70dp"
            android:gravity="center|left"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/recyclerview_item_imageview"
            android:layout_marginLeft="15dp"
            android:text="张三"/>
    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="#88CCCCCC">

    </View>

</LinearLayout>

 

 

6.接口

public interface IRecyclerViewItemClick {

    /**
     * Item点击事件
     *
     * @param view     View
     * @param position 位置
     */
    void onItemClick(View view, int position);

    /**
     * Item长按事件
     *
     * @param view     View
     * @param position 位置
     */
    void onItemLongClick(View view, int position);

}

 

 

 

 

 

 

三.具体知识讲解

1.包

RecycleView所在包android.support.v7.widget.RecyclerView。

 

 

2.Adapter

和ListView直接继承BaseAdapter不同。RecycleView的适配器

继承RecyclerView.Adapter<XXXAdapter.ViewHolder>。然后至少需要重写三个方法。

onCreateViewHolder方法:引入Item布局。

 
onBindViewHolder方法:获取数值。

 
getItemCount方法:获取列表Item条数。

 

 

 

3.Item点击

与ListView不同,RecycleView没有直接提供Item点击以及Item长按事件。需要自己写。详解见上面Demo。

 

 

 

4. 删除和添加数据

RecycleView 删除 添加 单条数据 非常方便。

Adapter中

/**
 * 添加数据
 */

public void addData(RecyclerViewBean recyclerViewBean, int position) {
    mList.add(position, recyclerViewBean);//集合中添加数据
    notifyItemInserted(position);//Adapter添加数据 内部调用notifyItemRangeInserted(position, 1)
    notifyItemRangeChanged(position, mList.size());//Adapter数据变化范围 不添加此行代码 也能添加 但是点击时可能错乱
}

/**
 * 删除数据
 */

 public void removeData(int position) {
    mList.remove(position);//集合中删除数据
    notifyItemRemoved(position);//Adapter删除数据 内部调用notifyItemRangeRemoved(position, 1)
    notifyItemRangeChanged(position, mList.size());//Adapter数据变化范围 不添加此行代码点 也能删除 但是击时可能错乱
}

备注

RecyclerView所有的刷新Item方法以及说明

notifyItemChanged(int)//内部调用notifyItemRangeChanged(position, 1) 更新单条Item时使用 但是问题比较多 尤其是列表中数据比较多时 所以局部刷新 不能使用这种方式 详解见下面

notifyItemInserted(int)//插入一条数据 内部调用notifyItemRangeInserted(position, 1) 一般结合notifyItemRangeChanged方法使用 即插入指定位置的数据后通知 从该位置到集合的底部 数据发生改变

notifyItemRemoved(int)//删除一条数据 内部调用notifyItemRangeRemoved(position, 1) 一般结合notifyItemRangeChanged方法使用   即删除指定位置的数据后通知 从该位置到集合的底部 数据发生改变

notifyItemRangeChanged(int, int)//数据发生改变  即 删除指定位置的数据 或者插入指定位置的数据 后通知 从该位置到集合的底部 数据发生改变

notifyItemRangeInserted(int, int)//notifyItemInserted(int)方法内部调用

notifyItemRangeRemoved(int, int)//notifyItemRemoved(int)方法内部调用

添加单条数据,删除单条数据。RecyclerView给我们提供了局部的刷新方法。但是更新一个Item或者集合中有几个Bean发生变化时可能会有问题。

局部刷新详解

RecycleView实现下拉刷新(DiffUtil工具实现局部刷新)

https://blog.csdn.net/weixin_37730482/article/details/71173037

 

 

 

5.滚动事件

RecycleView的滚动事件最好是这样添加。

recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener())

因为

recyclerview.setOnScrollListener(new RecyclerView.OnScrollListener())

可能会出现空指针,且已过期。另外RecycleView滚动事件 状态

SCROLL_STATE_SETTLING:滚动

SCROLL_STATE_DRAGGING:拖动

SCROLL_STATE_IDLE:空闲

 

 

 

 

6.LayoutManager

目前SDK中提供了三种自带的LayoutManager

LinearLayoutManager:ListView列表

GridLayoutManager:GridView列表

StaggeredGridLayoutManager:纵向列表

recyclerview.setLayoutManager(new LinearLayoutManager(this));
recyclerview.setLayoutManager(new GridLayoutManager(GlideRecycleViewActivity.this, 4));//4:GridView一行显示几个Item
recyclerview.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.HORIZONTAL));2:纵向列表一页显示几行item

 

 

 

7.动画效果

可设置RecycleView的Animator(动画效果,这里以默认为例)

recyclerview.setItemAnimator(new DefaultItemAnimator());

自定义动画

https://blog.csdn.net/weixin_37730482/article/details/72822878

 

 

8.RecyclerView的Item隐藏

需求中,可能有这样的需求。就是RecyclerView列表中可能某一个Item需要隐藏不展示。如果仅仅使用传统的GONE的用法,可能会出现空白的问题。

public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder> {


    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.textView.setText(mList.get(position).getTitle());

        //Item点击事件
        holder.itemView.setOnClickListener(v -> {
            if (null != mClick) {
                mClick.onItemClick(v, position);
            }
        });

        //Item长按事件
        holder.itemView.setOnLongClickListener(v -> {
            if (null != mClick) {
                mClick.onItemLongClick(v, position);
            }
            return true;
        });

        //模拟Item隐藏与否
        if (position == 5) {
            setRecyclerViewItemVisibility(holder.itemView, false);
        }
    }


    /**
     * Item隐藏显示
     */

    public void setRecyclerViewItemVisibility(View itemView, boolean isVisible) {
        RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) itemView.getLayoutParams();
        if (isVisible) {
            param.height = 100;//具体值看具体需求
            param.width = LinearLayout.LayoutParams.MATCH_PARENT;//具体值看具体需求
            itemView.setVisibility(View.VISIBLE);
        } else {
            itemView.setVisibility(View.GONE);
            param.height = 0;
            param.width = 0;
        }
        itemView.setLayoutParams(param);
    }

}

 

 

 

9.Demo

代码链接:https://github.com/wujianning/ViewListDemo

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值