基于SwipeRefreshLayout实现类QQ的侧滑删除

前言

记得去年做一个聊天项目需要实现类似QQ的下拉刷新并且有侧滑删除的功能,在网上找了很久都没有QQ的完美,多多少少存在各种的问题,最后把下拉刷新的功能去掉后,只保留了侧滑删除的功能才找到个完美的。回去后和一朋友讨论,朋友找了以后说了一句,这种功能没有8K以上的是写不出来的(⊙﹏⊙)b。现在看来当时真的太天真了。而如今自己也没有8K还是尝试去写写,顺便当练练手。

还是效果图优先

2017-10-30_11_28_34 00_00_00-00_00_18.gif

效果图当中看不出来事件滑动的解决方案(或者是我不会如何录制手指在屏幕上滑动方向和点击,知道的大神请告诉下,谢谢)具体的可以去下方的GitHub上下载看。

还是先看怎么用

首先传送门地址SwipeMenuRefreshView
此项目中引用了一个侧滑菜单的库具体的地址AndroidSwipeLayout(这是一个非常强大的库可以上下左右的滑动展示,具体可以去其GitHub上了解)

  • 引用(现在改为jitpack引用之前jcenter引用有问题感谢 一Zhi优雅的猪 实在抱歉各位老铁55555)
allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

dependencies {
            compile 'com.github.xypmhxy.SwipeMenueRefreshView:SwipeMenuRefreshView:v1.1'
    }
  • 布局文件
 <ren.widget.refresh.SwipeMenuRefreshView
        android:id="@+id/refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" />
    </ren.widget.refresh.SwipeMenuRefreshView>
  • Item布局文件
<com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    app:clickToClose="true">

    //侧滑出来的布局
    <LinearLayout
        android:id="@+id/bottom_wrapper_2"
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:tag="Bottom4">

        <TextView
            android:id="@+id/top"
            android:layout_width="70dp"
            android:layout_height="match_parent"
            android:background="#cfcfcf"
            android:gravity="center"
            android:text="置顶" />

        <TextView
            android:id="@+id/noread"
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:background="#ffa500"
            android:gravity="center"
            android:text="标记未读" />

        <TextView
            android:id="@+id/delete"
            android:layout_width="70dp"
            android:layout_height="match_parent"
            android:background="#FF0000"
            android:gravity="center"
            android:text="删除" />
    </LinearLayout>

    //默认展示的布局
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="80dp">

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:text="aaaaa"
            android:textSize="18sp" />
    </RelativeLayout>

</com.daimajia.swipe.SwipeLayout>

