SwipeRefreshLayout的事件处理

来源:互联网 发布:淘宝上的游侠9账号 编辑:程序博客网 时间:2024/05/23 23:09

本文并不是SwipeRefreshLayout全部事件处理的分析,而是针对一点进行详细的解析。具体是哪一点呢,不要着急,先听我说一个效果…
效果呢是这样:

  • 最早的下拉刷新大概是github上的一个pulltorefresh的一个库,这种库下拉效果是这样的:ListView向上滚动(手指向下滑动),当滚动到第一条的时候继续滚动的话是没有任何效果的,这时必须手抬起,重新按下然后向下滑动,下拉刷新的头部才会出现
  • SwipeRefreshLayout的效果是这样的,当滚动到第一条,手指不离开屏幕,继续向下滑动,这时下拉的头部就可以下拉出来了

有点绕,大家体会一下这个区别,不行自己拿demo跑一下看看。

可能看完上面的就有高手说话了,这还不简单,想和SwipeRefreshLayout一样的话直接在ListView的父布局中的onInterceptTouchEvent方法中判断ListView是否滚动到最上面不就完了吗。
道理是这么个道理,那就实际操作一下试试吧,自定义一个类SwipeRefreshLayout1,继承LinearLayout,复写onInterceptTouchEvent方法:

public class SwipeRefreshLayout1 extends LinearLayout {    public SwipeRefreshLayout1(Context context) {        super(context);    }    public SwipeRefreshLayout1(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        Log.e("lzw","onInterceptTouchEvent");        return super.onInterceptTouchEvent(ev);    }}

布局文件是这样写的,就是在上面的自定义的布局中放了一个ListView,好了,下面拖动一下ListView试试吧

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.pulltorefresh.pulltorefreshviews.SwipeRefreshActivity">    <com.pulltorefresh.pulltorefreshviews.SwipeRefreshLayout1        android:layout_width="match_parent"        android:layout_height="match_parent">        <com.pulltorefresh.pulltorefreshviews.ListView1            android:id="@+id/lv"            android:layout_width="match_parent"            android:layout_height="wrap_content"></com.pulltorefresh.pulltorefreshviews.ListView1>    </com.pulltorefresh.pulltorefreshviews.SwipeRefreshLayout1></RelativeLayout>

这是Log:,前面带---------的是ListView的onTouchEvent的Log。

08-17 02:54:38.621 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: onInterceptTouchEvent08-17 02:54:38.621 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: ---------onInterceptTouchEvent08-17 02:54:38.621 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent08-17 02:54:38.730 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: onInterceptTouchEvent08-17 02:54:38.730 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent08-17 02:54:38.741 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: onInterceptTouchEvent08-17 02:54:38.741 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent08-17 02:54:38.761 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: onInterceptTouchEvent08-17 02:54:38.761 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent08-17 02:54:38.800 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent08-17 02:54:38.810 1532-1532/com.pulltorefresh.pulltorefreshviews E/lzw: -------onTouchEvent

仔细看一下Log就会发现我擦嘞,怎么有问题啊,SwipeRefreshLayout1onInterceptTouchEvent方法怎么走了几次以后不走了啊,不按套路出牌啊,正常套路不应该是只要onInterceptTouchEvent不拦截(不返回true)事件会一直从onInterceptTouchEvent中走的啊(事件的分发可以参考我的事件分发的博客看一下),真是见了鬼了。

怎么样,是不是不实际操作不知道,实际写一下发现吓一跳呢,我当时到这之后简直要崩溃了,一时也没发现问题所在,酒吧问题搁置了。过了若干时间之后。。。具体是多久之后我也记不住了 = =,心里仍然很不爽啊,为啥SwipeRefreshLayout可以呢,为啥我写的就有问题呢,翻 源 码 ,就不信搞不定,皇天不负有心人,让我找到原因了。。。

在ListView的onTouchEvent方法中的MotionEvent.ACTION_MOVE中调用了onTouchMoveonTouchMove中又调用了startScrollIfNeededstartScrollIfNeeded中又有这么一段代码(真是九曲十八弯啊。。。):

final ViewParent parent = getParent();if (parent != null) {    parent.requestDisallowInterceptTouchEvent(true);}

你大爷的啊,调用了父类的requestDisallowInterceptTouchEvent方法不让父类拦截事件了,我们再去看看SwipeRefreshLayout人家这个方法做了点什么:

    @Override    public void requestDisallowInterceptTouchEvent(boolean b) {        // if this is a List < L or another view that doesn't support nested        // scrolling, ignore this request so that the vertical scroll event        // isn't stolen        if ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView)                || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget))) {            // Nope.        } else {            super.requestDisallowInterceptTouchEvent(b);        }    }

注释我都没给你去,各位程序猿们看看。mTarget是RecycleView中嵌套的View,对于ListView类型的子View,人家这个方法压根什么都没做,直接忽略了。另外还有一点简单说一下,版本小于21的才会忽略,那大于21的呢?21是5.0,对于5.0之后所有的View都有NestedScroll机制,压根就不用单独去考虑了。。。

到这问题的关键点就分析完了,把这段代码复制到SwipeRefreshLayout1中试一下,问题解决。我们就可以做到上面说的在onInterceptTouchEvent中判断事件是否需要被拦截了。

后面我们在用这个重新写一个简洁的DragTopLayout,不知道这个的童鞋可以单独去搜一下,git上有,但是写的比较复杂,也有一些很蛋疼的BUG

吐槽一下,从开始写到现在解决问题用了好久。。。

0 0
原创粉丝点击