失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

时间:2023-05-05 08:30:57

相关推荐

Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

1. 引言:

RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一下观察者模式。

2.最终目的

模拟ListView的setOnItemClickListener()方法,调用者只须调用类似于setOnItemClickListener的东西就能获得被点击item的相关数据。

3.原理

为RecyclerView的每个子item设置setOnClickListener,然后在onClick中再调用一次对外封装的接口,将这个事件传递给外面的调用者。而"为RecyclerView的每个子item设置setOnClickListener"在Adapter中设置。其实直接在onClick中也能完全处理item的点击事件,但是这样会破坏代码的逻辑。

4. 具体步骤如下:

在自定义MyAdapter之中(继承自RecyclerView.Adapter)

(1)在MyAdapter中定义如下接口,模拟ListView的OnItemClickListener:

//define interfacepublic static interface OnRecyclerViewItemClickListener {void onItemClick(View view , String data);}

(2)声明一个这个接口的变量

private OnRecyclerViewItemClickListener mOnItemClickListener = null;

(3)在onCreateViewHolder()中为每个item添加点击事件

@Overridepublic ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);ViewHolder vh = new ViewHolder(view);//将创建的View注册点击事件view.setOnClickListener(this);return vh;}

(4)将点击事件转移给外面的调用者:

@Overridepublic void onClick(View v) {if (mOnItemClickListener != null) {//注意这里使用getTag方法获取数据 mOnItemClickListener.onItemClick(v,(String)v.getTag());}}

(5)注意上面调用接口的onItemClick()中的v.getTag()方法,这需要在onBindViewHolder()方法中设置和item相关的数据

@Overridepublic void onBindViewHolder(ViewHolder viewHolder, int position) {viewHolder.mTextView.setText(datas[position]);//将数据保存在itemView的Tag中,以便点击时进行获取 viewHolder.itemView.setTag(datas[position]);}

(6)最后暴露给外面的调用者,定义一个设置Listener的方法():

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

以上所有步骤都发生在自定义的adapter中,典型的观察者模式,有点绕的地方在于,这里涉及到两个观察者模式的使用,view的setOnClickListener本来就是观察者模式,我们将这个观察者模式的事件监听传递给了我们自己的观察者模式。

(7)接下来当然是在Activity中使用,如下:

1 mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view); 2 //创建默认的线性LayoutManager 3 mLayoutManager = new LinearLayoutManager(this); 4 mRecyclerView.setLayoutManager(mLayoutManager); 5 //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 6 mRecyclerView.setHasFixedSize(true); 7 //创建并设置Adapter 8 mAdapter = new MyAdapter(data); 9 mRecyclerView.setAdapter(mAdapter);10 mAdapter.setOnItemClickListener(new OnRecyclerViewItemClickListener(){11 @Override 12 public void onItemClick(View view , String data){13 Toast.makeText(MainActivity.this, data, 600).show();14 }15 });

5. 案例演示:(结合上面的步骤理解)

(1)使用Eclipse创建一个工程,如下:

同时注意API要使用API21

(2)首先我们来到主布局activity_main.xml,如下:

1 <RelativeLayout xmlns:android="/apk/res/android" 2xmlns:tools="/tools" 3android:layout_width="match_parent" 4android:layout_height="match_parent" > 5 6<android.support.v7.widget.RecyclerView 7 android:id="@+id/recyclerview" 8 android:layout_width="match_parent" 9 android:layout_height="match_parent"10/>11 12 </RelativeLayout>

(3)接下来,我们来到RecyclerView的item布局item.xml,如下:

1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="/apk/res/android" 3xmlns:tools="/tools" 4android:layout_width="match_parent" 5android:layout_height="50dip" > 6 7<TextView 8 android:id="@+id/text" 9 android:text="默认"10 android:layout_marginTop="5dp"11 android:gravity="center_horizontal"12 android:layout_width="match_parent"13 android:layout_height="wrap_content"14 android:textSize="20sp" 15 android:textColor="@android:color/holo_red_dark"/>16 17 </RelativeLayout>

(4)接下来我们自定义MyAdapter,如下:

1 package com.himi.recyclerviewdemo; 2 3 import android.support.v7.widget.RecyclerView; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.TextView; 8 9 public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> 10 implements View.OnClickListener {11 12private String[] datas;13 14public MyAdapter(String[] datas) {15 this.datas = datas;16 17}18 19 20/**21* 1.定义接口22*/23public static interface OnRecyclerViewItemClickListener {24 25 void onItemClick(View view, String data);26 27}28 29/**30* 3.在onCreateViewHolder()中为每个item添加点击事件31*/32@Override33public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {34 View view = LayoutInflater.from(viewGroup.getContext())35 .inflate(R.layout.item, viewGroup, false);36 37 ViewHolder vh = new ViewHolder(view);38 // 将创建的View注册点击事件39 view.setOnClickListener(this);40 41 return vh;42}4344/**45* 5.注意上面调用接口的onItemClick()中的v.getTag()方法,46* 这需要在onBindViewHolder()方法中设置和item相关的数据47*/48@Override49public void onBindViewHolder(ViewHolder viewHolder, int position) {50 51 viewHolder.mTextView.setText(datas[position]);52 53 // 将数据保存在itemView的Tag中,以便点击时进行获取54 viewHolder.itemView.setTag(datas[position]);55}56 57/**58* 4.将点击事件转移给外面的调用者59*/60public void onClick(View v) {61 if (mOnItemClickListener != null) {62 // 注意这里使用getTag方法获取数据63 mOnItemClickListener.onItemClick(v, (String) v.getTag());64 }65}66 67/**68* 2.声明一个这个接口的变量69*/70private OnRecyclerViewItemClickListener mOnItemClickListener = null;717273/**74*6.最后暴露给外面的调用者,定义一个设置Listener的方法()75*/7677public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {78 this.mOnItemClickListener = listener;79}808182 83// 获取数据的数量84@Override85public int getItemCount() {86 return datas.length;87}88 89// 自定义的ViewHolder,持有每个Item的的所有界面元素90public static class ViewHolder extends RecyclerView.ViewHolder {91 public TextView mTextView;92 93 public ViewHolder(View view) {94 super(view);95 mTextView = (TextView) view.findViewById(R.id.text);96 }97}98 99 }

(5)接下来来到MainActivity,如下:

1 package com.himi.recyclerviewdemo; 2 3 import com.himi.recyclerviewdemo.MyAdapter.OnRecyclerViewItemClickListener; 4 5 import android.app.Activity; 6 import android.os.Bundle; 7 import android.support.v7.widget.LinearLayoutManager; 8 import android.support.v7.widget.RecyclerView; 9 import android.view.View;10 import android.widget.Toast;11 12 public class MainActivity extends Activity {13 14private RecyclerView mRecyclerView;15private LinearLayoutManager mLayoutManager;16private MyAdapter mAdapter;17private String[] data = new String[] { 18 "刘德华", "周杰伦", "梁朝伟", "郭富城", "黎明", "张学友", 19 "成龙", "午马", "洪金宝", "林正英", "元彪", "林志颖", 20 "吴奇隆", "苏有朋", "赵薇", "陈坤", "周润发", "范冰冰", 21 "贾静雯", "周星驰" 22 };23 24@Override25protected void onCreate(Bundle savedInstanceState) {26 super.onCreate(savedInstanceState);27 setContentView(R.layout.activity_main);28 mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);29 30 // 创建默认的线性LayoutManager31 mLayoutManager = new LinearLayoutManager(this);32 mRecyclerView.setLayoutManager(mLayoutManager);33 34 // 如果可以确定每个item的高度是固定的,设置这个选项可以提高性能35 mRecyclerView.setHasFixedSize(true);36 37 //添加item间的分割线38 mRecyclerView.addItemDecoration(new RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL));39 40 // 创建并设置Adapter41 mAdapter = new MyAdapter(data);42 mRecyclerView.setAdapter(mAdapter);43 mAdapter.setOnItemClickListener(new OnRecyclerViewItemClickListener() {44 @Override45 public void onItemClick(View view, String data) {46 Toast.makeText(MainActivity.this, data, 1).show();47 }48 });49}50 51 }

这里使用到的自定义分割线类RecycleViewDivider是别人写的,我直接拿来用了,在此我表示感谢,如下:

1 package com.himi.recyclerviewdemo; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Canvas; 6 import android.graphics.Paint; 7 import android.graphics.Rect; 8 import android.graphics.drawable.Drawable; 9 import android.support.v4.content.ContextCompat; 10 import android.support.v7.widget.LinearLayoutManager; 11 import android.support.v7.widget.RecyclerView; 12 import android.support.v7.widget.RecyclerView.ItemDecoration; 13 import android.view.View; 14 15 public class RecycleViewDivider extends ItemDecoration { 16 private Paint mPaint; 17 private Drawable mDivider; 18 private int mDividerHeight = 2;//分割线高度,默认为1px 19 private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL 20 private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; 21 22 /** 23* 默认分割线:高度为2px,颜色为灰色 24* 25* @param context 26* @param orientation 列表方向 27*/ 28 public RecycleViewDivider(Context context, int orientation) { 29 if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { 30 throw new IllegalArgumentException("请输入正确的参数!"); 31 } 32 mOrientation = orientation; 33 34 final TypedArray a = context.obtainStyledAttributes(ATTRS); 35 mDivider = a.getDrawable(0); 36 a.recycle(); 37 } 38 39 /** 40* 自定义分割线 41* 42* @param context 43* @param orientation 列表方向 44* @param drawableId 分割线图片 45*/ 46 public RecycleViewDivider(Context context, int orientation, int drawableId) { 47 this(context, orientation); 48 mDivider = ContextCompat.getDrawable(context, drawableId); 49 mDividerHeight = mDivider.getIntrinsicHeight(); 50 } 51 52 /** 53* 自定义分割线 54* 55* @param context 56* @param orientation 列表方向 57* @param dividerHeight 分割线高度 58* @param dividerColor 分割线颜色 59*/ 60 public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) { 61 this(context, orientation); 62 mDividerHeight = dividerHeight; 63 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 64 mPaint.setColor(dividerColor); 65 mPaint.setStyle(Paint.Style.FILL); 66 } 67 68 69 //获取分割线尺寸 70 @Override 71 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 72 super.getItemOffsets(outRect, view, parent, state); 73 outRect.set(0, 0, 0, mDividerHeight); 74 } 75 76 //绘制分割线 77 @Override 78 public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 79 super.onDraw(c, parent, state); 80 if (mOrientation == LinearLayoutManager.VERTICAL) { 81 drawVertical(c, parent); 82 } else { 83 drawHorizontal(c, parent); 84 } 85 } 86 87 //绘制横向 item 分割线 88 private void drawHorizontal(Canvas canvas, RecyclerView parent) { 89 final int left = parent.getPaddingLeft(); 90 final int right = parent.getMeasuredWidth() - parent.getPaddingRight(); 91 final int childSize = parent.getChildCount(); 92 for (int i = 0; i < childSize; i++) { 93 final View child = parent.getChildAt(i); 94 RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); 95 final int top = child.getBottom() + layoutParams.bottomMargin; 96 final int bottom = top + mDividerHeight; 97 if (mDivider != null) { 98 mDivider.setBounds(left, top, right, bottom); 99 mDivider.draw(canvas);100 }101 if (mPaint != null) {102 canvas.drawRect(left, top, right, bottom, mPaint);103 }104 }105 }106 107 //绘制纵向 item 分割线108 private void drawVertical(Canvas canvas, RecyclerView parent) {109 final int top = parent.getPaddingTop();110 final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();111 final int childSize = parent.getChildCount();112 for (int i = 0; i < childSize; i++) {113 final View child = parent.getChildAt(i);114 RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();115 final int left = child.getRight() + layoutParams.rightMargin;116 final int right = left + mDividerHeight;117 if (mDivider != null) {118 mDivider.setBounds(left, top, right, bottom);119 mDivider.draw(canvas);120 }121 if (mPaint != null) {122 canvas.drawRect(left, top, right, bottom, mPaint);123 }124 }125 }126}

(6)部署程序到手机上,如下:

6. 总结:

在ListView中我们是调用ListView的setOnItemClickListener:

1 mListView.setOnItemClickListener(new OnItemClickListener() {2 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {3 4 ... 5 6 }7 });

而在我们这里是调用mAdapter的setOnItemClickListener。且回调方法public void onItemClick()的参数也不一致,ListView中有被点击item的position参数,而我们这里直接是被点击item的相关数据(这里只是一个字符串)。

如果觉得《Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。