Android高级UI开发(二)RecyclerView控件使用----列表项的单击事件、添加(删除)列表项

举报
yd_57386892 发表于 2020/12/28 23:04:12 2020/12/28
【摘要】       上篇文章介绍了RecyclerView控件的基本用法,我们已经知道它是一个ListView的升级版,可轻松的展示各种列表风格,例如水平列表、垂直列表、网格列表、瀑布流列表等。但是,我们项目中仅仅展示数据是不够的,我们经常还有列表项的单击事件、添加列表项、删除列表项等。今天我们就着重讲解一下RecyclerView列表项的单击事件、添加列表项、删除列表项。 效果:...

      上篇文章介绍了RecyclerView控件的基本用法,我们已经知道它是一个ListView的升级版,可轻松的展示各种列表风格,例如水平列表、垂直列表、网格列表、瀑布流列表等。但是,我们项目中仅仅展示数据是不够的,我们经常还有列表项的单击事件、添加列表项、删除列表项等。今天我们就着重讲解一下RecyclerView列表项的单击事件、添加列表项、删除列表项。

效果:

1. RecyclerView列表项的单击事件

  不幸的是RecyclerView控件没有与ListView一样的 onItemClickListener单击事件监听器,那么就需要我们自定义onItemClickListener。我们先贴出MyRecyclerAdapter源码(在上一篇源码基础上修改,用来给RecyclerView装配数据的adapter)


  
  1. package com.anyikang.volunteer.sos.recyclerview;
  2. import android.support.v7.widget.RecyclerView;
  3. import android.view.View;
  4. import android.view.ViewGroup;
  5. import android.widget.TextView;
  6. import java.util.List;
  7. public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {
  8. private List<String> list; //列表数据
  9. private OnItemClickListener mOnItemClickListener;
  10. public MyRecyclerAdapter(List<String> list) {
  11. // TODO Auto-generated constructor stub
  12. this.list = list;
  13. }
  14. /**
  15. *
  16. * 实例化 列表项布局中的控件,在此为一个简单的textview
  17. */
  18. class MyViewHolder extends RecyclerView.ViewHolder{
  19. TextView tv;
  20. public MyViewHolder(View view) {
  21. super(view);
  22. tv = (TextView)view.findViewById(R.id.text1);
  23. }
  24. }
  25. /**
  26. * 要显示的列表项数
  27. * @return 列表项总数
  28. */
  29. @Override
  30. public int getItemCount() {
  31. // TODO Auto-generated method stub
  32. return list.size();
  33. }
  34. /**
  35. * 用数据填充列表项上的 textview文本
  36. * @param holder: 当前列表项 布局的 控件实例
  37. * @param position: 列表项的索引
  38. */
  39. @Override
  40. public void onBindViewHolder(MyViewHolder holder, final int position) {
  41. holder.tv.setText(list.get(position)); //将列表数据list数组中的position位置的字符串 填充给 这个列表项上的textview
  42. //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
  43. if(mOnItemClickListener!=null){
  44. holder.itemView.setOnClickListener(new View.OnClickListener() {
  45. @Override
  46. public void onClick(View v) {
  47. mOnItemClickListener.onItemClick(v, position);
  48. }
  49. });
  50. }
  51. }
  52. /**
  53. * 为列表项实例化布局,将在onBindViewHolder里为布局控件赋值
  54. * @param viewGroup
  55. * @param arg1
  56. * @return
  57. */
  58. @Override
  59. public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int arg1) {
  60. MyViewHolder holder = new MyViewHolder(View.inflate(viewGroup.getContext(), R.layout.list_item, null));
  61. return holder;
  62. }
  63. public interface OnItemClickListener{
  64. void onItemClick(View view, int position);
  65. }
  66. public void setOnItemClickListener(OnItemClickListener listener){
  67. this.mOnItemClickListener = listener;
  68. }
  69. }
红色标注的代码,就实现了一个列表单击监听器。我们先回顾一下listview的itemOnclickListener在代码中是如何运用的:
 

//listview列表项单击事件,放在一个Activity里,例如MainActivity


  
  1. lvFence.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  2. @Override
  3. public void onItemClick(AdapterView<?> parent, View view, int position, long id)
 //在这里添加单击处理代码
 

  
  1. return;
  2. }
  3. });
上述代码通过调用listview的setOnItemClickListener函数为listview设置了一个 单击监听器OnItemClickListener类对象,
 

我们从中能分析到什么?

(1)Listview类里有一个成员变量,该成员变量是一个OnItemClickListener类的实例对象。同时,有一个setOnItemClickListener函数来设置该成员变量的具体实例值。

