• Android -- RecyclerView实现左滑删除


    1,在实际项目中我们常常有对一个列表进行滑删除操作,使用我们昨天的ItemTouchHelper其实也可以实现简单的实现这个功能,先来看一下使用ItemTouchHelper来实现的效果:

    2,从上面的效果图我们可以看到,大致的实现了我们的需求,具体操作如下

      第一步 :添加表示为START和END标识位

                @Override
                public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                    if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
                        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
                                ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                        final int swipeFlags = 0;
                        return makeMovementFlags(dragFlags, swipeFlags);
                    } else {
                        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    
                        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                        return makeMovementFlags(dragFlags, swipeFlags);
                    }
                }
    

      第二步 : 在侧滑过程中删除数据

                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                   int position = viewHolder.getAdapterPosition();
                   myAdapter.notifyItemRemoved(position);
                   datas.remove(position);
                }
    

      这样就很简单的实现了我们的操作

    3,但是上面实现方法有一个短板,就是用户有时候是不小心向左滑动,这样我们最好在滑动后添加一个确定操作的按钮,以确保用户不是手误滑动,这是我们要自定义RecyclerView重写OnTouchEvent方法来实现,先看一下实现的效果:

      来说一下整体的思路

      第一步:RecyclerView的item布局是由两部分组成,一是我们正常的item,还有一部分是我们还有删除按钮的布局文件,布局文件展示效果如下:

    代码如下:

    item_linear.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:orientation="horizontal"
                  android:id="@+id/ll_item"
        >
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="5dp"
                android:layout_weight="1"
                android:text="我是标题"
                android:textSize="16dp"/>
    
            <ImageView
                android:id="@+id/img"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp"
                android:layout_marginTop="5dp"
                android:src="@mipmap/ic_category_0"
                />
        </LinearLayout>
    
        <!-- 屏幕右侧外边部分,正常时在屏幕中处于不可见 -->
        <LinearLayout
            android:id="@+id/ll_hidden"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            android:background="#ff0000"
            android:gravity="center"
            >
    
            <TextView
                android:id="@+id/tv_item_delete"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="删除"
                android:textColor="#ffffff"
                android:textSize="16sp"
                />
        </LinearLayout>
    </LinearLayout>
    

      第二步:创建自定义的RecyclerView,重写onTouchEvent()方法,而重写OnTouchEvent()的大致思路是当用户手指按下时,计算出当前选中的是哪个Item,并获取到该Item对象;然后判断手指移动方向,若左移,则滑动(在滑动之前,先恢复上次的状态);若右移,则恢复;当左移完成之后,“删除”按钮自然就“暴露”在屏幕上可点击的范围了;然后就可以对Item进行删除操作了。 由于代码中的注释很详细了,就不再讲解了

      SwipRecyclerView.java

    package com.qianmo.dragrecyclerview;
    
    import android.content.Context;
    import android.graphics.Rect;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    import android.view.animation.LinearInterpolator;
    import android.widget.LinearLayout;
    import android.widget.Scroller;
    import android.widget.TextView;
    
    /**
     * Created by Administrator on 2017/3/14 0014.
     * E-Mail:543441727@qq.com
     */
    
    public class SwipeRecyclerView extends RecyclerView{
    
        private static final String TAG = "RecycleView";
        private int maxLength, mTouchSlop;
        private int xDown, yDown, xMove, yMove;
        /**
         * 当前选中的item索引(这个很重要)
         */
        private int curSelectPosition;
        private Scroller mScroller;
    
        private LinearLayout mCurItemLayout, mLastItemLayout;
        private LinearLayout mLlHidden;//隐藏部分
        private TextView mItemContent;
        private LinearLayout mItemDelete;
    
        /**
         * 隐藏部分长度
         */
        private int mHiddenWidth;
        /**
         * 记录连续移动的长度
         */
        private int mMoveWidth = 0;
        /**
         * 是否是第一次touch
         */
        private boolean isFirst = true;
        private Context mContext;
    
        /**
         * 删除的监听事件
         */
        private OnRightClickListener mRightListener;
    
        public void setRightClickListener(OnRightClickListener listener){
            this.mRightListener = listener;
        }
    
    
        public SwipeRecyclerView(Context context) {
            this(context, null);
        }
    
        public SwipeRecyclerView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SwipeRecyclerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mContext = context;
            //滑动到最小距离
            mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
            //滑动的最大距离
            maxLength = ((int) (180 * context.getResources().getDisplayMetrics().density + 0.5f));
            //初始化Scroller
            mScroller = new Scroller(context, new LinearInterpolator(context, null));
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            int x = (int)e.getX();
            int y = (int)e.getY();
            switch (e.getAction()){
                case MotionEvent.ACTION_DOWN:
                    //记录当前按下的坐标
                    xDown = x;
                    yDown = y;
                    //计算选中哪个Item
                    int firstPosition = ((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();
                    Rect itemRect = new Rect();
    
                    final int count = getChildCount();
                    for (int i=0; i<count; i++){
                        final View child = getChildAt(i);
                        if (child.getVisibility() == View.VISIBLE){
                            child.getHitRect(itemRect);
                            if (itemRect.contains(x, y)){
                                curSelectPosition = firstPosition + i;
                                break;
                            }
                        }
                    }
    
                    if (isFirst){//第一次时,不用重置上一次的Item
                        isFirst = false;
                    }else {
                        //屏幕再次接收到点击时,恢复上一次Item的状态
                        if (mLastItemLayout != null && mMoveWidth > 0) {
                            //将Item右移,恢复原位
                            scrollRight(mLastItemLayout, (0 - mMoveWidth));
                            //清空变量
                            mHiddenWidth = 0;
                            mMoveWidth = 0;
                        }
    
                    }
    
                    //取到当前选中的Item,赋给mCurItemLayout,以便对其进行左移
                    View item = getChildAt(curSelectPosition - firstPosition);
                    if (item != null) {
                        //获取当前选中的Item
                        MyAdapter.ViewHolder viewHolder = (MyAdapter.ViewHolder) getChildViewHolder(item);
                        mCurItemLayout = viewHolder.ll_item;
                        //找到具体元素(这与实际业务相关了~~)
                        mLlHidden = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
                        mItemDelete = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);
                        mItemDelete.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if (mRightListener != null){
                                    //删除
                                    mRightListener.onRightClick(curSelectPosition, "");
                                }
                            }
                        });
    
                        //这里将删除按钮的宽度设为可以移动的距离
                        mHiddenWidth = mLlHidden.getWidth();
                    }
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    xMove = x;
                    yMove = y;
                    int dx = xMove - xDown;//为负时:手指向左滑动;为正时:手指向右滑动。这与Android的屏幕坐标定义有关
                    int dy = yMove - yDown;//
    
                    //左滑
                    if (dx < 0 && Math.abs(dx) > mTouchSlop && Math.abs(dy) < mTouchSlop){
                        int newScrollX = Math.abs(dx);
                        if (mMoveWidth >= mHiddenWidth){//超过了,不能再移动了
                            newScrollX = 0;
                        } else if (mMoveWidth + newScrollX > mHiddenWidth){//这次要超了,
                            newScrollX = mHiddenWidth - mMoveWidth;
                        }
                        //左滑,每次滑动手指移动的距离
                        scrollLeft(mCurItemLayout, newScrollX);
                        //对移动的距离叠加
                        mMoveWidth = mMoveWidth + newScrollX;
                    }else if (dx > 0){//右滑
                        //执行右滑,这里没有做跟随,瞬间恢复
                        scrollRight(mCurItemLayout, 0 - mMoveWidth);
                        mMoveWidth = 0;
                    }
    
                    break;
                case MotionEvent.ACTION_UP://手抬起时
                    int scrollX = mCurItemLayout.getScrollX();
    
                    if (mHiddenWidth > mMoveWidth) {
                        int toX = (mHiddenWidth - mMoveWidth);
                        if (scrollX > mHiddenWidth / 2) {//超过一半长度时松开,则自动滑到左侧
                            scrollLeft(mCurItemLayout, toX);
                            mMoveWidth = mHiddenWidth;
                        } else {//不到一半时松开,则恢复原状
                            scrollRight(mCurItemLayout, 0 - mMoveWidth);
                            mMoveWidth = 0;
                        }
                    }
                    mLastItemLayout = mCurItemLayout;
                    break;
    
    
            }
            return super.onTouchEvent(e);
        }
    
    
        @Override
        public void computeScroll() {
            if (mScroller.computeScrollOffset()) {
    
                Log.e(TAG, "computeScroll getCurrX ->" + mScroller.getCurrX());
                mCurItemLayout.scrollBy(mScroller.getCurrX(), 0);
                invalidate();
            }
        }
    
        /**
         * 向左滑动
         */
        private void scrollLeft(View item, int scorllX){
            Log.e(TAG, " scroll left -> " + scorllX);
            item.scrollBy(scorllX, 0);
        }
    
        /**
         * 向右滑动
         */
        private void scrollRight(View item, int scorllX){
            Log.e(TAG, " scroll right -> " + scorllX);
            item.scrollBy(scorllX, 0);
        }
    
        public interface OnRightClickListener{
            void onRightClick(int position, String id);
        }
    }
    

      这样我们就实现了给RecyclerView添加左滑删除了 ,这是GitHub下载链接  See You Next Time !

  • 相关阅读:
    积少成多Flash(8) ActionScript 3.0 网页之获取参数,JavaScript与ActionScript之间的相互调用
    积少成多Flash(11) Flex 3.0 动画效果(effect)
    积少成多Flash(9) Flex 3.0 布局控件, 样式(css), 皮肤(skin)
    系出名门Android(8) 控件(View)之TextSwitcher, Gallery, ImageSwitcher, GridView, ListView, ExpandableList
    系出名门Android(9) 数据库支持(SQLite), 内容提供器(ContentProvider)
    积少成多 Flash(ActionScript 3.0 & Flex 3.0) 系列文章索引
    系出名门Android(5) 控件(View)之TextView, Button, ImageButton, ImageView, CheckBox, RadioButton, AnalogClock, DigitalClock
    系出名门Android(1) 在 Windows 下搭建 Android 开发环境,以及 Hello World 程序
    小程序webview组件 nothing
    Python3的bytes/str之别
  • 原文地址:https://www.cnblogs.com/wjtaigwh/p/6548197.html
Copyright © 2020-2023  润新知