RecyclerView学习(三)----高仿知乎的侧滑删除


转载地址:http://blog.csdn.net/tyk0910/article/details/51669205#rd


偶尔看到知乎首页的侧滑删除,感觉还不错。之前用RecyclerView的ItemTouchHelper类来实现了Item的拖动和删除功能,今天带来的则是纯手工打造的一个侧滑删除。老规矩,先看看效果图:

这里写图片描述

当滑动的距离小于红块的一半,松开手指以后,会自动收缩当前item;当滑动的距离超过一半,松开手指以后,会自动将当前item删除。一起看看怎么实现的吧:

1.准备工作: 
(1)数据准备:一个存放数字的List数组来模拟RecyclerView的数据 
(2)子Item的布局:整体线性布局水平排列,左侧是显示的部分,右侧是不显示的部分,也就是删除的部分。删除的部分是一个相对布局,然后通过滑动的距离来控制字体与图片的显示与隐藏。 
(3)RecyclerView三要素:RecyclerAdapter,RecyclerViewHolder,LayoutManager依次设置即可。

2.View的滑动实现: 
(1)滑动方法: 
这里我是使用View本身提供的scrollTo/scrollBy方法来实现滑动,scrollBy实际上也是调用了scrollTo方法,scrollTo实现的是基于所传递参数的绝对滑动,而scrollBy实现的是基于当前位置的相对滑动。

举个例子: 
scrollTo(50,50)会将View位置移动到指定位置,多次调用无效 
scrollBy(50,50)会将View位置移动到指定位置,每调用一次会在现有位置基础上进行移动 
结合这个例子分析一下,手指滑动的距离就是整体View移动的距离,那我们可以直接使用scrollBy(x,y)方法来进行处理,将手指滑动的距离作为第一个参数传递进去,而不用考虑当前View滑动的位置。

(2)滑动方向 
Android屏幕直角坐标系中,原点在屏幕左上角,向右X为正,向下Y为正。 
scrollBy()的参数的正负影响滑动的方向,这里我们只考虑水平方向上的滑动,所以将第二个参数设置为0。 
按我们正常的理解,应该是参数为负的时候,向坐标轴负方向滑动;当参数为正的时候,向坐标轴正方向滑动。 
scrollBy()在参数为负的时候,向坐标轴正方向滑动;当参数为正的时候,向坐标轴负方向滑动。 
这是因为在scrollBy()源码执行过程的最后,会调用这个方法 : 
invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 
其中l,t,r,b为原来坐标点,scrollX,scrollY为目标坐标点,只有当目标坐标点值是负数时,负负得正,移动到的位置才为正数,这样才会重新绘制,整体的View就会向坐标轴正方向滑动。

综上,我们想让子Item从右往左沿X轴的负方向滑动,scrollBy(X,0)中的X一定是大于0的