(2)从new AdapterView.OnItemClickListener()这行代码可以猜测OnItemClickListener可能是定义在ListView类中的一个抽象接口,需要在MainActivity里通过 实现(实例化)这个接口以及它包含的抽象函数onItemClick 来处理业务逻辑。当ListView列表项被单击时,ListView会调用OnItemClickListener类型的成员对象(已通过setOnItemClickListener赋值)的 onItemClick函数,由于onItemClick函数实质是在MainActivity里实现的,因此onItemClick的处理代码将在MainActivity里执行,这也就是我们通常所说的“回调”,即在MainActivity里先实现抽象函数,这时并没有调用,而是在恰当的时机回过头来调用onItemClick函数。

综合(1)(2)分析类比,我们为RecyclerView控件自定义了列表项监听功能,具体步骤如下:

第一步,在适配器MyRecyclerAdapter类里定义抽象接口“OnItemClickListener”,其中有一个抽象函数OnItemClick。

第二步,在适配器MyRecyclerAdapter类声明一个OnItemClickListener类型的成员变量与setOnItemClickListener函数。

第三步,在Activity(例如MainActivity)里实现化接口OnItemClickListener及OnItemClick函数,并调用setOnItemClickListener函数为MyRecyclerAdapter中的OnItemClickListener类型成员变量赋值。

第四步,回调。在MyRecyclerAsetOnClickListenerdapter的onBindViewHolder函数里为列表项对应的VIEW布局的单击函数

 

(这个系统里已经有了,就是普通的按钮单击事件处理)里回调onItemClick函数,具体核心代码如下:
 

  
  1. //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
  2. if(mOnItemClickListener!=null){
  3. holder.itemView.setOnClickListener(new View.OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. mOnItemClickListener.onItemClick(v, position);
  7. }
  8. });
  9. }
到此,为RecyclerView控件补充我们自定义的列表项单击事件分析完毕,具体源码在文章最后。
 

2. RecyclerView添加、删除列表项与高效更新

当我们更新RecyclerView控件的列表数据时,以往的作法有如下:

(1)setAdapter ,为控件配置数据适配器,同时刷新全部列表项

 

(2)notifyDataSetChanged 刷新全部列表项数据

以上2种作法比较影响效率,RecyclerView控件为我们提供了 更有效率的两个刷新列表项函数:

   函数1----public final void notifyItemInserted(int position) 

  用于在某一个列表项位置position上新添加一个列表项的情况下刷新列表。示例代码如下:

  
 
  list.add(position,"additem"+position);   //在列表数据数组List<String>的position位置上添加一个新数据 

 
  //notifyDataSetChanged();--会影响效率=
 
 
 
notifyItemInserted(position); 
 
其中notifyItemInserted(position)不会重新刷新整个列表数据,只是在position位置上新绘制一个列表项,同时原来
 
position位置上的列表项的索引 变为position + 1,即从原position位置开始的列表项统一后移。
 

 函数2--notifyItemRemoved(int position) 

 

 
 
  list.remove(position,"additem"+position);   //在列表数据数组List<String>的position位置上删除一个新数据 

 
  //notifyDataSetChanged();--会影响效率=
 
 
 
 
 
notifyItemRemoved(position); 
 
其中notifyItemInserted(position)不会重新刷新整个列表数据,只是在position位置上删除一个列表项,
 
同时原来position+1位置上的列表项的索引 变为position,即从原position+1位置开始的列表项统一前移。
 
完整的代码先贴出来:
 

布局文件:


  
  1. RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. >
  6. <android.support.v7.widget.RecyclerView
  7. android:id="@+id/recylerview"
  8. android:layout_width="match_parent"
  9. android:layout_height="400dp"
  10. />
  11. <LinearLayout
  12. android:layout_marginTop="30dp"
  13. android:layout_below="@+id/recylerview"
  14. android:orientation="horizontal"
  15. android:layout_width="match_parent"
  16. android:layout_height="match_parent">
  17. <Button
  18. android:id="@+id/btAdd"
  19. android:text="添加"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content" />
  22. <Button
  23. android:layout_marginLeft="20dp"
  24. android:id="@+id/btDelete"
  25. android:text="删除"
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content" />
  28. </LinearLayout>
  29. </RelativeLayout>
