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); } }); }
- Android_将RecyclerView打造成自己SwipeRecyclerView
- 将自己的vim打造成IDE
- Android-->如何将RecyclerView打造成ViewPager的效果
- SwipeRecyclerView
- 将VisualStudio打造成Vim
- 将vim打造成IDE
- 谷歌如何将自己打造成最佳雇主:幸福靠算计
- 将vim打造成IDE编译环境——自己用的vim(gvim)插件
- 将RecyclerView打jar包
- 将iPhone打造成数码单反相机
- 将笔记本打造成无线路由
- 将vim打造成IDE编程环境
- 将gvim打造成txt编辑利器
- 将小米盒子打造成开发环境
- 将VIM打造成一个IDE
- 将VIM打造成强大的IDE
- 将centos7打造成桌面系统
- 将gedit打造成简单的IDE
- poj 1840 哈希+离散化
- Codeforces Round #361 (Div. 2) -- A. Mike and Cellphone (思路题目)
- 经常逛的网站,持续更新
- 解决Mac AndroidStudio无法关联源码问题
- 关于Fragment的一点小技巧
- Android_将RecyclerView打造成自己SwipeRecyclerView
- Android中线程同步之Mutex与Condtion的用法
- 教你快速掌握androidstudio使用git上传本地项目到github、版本控制
- 正则表达式学习笔记(一)全部符号解释
- 画折线
- springMVC理解
- LeetCode—Construct BinaryTree By InOrder and PostOrder
- 在源文件中没有找到用 /Ycstdafx.h 命令行选项指定的“#include”语句
- 解决Mac Androidstudio无法关联源码问题