Material Design材料设计原则----RecyclerView控件使用(二)列表项的单击事件、添加(删除)列表项

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

效果:


1. RecyclerView列表项的单击事件

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

package com.anyikang.volunteer.sos.recyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {

   private List<String> list;  //列表数据
   private OnItemClickListener mOnItemClickListener;

   public MyRecyclerAdapter(List<String> list) {
      // TODO Auto-generated constructor stub
      this.list = list;
   }

   /**
    *
    * 实例化 列表项布局中的控件,在此为一个简单的textview
    */
   class MyViewHolder extends RecyclerView.ViewHolder{
      TextView tv;

      public MyViewHolder(View view) {
         super(view);
         tv = (TextView)view.findViewById(R.id.text1);
      }
      
   }

   /**
    * 要显示的列表项数
    * @return 列表项总数
    */
   @Override
   public int getItemCount() {
      // TODO Auto-generated method stub
      return list.size();
   }

   /**
    * 用数据填充列表项上的 textview文本
    * @param holder:  当前列表项 布局的 控件实例
    * @param position: 列表项的索引
    */
   @Override
   public void onBindViewHolder(MyViewHolder holder, final int position) {
      holder.tv.setText(list.get(position));   //将列表数据list数组中的position位置的字符串 填充给 这个列表项上的textview

      //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
      if(mOnItemClickListener!=null){
         holder.itemView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
               mOnItemClickListener.onItemClick(v, position);
            }
         });
      }
   }


   /**
    * 为列表项实例化布局,将在onBindViewHolder里为布局控件赋值
    * @param viewGroup
    * @param arg1
    * @return
    */
   @Override
   public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int arg1) {
      MyViewHolder holder = new MyViewHolder(View.inflate(viewGroup.getContext(), R.layout.list_item, null));
      return holder;
   }

   public interface OnItemClickListener{
      void onItemClick(View view, int position);
   }

   public void setOnItemClickListener(OnItemClickListener listener){
      this.mOnItemClickListener = listener;
   }
}
红色标注的代码,就实现了一个列表单击监听器。我们先回顾一下listview的itemOnclickListener在代码中是如何运用的:

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

lvFence.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
       //在这里添加单击处理代码
        return;
    }
});
上述代码通过调用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函数,具体核心代码如下:
  //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
      if(mOnItemClickListener!=null){
         holder.itemView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
               mOnItemClickListener.onItemClick(v, position);
            }
         });
      }
到此,为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位置开始的列表项统一前移。
完整的代码先贴出来:

布局文件:

RelativeLayout 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.support.v7.widget.RecyclerView
        android:id="@+id/recylerview"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        />

    <LinearLayout
        android:layout_marginTop="30dp"
        android:layout_below="@+id/recylerview"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/btAdd"
            android:text="添加"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:layout_marginLeft="20dp"
            android:id="@+id/btDelete"
            android:text="删除"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</RelativeLayout>
MainActivity代码:

   

package com.anyikang.volunteer.sos.recyclerview;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.anyikang.volunteer.sos.recyclerview.MyRecyclerAdapter.OnItemClickListener;

import java.util.ArrayList;

public class MainActivity extends Activity {

   private RecyclerView recylerview;  //RecyclerView控件实例对象
   private ArrayList<String> list;    //RecyclerView要显示的 列表数据,在此为一组字符串。
    private MyRecyclerAdapter adapter; //ListView一样,需要一个适配器来 将list数据 装载到 RecyclerView列表控件。
   //private MyStaggedRecyclerAdapter adapter;  //列表显示风格  为瀑布流 界面样式 的 适配器。
   boolean isGrid = true;

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

   public void initView()
   {
      //实例化布局中的recylerview控件
      recylerview = (RecyclerView)findViewById(R.id.recylerview);
      Button btAdd = findViewById(R.id.btAdd);
      Button btDelete = findViewById(R.id.btDelete);
      Button btConvert = findViewById(R.id.btConvert);

      btAdd.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
            adapter.addData(3);
         }
      });

      btDelete.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
            adapter.removeData(3);
         }
      });
   }

   public void initData()
   {

      //模拟60条数据
      list = new ArrayList<String>();

      for (int i = 0; i < 60; i++) {
         list.add("item"+i);
      }


      //普通列表的适配器
      adapter = new MyRecyclerAdapter(list);

      //列表显示风格为 垂直方向的列表
      //recylerview.setLayoutManager(new LinearLayoutManager(this));

      //列表显示风格为 水平方向的列表
      //recylerview.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));

      //列表显示风格为 瀑布流样式
      recylerview.setLayoutManager(new StaggeredGridLayoutManager(3, LinearLayoutManager.VERTICAL));

      //列表显示风格为 网格样式,如9宫格布局
      //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代码:

package com.anyikang.volunteer.sos.recyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {

   private List<String> list;  //列表数据
   private OnItemClickListener mOnItemClickListener;

   public MyRecyclerAdapter(List<String> list) {
      // TODO Auto-generated constructor stub
      this.list = list;
   }

   /**
    *
    * 实例化 列表项布局中的控件,在此为一个简单的textview
    */
   class MyViewHolder extends RecyclerView.ViewHolder{
      TextView tv;

      public MyViewHolder(View view) {
         super(view);
         tv = (TextView)view.findViewById(R.id.text1);
      }
      
   }

   /**
    * 要显示的列表项数
    * @return 列表项总数
    */
   @Override
   public int getItemCount() {
      // TODO Auto-generated method stub
      return list.size();
   }

   /**
    * 用数据填充列表项上的 textview文本
    * @param holder:  当前列表项 布局的 控件实例
    * @param position: 列表项的索引
    */
   @Override
   public void onBindViewHolder(MyViewHolder holder, final int position) {
      holder.tv.setText(list.get(position));   //将列表数据list数组中的position位置的字符串 填充给 这个列表项上的textview

      //实现列表item单击事件,主要使用java interface来实现回调MainActivity中的onItemClick函数
      if(mOnItemClickListener!=null){
         holder.itemView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
               mOnItemClickListener.onItemClick(v, position);
            }
         });
      }
   }


   /**
    * 为列表项实例化布局,将在onBindViewHolder里为布局控件赋值
    * @param viewGroup
    * @param arg1
    * @return
    */
   @Override
   public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int arg1) {
      MyViewHolder holder = new MyViewHolder(View.inflate(viewGroup.getContext(), R.layout.list_item, null));
      return holder;
   }


   public void addData(int position){
      list.add(position,"additem"+position);
      //提示刷新--会影响效率
//    notifyDataSetChanged();
      notifyItemInserted(position);
   }
   public void removeData(int position){
      list.remove(position);
      notifyItemRemoved(position);
   }

   public interface OnItemClickListener{
      void onItemClick(View view, int position);
   }

   public void setOnItemClickListener(OnItemClickListener listener){
      this.mOnItemClickListener = listener;
   }

}

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

猜你喜欢

转载自blog.csdn.net/gaoxiaoweiandy/article/details/79968066
今日推荐