具体实现

    1. 实现思路
      思路其实也很简单就是在实现自定义SwipeRefreshLayout重写onInterceptTouchEvent根据左右还是上下滑动进行事件的拦截和下发
    1. 判断滑动方向
      主要根据用户滑动的夹角来判断是上下滑动还是左右滑动。判断后设置一个标记,下一次滑动的时候如果上下滑动(Listiview)的滑动那么就调用父类的的onInterceptTouchEvent方法正常滑动,此时事件在到达侧滑菜单的时候已经被消费了所有不会滑出侧滑菜单。如果是左右滑动则return false 不拦截事件交由子控件处理,这是左右滑动Listview是不会做消费所以会到达让侧滑菜单来处理。
      case MotionEvent.ACTION_DOWN:
                pressX = (int) ev.getX(); //记录按下的X坐标
                pressY = (int) ev.getY();//记录按下的Y坐标
                break;
     case MotionEvent.ACTION_MOVE:
                //判断滑动距离是否是正常的滑动
                if (Math.abs(ev.getY() - pressY) < touchSlop && Math.abs(ev.getX() - pressX) < touchSlop)
                    return super.onInterceptTouchEvent(ev);
                //如果用户是滑动listview则交由父类onInterceptTouchEvent处理
                if (interceptStatus == REFRESH_STATUS)
                    return super.onInterceptTouchEvent(ev);
                    //用户如果是滑出SwipeLayout则不拦截时间交由SwipeLayout处理
                else if (interceptStatus == SWIPE_MENU_OPEN)
                    return false;
                //根据滑动角度判断用户是滑出SwipeLayout还是Listview
                double angle = Math.atan((ev.getY() - pressY) / (ev.getX() - pressX));//计算滑动的角度
                int degrees = (int) Math.toDegrees(angle);
                degrees = Math.abs(degrees);
                //大于45度则判断为Listview滑动
                if (degrees > 45) {
                    Log.d(TAG, "正在上下滑动");
                    //如果当前是SwipeLayout内点击的事件序列则不允许滑动
                    if (interceptStatus == SWIPE_MENU_CLOSE)
                        return true;
                    interceptStatus = REFRESH_STATUS; //标记为Listview滑动
                    return super.onInterceptTouchEvent(ev);
                } else { //小于45度则判断为SwipeLayout滑动
                    Log.e(TAG, "正在左右滑动");
                    currentSwipeLayout = getCurrentSwipeLayout(); //获取当前滑出的SwipeLayout
                    interceptStatus = SWIPE_MENU_OPEN; //标记为SwipeLayout滑动
                    return false;
                }
  • 3点击事件处理
    点击事件分为几种情况
    1.用户普通的item点击:此情况下不做任何处理
    2.当滑出侧滑菜单栏以后,点击其他的item时,这是判断是否是当前滑出的侧滑菜单的position如若不是在down事件的时候变将其关闭并且 return true当在onInterceptTouchEvent中retur true 后此后所有的事件,直到手指抬起时的所有操作都交由自身的onTouchEvent处理而在onTouchEvent中也不做任何操作直接拦截即可达到需要的效果
        判断是否是点击的当前滑出菜单的Item
       if (currentSwipeLayout != null && currentSwipeLayout.getOpenStatus() != SwipeLayout.Status.Close) { //如果当前有打开或者正在打开的SwipeLayout
                    Log.d(TAG, "currentSwipeLayout.getOpenStatus() " + currentSwipeLayout.getOpenStatus());
                    interceptStatus = SWIPE_MENU_CLOSE;//此次用户操作为关闭SwipeLayout
                    Rect rect = new Rect();
                    currentSwipeLayout.getHitRect(rect);
                    //判断当前点击X Y坐标是否在当前SwipeLayout中,即用户是否点击这个SwipeLayout,有就不拦截时间交由SwipeLayout自己处理
                    if (rect.contains(pressX, pressY)) {
                        return false;
                    }       

        onInterceptTouchEvent中down事件
         case MotionEvent.ACTION_DOWN:
                     //如果没有就关闭并且拦截此时间顺序中所有事件
                    currentSwipeLayout.close();
                    return true;

         onTouchEvent中的move事件
         case MotionEvent.ACTION_MOVE:
                if (interceptStatus == SWIPE_MENU_CLOSE)//如果是SwipeLayout关闭事件序列则拦截事件
                    return true;

3.当用户点击的是当前侧滑菜单,这里又有两种情况如果点击的范围不是侧滑菜单的范围则return false这时如果抬手时是在侧滑菜单的范围内将会触发点击事件(如果有)如果没有在此范围则关闭侧滑菜单。如果此期间有move事件即用户有滑动会进入之前说的move判断逻辑。
简而言之就是按下的范围是滑出侧滑菜单的Item则不拦截交由儿子你说了算,如果有滑动就由父类进行开始说的判断,然后进行相应逻辑,此时就不是儿子说了算。

  //判断当前点击X Y坐标是否在当前SwipeLayout中,即用户是否点击这个SwipeLayout,有就不拦截时间交由SwipeLayout自己处理
                    if (rect.contains(pressX, pressY)) {
                        return false;
                    }
                    //如果没有就关闭并且拦截此时间顺序中所有事件
                    currentSwipeLayout.close();
                    return true;

结语

此文设计事件分发的许多知识,加上这几个控件都有自己的方法所有有许多内容不太容易说的清楚(甚至自己都不一定弄的很清楚)加之本人表达能力不算好,所以可能云里雾里的,如果有兴趣的朋友们可以去GitHub下载源码看看。最后在给一次地址SwipeMenuRefreshView

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,442评论 25 707
  • 最近PM2.5对侧滑菜单比较感兴趣,很多页面上都用到了侧滑菜单,之前也在网上看到了很多关于侧滑,有自定义Recyc...
    wustor阅读 932评论 0 1
  • 我的开源库:一句代码搞定 RecycleView 侧滑菜单、添加头部底部、加载更多 本文已授权微信公众号:鸿洋(h...
    王英豪阅读 2,634评论 0 41
  • 颜倾城 才冠天下 抵不过 岁月一纸流沙 黑衣盛装及腰长发 只为隐藏灵魂伤疤 我所求的也仅仅只是你开心快乐啊 又何苦...
    寒江梅阅读 219评论 0 3
  • 早晨睡眼朦胧间,雨就来了,很准时,遵从了天气预报的指示。这次它来得没有以往那么匆匆忙忙,有的只是循序渐进。开始时雨...
    一浅疏影阅读 510评论 3 38