(3)滑动实现 
现在滑动的方法与方向都已经确定了,接下来的重点就是计算滑动的距离,也就是scrollBy(X,0)中的X的大小了。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">   <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> boolean <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>) {

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getX();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> y = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getY();

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">switch</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getAction()) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_DOWN: {
            }
             <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; 
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_MOVE: {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollX = itemLayout.getScrollX();
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> newScrollX = mStartX - x;
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (newScrollX < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && scrollX <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                        newScrollX = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
                    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (newScrollX > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && scrollX >= maxLength) {
                        newScrollX = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
                    }
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (scrollX > maxLength / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>) {
                        textView.setVisibility(GONE);
                        imageView.setVisibility(VISIBLE);

                       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isFirst) {
                            ObjectAnimator animatorX = ObjectAnimator.ofFloat(imageView, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"scaleX"</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.2</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f);
                            ObjectAnimator animatorY = ObjectAnimator.ofFloat(imageView, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"scaleY"</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.2</span>f, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>f);
                            AnimatorSet animSet = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AnimatorSet();
                            animSet.play(animatorX).with(animatorY);
                            animSet.setDuration(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">800</span>);
                            animSet.start();
                            isFirst = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>;
                        }



                    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                        textView.setVisibility(VISIBLE);
                        imageView.setVisibility(GONE);
                    }
                    itemLayout.scrollBy(newScrollX, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_UP: {

            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;
        mStartX = x;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> super.onTouchEvent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>);
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li></ul>

其中itemLayout为一个水平的LinearLayout,textView为LinearLayout中的”删除”,imageView为LinearLayout中的眼睛图片。

移动计算值 = 最开始点坐标 - 最后移动到的坐标

  1. 滑动开始的时候,不允许item向右滑动,此时scrollBy(x,0)中的x小于0;滑动的过程中,左右滑动都可以,但getScrollX()小于等于0的时候就不允许继续滑动。此时将x设置为0,代表不再滑动
  2. 滑动距离大于一半的时候,将文字设置为GONE,图片设置为VISIBLE,否则刚好相反。细心的小伙伴会发现,眼睛图片的显示有一个从小到大再到小的过程,这里用的是属性动画ObjectAnimator加上组合动画AnimatorSet实现的,并且进行了一下判断,让动画在滑动过程中只出现一次
  3. 滑动的距离超过红块的距离的时候,不允许item向左滑动,此时scrollBy(x,0)中的x是大于0。此时将x设置为0,代表不再滑动

3.RecyclerView的滑动实现

前面已经实现了将一个LinearLayout左右进行滑动,现在关键就是将这个LinearLayout的滑动与我们RecyclerView的滑动相结合。 
解决办法就是将这个水平排列的LinearLayout作为子item布局的一部分,然后再获取每一个item的LinearLayout就可以进行滑动了。这里肯定需要一个参数position,只有获取到item的position才能得到item的LinearLayout,才能进行删除操作。

(1)通过触碰的坐标计算当前的position 
这里我们肯定要自定义一个MyRecyclerView继承自RecyclerView,然后重写onTouchEvent()方法,在MotionEvent.ACTION_DOWN的时候就要拿到你触碰的item的position。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> boolean <span class="hljs-title" style="box-sizing: border-box;">onTouchEvent</span>(MotionEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>) {

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> x = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getX();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> y = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getY();

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">switch</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>.getAction()) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_DOWN: {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//通过点击的坐标计算当前的position</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> mFirstPosition = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
                Rect frame = mTouchFrame;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (frame == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                    mTouchFrame = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Rect();
                    frame = mTouchFrame;
                }
                final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> count = getChildCount();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = count - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i--) {
                    final View child = getChildAt(i);
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (child.getVisibility() == View.VISIBLE) {
                        child.getHitRect(frame);
                        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (frame.contains(x, y)) {
                            pos = mFirstPosition + i;
                        }
                    }
                }
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

在Listview当中,有一个pointToPosition(x, y)方法可以根据坐标获取到当前的position,在RecyclerView中没有这个方法,需要我们自己动手写一个。

这里有一点特别需要注意的是:这里遍历的是当前可见范围内的子项。使用getChildCount()与getChildAt()进行取值,只能是当前可见区域的子项!取值范围在0到getLastVisiblePosition()减去getFirstVisiblePosition()之间(可取等于)。

(2)通过position得到item的viewHolder

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">                //通过position得到item的viewHolder
                View view = getChildAt(pos - mFirstPosition)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
                MyViewHolder viewHolder = (MyViewHolder) getChildViewHolder(view)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
                itemLayout = viewHolder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layout</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
                textView = (TextView) itemLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.item</span>_delete_txt)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
                imageView = (ImageView) itemLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findViewById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.item</span>_delete_img)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

viewHolder是存放视图与数据的地方,只要拿到当前item的viewHolder,就可以获取到我们的itemLayout,也就是需要滑动的LinearLayout。RecyclerView提供了一个getChildViewHolder()的方法来获取当前item的viewHolder,传进去的参数就是通过getChildAt(index)获取到的view。

4.RecyclerView的删除实现

我们在上一步已经拿到了item的position与itemLayout,在MotionEvent.ACTION_MOVE的时候使用itemLayout就可以进行滑动,在MotionEvent.ACTION_UP的时候使用position就可以进行删除。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_UP: {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollX = itemLayout.getScrollX();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (scrollX > maxLength / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>) {
                    ((RecyclerAdapter) getAdapter()).removeRecycle(pos);
                }
            }
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

当滑动的距离大于一半的时候,执行删除操作。 将删除方法写在RecyclerAdapter中:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">removeRecycle</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> position) {
        lists.remove(position);
        notifyDataSetChanged();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (lists.size() == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
            Toast.makeText(context, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"已经没数据啦"</span>, Toast.LENGTH_SHORT).show();
        }
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

5.RecyclerView的滑动优化 
之前说到当滑动的距离小于红块的一半,松开手指以后,会自动收缩当前item,但是这个滑动比较生硬,用户体验很差。我们需要实现渐进式滑动,也就是View的弹性滑动。这里我们使用的是Scroller。

初始化Scroller:

<code class="hljs vhdl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
        mScroller = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Scroller(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">context</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinearInterpolator(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">context</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>));</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

第二个参数是一个匀速插值器

Scroller的使用方法:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MotionEvent.ACTION_UP: {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> scrollX = itemLayout.getScrollX();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (scrollX > maxLength / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>) {
                    ((RecyclerAdapter) getAdapter()).removeRecycle(pos);
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    mScroller.startScroll(scrollX, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, -scrollX, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
                    invalidate();
                }
            isFirst = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>;
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

startScroll()四个参数依次为:开始移动时的X坐标;开始移动时的Y坐标;沿X轴移动距离,为负时,子控件向右移动;沿Y轴移动距离。如果后面没有duration这个参数,系统会使用默认的时长:250毫秒 
然后调用invalidate()是使view进行重绘,在view的onDraw()方法中又会去调用computeScroll()方法,view才能实现弹性滑动

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">computeScroll</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mScroller.computeScrollOffset()) {
            itemLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

首先向Scroller获取当前的滑动起点,通过scrollTo方法实现滑动,然后再调用invalidate()来进行重绘,又会调用computeScroll()方法,然后再获取当前的起点,使用scrollTo方法滑动到新的位置。如此往复,直到整个滑动结束。其实Scroller的设计思想就是小幅度滑动组成整个的弹性滑动。

至此,一个漂亮的侧滑删除就已经实现了,零碎的东西不少,记录下来一起学习~~

源码地址


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值