MainActivity代码:
 

   


  
  1. package com.anyikang.volunteer.sos.recyclerview;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.support.v7.widget.DefaultItemAnimator;
  5. import android.support.v7.widget.LinearLayoutManager;
  6. import android.support.v7.widget.RecyclerView;
  7. import android.support.v7.widget.StaggeredGridLayoutManager;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.Toast;
  11. import com.anyikang.volunteer.sos.recyclerview.MyRecyclerAdapter.OnItemClickListener;
  12. import java.util.ArrayList;
  13. public class MainActivity extends Activity {
  14. private RecyclerView recylerview; //RecyclerView控件实例对象
  15. private ArrayList<String> list; //RecyclerView要显示的 列表数据,在此为一组字符串。
  16. private MyRecyclerAdapter adapter; //同ListView一样,需要一个适配器来 将list数据 装载到 RecyclerView列表控件。
  17. //private MyStaggedRecyclerAdapter adapter; //列表显示风格 为瀑布流 界面样式 的 适配器。
  18. boolean isGrid = true;
  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.activity_main);
  23. initView();
  24. initData();
  25. }
  26. public void initView()
  27. {
  28. //实例化布局中的recylerview控件
  29. recylerview = (RecyclerView)findViewById(R.id.recylerview);
  30. Button btAdd = findViewById(R.id.btAdd);
  31. Button btDelete = findViewById(R.id.btDelete);
  32. Button btConvert = findViewById(R.id.btConvert);
  33. btAdd.setOnClickListener(new View.OnClickListener() {
  34. @Override
  35. public void onClick(View view) {
  36. adapter.addData(3);
  37. }
  38. });
  39. btDelete.setOnClickListener(new View.OnClickListener() {
  40. @Override
  41. public void onClick(View view) {
  42. adapter.removeData(3);
  43. }
  44. });
  45. }
  46. public void initData()
  47. {
  48. //模拟60条数据
  49. list = new ArrayList<String>();
  50. for (int i = 0; i < 60; i++) {
  51. list.add("item"+i);
  52. }
  53. //普通列表的适配器
  54. adapter = new MyRecyclerAdapter(list);
  55. //列表显示风格为 垂直方向的列表
  56. //recylerview.setLayoutManager(new LinearLayoutManager(this));
  57. //列表显示风格为 水平方向的列表
  58. //recylerview.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
  59. //列表显示风格为 瀑布流样式
  60. recylerview.setLayoutManager(new StaggeredGridLayoutManager(3, LinearLayoutManager.VERTICAL));
  61. //列表显示风格为 网格样式,如9宫格布局
  62. //recylerview.setLayoutManager(new GridLayoutManager(this, 3));
   
 
 //瀑布流适配器,与普通适配器adapter的区别是,每一个列表项的布局大小都可能参差不齐 
 
 //adapter = new MyStaggedRecyclerAdapter(list); 
 

//装载显示列表数据 recylerview.setAdapter(adapter); recylerview.setItemAnimator(new DefaultItemAnimator());//添加删除列表项时会有动画效果,具体运行源码查看。 adapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, "点了"+position, Toast.LENGTH_SHORT).show(); } }); return; }}

adapter代码:
 

 


  
  1. package com.anyikang.volunteer.sos.recyclerview;
  2. import android.support.v7.widget.RecyclerView;
  3. import android.view.View;
  4. import android.view.ViewGroup;
  5. import android.widget.TextView;
  6. import java.util.List;
  7. public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {
  8. private List<String> list; //列表数据
  9. private OnItemClickListener mOnItemClickListener;
  10. public MyRecyclerAdapter(List<String> list) {
  11. // TODO Auto-generated constructor stub
  12. this.list = list;
  13. }
  14. /**
  15. *
  16. * 实例化 列表项布局中的控件,在此为一个简单的textview
  17. */
  18. class MyViewHolder extends RecyclerView.ViewHolder{
  19. TextView tv;
  20. public MyViewHolder(View view) {
  21. super(view);
  22. tv = (TextView)view.findViewById(R.id.text1);
  23. }
  24. }
  25. /**
  26. * 要显示的列表项数
  27. * @return 列表项总数
  28. */
  29. @Override
  30. public int getItemCount() {
  31. // TODO Auto-generated method stub
  32. return list.size();
  33. }
  34. /**
  35. * 用数据填充列表项上的 textview文本
  36. * @param holder: 当前列表项 布局的 控件实例
  37. * @param position: 列表项的索引
  38. */
  39. @Override
  40. public void onBindViewHolder(MyViewHolder holder, final int position) {
  41. holder.tv.setText(list.get(position)); //将列表数据list数组中的position位置的字符串 填充给 这个列表项上的textview
  42. //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
  43. if(mOnItemClickListener!=null){
  44. holder.itemView.setOnClickListener(new View.OnClickListener() {
  45. @Override
  46. public void onClick(View v) {
  47. mOnItemClickListener.onItemClick(v, position);
  48. }
  49. });
  50. }
  51. }
  52. /**
  53. * 为列表项实例化布局,将在onBindViewHolder里为布局控件赋值
  54. * @param viewGroup
  55. * @param arg1
  56. * @return
  57. */
  58. @Override
  59. public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int arg1) {
  60. MyViewHolder holder = new MyViewHolder(View.inflate(viewGroup.getContext(), R.layout.list_item, null));
  61. return holder;
  62. }
  63. public void addData(int position){
  64. list.add(position,"additem"+position);
  65. //提示刷新--会影响效率
  66. // notifyDataSetChanged();
  67. notifyItemInserted(position);
  68. }
  69. public void removeData(int position){
  70. list.remove(position);
  71. notifyItemRemoved(position);
  72. }
  73. public interface OnItemClickListener{
  74. void onItemClick(View view, int position);
  75. }
  76. public void setOnItemClickListener(OnItemClickListener listener){
  77. this.mOnItemClickListener = listener;
  78. }

}

完整的工程源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/10364579

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/79968066

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。