Android——实现RecyclerView左侧滑删除与右侧滑选择
Posted 化作孤岛的瓜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——实现RecyclerView左侧滑删除与右侧滑选择相关的知识,希望对你有一定的参考价值。
项目中要实现的功能,之前找了很久发现网上大部分的侧滑删除和列表全选都是ListView的实现,而对RecyclerView的实现却是少之又少,所以花了很多时间实现了一个还比较满意的版本,
效果如下:
侧滑删除(带自动校位滑动效果):
右滑出现选择框:
一键编辑(全选):
实现原理:
1.首先需要实现一个基本的RecyclerView。
2. 自定义Item的布局。
3.结合自定义item布局通过自定义Item项实现左右滑效果。
代码实现:
1.首先是实现RecyclerView的基本用法,这里我们先要实现item的布局:layout_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.ng.ngrecyclerview.view.SlidingButtonView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="1dp"
android:background="@android:color/white">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_delete"
android:layout_width="80dp"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/layout_content"
android:background="@drawable/btn_click_red_havebackground"
android:gravity="center"
android:text="删 除"
android:textColor="#DDFFFFFF" />
<LinearLayout
android:id="@+id/layout_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0280ff"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rl_left"
android:layout_width="50dp"
android:layout_height="match_parent">
<RadioButton
android:id="@+id/rbtn"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/btn_click_black_havebackground"
android:gravity="center"
android:textColor="#DD000000"
android:textSize="50dp" />
</LinearLayout>
</RelativeLayout>
</com.ng.ngrecyclerview.view.SlidingButtonView>
布局预览:
注意:因为逻辑问题所以可以这样划分:id为rl_left的RelativeLayout为左侧想自定义的布局,可以直接在这个RelativeLayout里修改,id为text的TextView为中部部分布局,可以替换为其他Viewgroup并自定义。
删除布局是id为tv_delete的TextView,也可以随意自定义替换。
2.Adapter实现:
public class MyAdapter extends RecyclerView.Adapter implements SlidingButtonView.IonSlidingButtonListener
Context context;
private IonSlidingViewClickListener mIDeleteBtnClickListener;
private List<String> mDatas = new ArrayList<String>();
private SlidingButtonView mMenu = null;
public MyAdapter(Context context, ArrayList<String> date)
this.context = context;
this.mDatas = date;
mIDeleteBtnClickListener = (IonSlidingViewClickListener) context;
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View view = LayoutInflater.from(context).inflate(R.layout.layout_item, parent, false);
return new MyViewHolder(view);
boolean allopen = false;
public void setAllopen(boolean allopen)
this.allopen = allopen;
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position)
final MyViewHolder viewHolder = (MyViewHolder) holder;
viewHolder.slidingButtonView.setSlidingButtonListener(MyAdapter.this);
viewHolder.textView.setText(mDatas.get(position));
//设置内容布局的宽为屏幕宽度
viewHolder.layout_content.getLayoutParams().width = Utils.getScreenWidth(context) + viewHolder.rl_left.getLayoutParams().width;
// viewHolder.textView.setOnClickListener(new View.OnClickListener()
// @Override
// public void onClick(View v)
// //判断是否有删除菜单打开
if (menuIsOpen())
closeMenu();//关闭菜单
else
int n = viewHolder.getLayoutPosition();
mIDeleteBtnClickListener.onItemClick(v, n);
//
//
// );
viewHolder.btn_Delete.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
int n = holder.getLayoutPosition();
mIDeleteBtnClickListener.onDeleteBtnCilck(v, n);
);
LogUtils.d("项:" + position + "是否开:" + allopen);
if (allopen)
LogUtils.d("打开?");
viewHolder.slidingButtonView.openMenu();
viewHolder.slidingButtonView.setCanTouch(false);
else
viewHolder.slidingButtonView.closeMenu();
viewHolder.slidingButtonView.setCanTouch(true);
@Override
public int getItemCount()
return mDatas.size();
/**
* 删除菜单打开信息接收
*/
@Override
public void onMenuIsOpen(View view)
mMenu = (SlidingButtonView) view;
/**
* 滑动或者点击了Item监听
*
* @param slidingButtonView
*/
@Override
public void onDownOrMove(SlidingButtonView slidingButtonView)
if (menuIsOpen())
if (mMenu != slidingButtonView)
closeMenu();
/**
* 关闭菜单
*/
public void closeMenu()
mMenu.closeMenu();
mMenu = null;
/**
* 判断是否有菜单打开
*/
public Boolean menuIsOpen()
if (mMenu != null)
return true;
return false;
public interface IonSlidingViewClickListener
void onItemClick(View view, int position);
void onDeleteBtnCilck(View view, int position);
public void addData(int position)
mDatas.add(position, "添加项");
notifyItemInserted(position);
public void removeData(int position)
mDatas.remove(position);
notifyItemRemoved(position);
这里没有太多要说的,主要就是一个判断是否打开左侧编辑菜单的标识符boolean值allopen的判定方法,其他都为基础的RecyclerView的Adapter使用方法。
在Activity中的使用也是基础的方法,这里不提,后面源码下载可以看到。
3.Item侧滑效果实现类SlidingButtonView:
public class SlidingButtonView extends HorizontalScrollView
//删除按钮
private TextView mTextView_Delete;
//左侧控件
private RadioButton rbtn;
private TextView text;
private int leftWidth;
//记录滚动条滚动的距离
private int mScrollWidth;
public int getLeftWidth()
return leftWidth;
//自定义的接口,用于传达滑动事件
private IonSlidingButtonListener mIonSlidingButtonListener;
//记录按钮菜单是否打开,默认关闭false
private Boolean isOpen = false;
public Boolean getOpen()
return isOpen;
public void setOpen(Boolean open)
isOpen = open;
//在onMeasure中只执行一次的判断
private Boolean once = false;
public SlidingButtonView(Context context)
this(context, null);
public SlidingButtonView(Context context, AttributeSet attrs)
this(context, attrs, 0);
public SlidingButtonView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this.setOverScrollMode(OVER_SCROLL_NEVER);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!once)
//只需要执行一次
mTextView_Delete = (TextView) findViewById(R.id.tv_delete);
rbtn = (RadioButton) findViewById(R.id.rbtn);
text = (TextView) findViewById(R.id.text);
once = true;
//使Item在每次变更布局大小时回到初始位置,并且获取滚动条的可移动距离
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
super.onLayout(changed, l, t, r, b);
if (changed)
//获取水平滚动条可以滑动的范围,即右侧按钮的宽度
mScrollWidth = mTextView_Delete.getWidth();
leftWidth = rbtn.getWidth();
this.scrollTo(leftWidth, 0);
// LogUtils.d("可以滑动的范围:" + mScrollWidth);
private boolean canTouch = true;
public boolean isCanTouch()
return canTouch;
public void setCanTouch(boolean canTouch)
this.canTouch = canTouch;
@Override
public boolean onTouchEvent(MotionEvent ev)
if (!canTouch)
return true;
int action = ev.getAction();
switch (action)
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
mIonSlidingButtonListener.onDownOrMove(this);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
changeScrollx();
return true;
default:
break;
return super.onTouchEvent(ev);
//滚动监听,为了让删除按钮显示在项的背后的效果
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt)
super.onScrollChanged(l, t, oldl, oldt);
// mTextView_Delete.setTranslationX(l - mScrollWidth -100);
// mTextView_Delete.setTranslationX(l - mScrollWidth );
//this.setX(l);
public void changeScrollx()
// LogUtils.d("getScrollX(): " + getScrollX());
// LogUtils.d("mScrollWidth: " + mScrollWidth);
// LogUtils.d("leftWidth: " + leftWidth);
if (getScrollX()-leftWidth >= (mScrollWidth / 2))
this.smoothScrollTo(mScrollWidth + leftWidth, 0);
isOpen = true;
mIonSlidingButtonListener.onMenuIsOpen(this);
else
this.smoothScrollTo(leftWidth, 0);
isOpen = false;
Handler scrollHandler = new Handler()
@Override
public void handleMessage(Message msg)
if (msg.what==2)
SlidingButtonView.this.smoothScrollTo(leftWidth,0);
else if (msg.what==1)
SlidingButtonView.this.smoothScrollTo(0,0);
;
public void openMenu()
// if (isOpen)
// return;
//
Message msg = new Message();
msg.what= 1;
scrollHandler.sendMessage(msg);
isOpen = true;
mIonSlidingButtonListener.onMenuIsOpen(this);
public void closeMenu()
if (!isOpen)
return;
Message msg = new Message();
msg.what= 2;
scrollHandler.sendMessage(msg);
isOpen = false;
public void setSlidingButtonListener(IonSlidingButtonListener listener)
mIonSlidingButtonListener = listener;
public interface IonSlidingButtonListener
void onMenuIsOpen(View view);
void onDownOrMove(SlidingButtonView slidingButtonView);
这个类是重点所在,我们按方法来一个一个讲:
onMeasure:
进行布局的初始化操作。
onLayout:
获取水平滚动条可以滑动的范围,即右侧按钮的宽度。
滑动到初始范围。
setCanTouch:
设置是否响应触摸事件。
onTouchEvent:
点击事件判断,在移动事件:MotionEvent.ACTION_MOVE中执行拖动条的滑动。
在事件取消:MotionEvent.ACTION_CANCEL中执行让滑动条滚动回到原位。
源码下载:
以上是关于Android——实现RecyclerView左侧滑删除与右侧滑选择的主要内容,如果未能解决你的问题,请参考以下文章
Android 使用HorizontalScrollView实现RecyclerView左滑删除的功能