Android_将RecyclerView打造成自己SwipeRecyclerView

来源:互联网 发布:FC HBA 端口 编辑:程序博客网 时间:2024/05/17 21:46

将RecyclerView打造成自己SwipeRecyclerView

一、概述
最近在项目中用到一个将ListView的Item进行左滑,然后点击删除的功能。在网上找了一些SwipeListView,看了下源码400多行,而且好多方法,感觉好复杂,于是自己动手参照着写了一个基于RecyclerView的SwipeRecyclerView。目前只实现了侧滑删除,后期准备加上头部,尾部以及其它效果。
控件的代码在Github上:

https://github.com/privatego/SwipeRecyclerView.git

欢迎大家评论和拍砖哈~~

二、关于RecyclerView
关于RecyclerView的基础知识,鸿洋大神在《Android RecyclerView 使用完全解析 体验艺术般的控件》中已经详细介绍过了,在这不重复介绍,直接进入实际操作
RecyclerView是在support-v7中,可以通过如下方法导入:

compile 'com.android.support:recyclerview-v7:24.0.0'

三、打造属于自己的SwipeRecyclerView控件
先看看最终的运行效果:
这里写图片描述

具体实现:
1.定义RecyclerView的Item样式

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="100dp"    android:background="@color/white"    android:id="@+id/ll_item"    >    <!-- 屏幕的正常宽度 -->    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <TextView            android:id="@+id/tv_item_content"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="item"            android:textSize="24dp"            />    </LinearLayout>    <!-- 屏幕右侧外边部分,正常时在屏幕中处于不可见 -->    <LinearLayout        android:id="@+id/ll_hidden"        android:layout_width="100dp"        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:textSize="24dp"            />    </LinearLayout></LinearLayout>

注意到第二个LinearLayout是处于屏幕右侧外边的,当Item向左滑动时,等于整个Item左移,这样就Item右侧显示,左侧会隐藏部分内容。
2.自定义SwipeRecyclerView,继承RecyclerView,重写其构造方法和onTouchEvent方法。

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 jingling on 16/6/29. */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                    MyRecycleAdapter.MyViewHolder viewHolder = (MyRecycleAdapter.MyViewHolder) getChildViewHolder(item);                    mCurItemLayout = viewHolder.mLlItem;                    //找到具体元素(这与实际业务相关了~~)                    mLlHidden = (LinearLayout)mCurItemLayout.findViewById(R.id.ll_hidden);                    mItemContent = (TextView)mCurItemLayout.findViewById(R.id.tv_item_content);                    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, "");                                getAdapter().notifyItemRemoved(curSelectPosition);                                getAdapter().notifyItemRangeChanged(curSelectPosition, getAdapter().getItemCount());                            }                        }                    });                    //这里将删除按钮的宽度设为可以移动的距离                    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{        boolean onRightClick(int position, String id);    }}

上述代码中,主要是重定onTouchEvent事件方法:
当手指按下时,计算出当前选中的是哪个Item,并获取到该Item对象;然后判断手指移动方向,若左移,则滑动(在滑动之前,先恢复上次的状态);若右移,则恢复;当左移完成之后,“删除”按钮自然就“暴露”在屏幕上可点击的范围了;然后就可以对Item进行删除操作了。
3.最后,在Activity中进行调用

private void initView() {        //设置布局管理器        LinearLayoutManager layoutManager = new LinearLayoutManager(this);        mRecycleView.setLayoutManager(layoutManager);        layoutManager.setOrientation(OrientationHelper.VERTICAL);        mRecycleView.setAdapter(mAdapter);        DividerItemDecoration dividerLine = new DividerItemDecoration(DividerItemDecoration.VERTICAL);        dividerLine.setSize(1);        dividerLine.setColor(0xffdddddd);        mRecycleView.addItemDecoration(dividerLine);        mRecycleView.setRightClickListener(new SwipeRecyclerView.OnRightClickListener() {            @Override            public void onRightClick(int position, String id) {                Toast.makeText(RecyclerViewActivity.this, " position = " + position , Toast.LENGTH_SHORT).show();                Log.e(TAG, " onRightClick position = " + position);            }        });    }
1 0
原创粉丝点击