项目中要实现的功能,之前找了很久发现网上大部分的侧滑删除和列表全选都是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中执行让滑动条滚动回到原位。
源码下载:
作者:qq_22770457 发表于2017/1/13 15:35:17 原文链接
阅读:72 评论:0 查看评论