`

下拉刷新相关

 
阅读更多

 

 

Android 在发布 Lollipop版本之后,为了更好的用户体验,Google为Android的滑动机制提供了NestedScrolling特性

NestedScrolling的特性可以体现在哪里呢?
比如你使用了Toolbar,下面一个ScrollView,向上滚动隐藏Toolbar,向下滚动显示Toolbar,这里在逻辑上就是一个NestedScrolling —— 因为你在滚动整个Toolbar在内的View的过程中,又嵌套滚动了里面的ScrollView

效果如上图【别嫌弃我】

在这之前,我们知道AndroidTouch事件的分发是有自己一套机制的。主要是有是三个函数:
dispatchTouchEventonInterceptTouchEventonTouchEvent

这种分发机制有一个漏洞:

如果子view获得处理touch事件机会的时候,父view就再也没有机会去处理这个touch事件了,直到下一次手指再按下。

也就是说,我们在滑动子View的时候,如果子View对这个滑动事件不想要处理的时候,只能抛弃这个touch事件,而不会把这些传给父view去处理。

但是Google新的NestedScrolling机制就很好的解决了这个问题。
我们看看如何实现这个NestedScrolling,首先有几个类(接口)我们需要关注一下

NestedScrollingChild
NestedScrollingParent
NestedScrollingChildHelper
NestedScrollingParentHelper

以上四个类都在support-v4包中提供,Lollipop的View默认实现了几种方法。
实现接口很简单,这边我暂时用到了NestedScrollingChild系列的方法(因为Parent是support-design提供的CoordinatorLayout

    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        super.setNestedScrollingEnabled(enabled);
        mChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return mChildHelper.startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll() {
        mChildHelper.stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        return mChildHelper.hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
    }

对,简单的话你就这么实现就好了。

这些接口都是我们在需要的时候自己调用的。childHelper干了些什么事呢?,看一下startNestedScroll方法

    /**
     * Start a new nested scroll for this view.
     *
     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
     * method/{@link NestedScrollingChild} interface method with the same signature to implement
     * the standard policy.</p>
     *
     * @param axes Supported nested scroll axes.
     *             See {@link NestedScrollingChild#startNestedScroll(int)}.
     * @return true if a cooperating parent view was found and nested scrolling started successfully
     */
    public boolean startNestedScroll(int axes) {
        if (hasNestedScrollingParent()) {
            // Already in progress
            return true;
        }
        if (isNestedScrollingEnabled()) {
            ViewParent p = mView.getParent();
            View child = mView;
            while (p != null) {
                if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {
                    mNestedScrollingParent = p;
                    ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);
                    return true;
                }
                if (p instanceof View) {
                    child = (View) p;
                }
                p = p.getParent();
            }
        }
        return false;
    }

可以看到这里是帮你实现一些跟NestedScrollingParent交互的一些方法。
ViewParentCompat是一个和父view交互的兼容类,它会判断api version,如果在Lollipop以上,就是用view自带的方法,否则判断是否实现了NestedScrollingParent接口,去调用接口的方法。

那么具体我们怎么使用这一套机制呢?比如子View这时候我需要通知父view告诉它我有一个嵌套的touch事件需要我们共同处理。那么针对一个只包含scroll交互,它整个工作流是这样的:

一、startNestedScroll

首先子view需要开启整个流程(内部主要是找到合适的能接受nestedScroll的parent),通知父View,我要和你配合处理TouchEvent

二、dispatchNestedPreScroll

在子View的onInterceptTouchEvent或者onTouch中(一般在MontionEvent.ACTION_MOVE事件里),调用该方法通知父View滑动的距离。该方法的第三第四个参数返回父view消费掉的scroll长度和子View的窗体偏移量。如果这个scroll没有被消费完,则子view进行处理剩下的一些距离,由于窗体进行了移动,如果你记录了手指最后的位置,需要根据第四个参数offsetInWindow计算偏移量,才能保证下一次的touch事件的计算是正确的。
如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。
这个函数一般在子view处理scroll前调用。

三、dispatchNestedScroll

向父view汇报滚动情况,包括子view消费的部分和子view没有消费的部分。
如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。
这个函数一般在子view处理scroll后调用。

四、stopNestedScroll

结束整个流程。

整个对应流程是这样

子view 父view
startNestedScroll onStartNestedScroll、onNestedScrollAccepted
dispatchNestedPreScroll onNestedPreScroll
dispatchNestedScroll onNestedScroll
stopNestedScroll onStopNestedScroll

一般是子view发起调用,父view接受回调。

我们最需要关注的是dispatchNestedPreScroll中的consumed参数。

    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) ;

它是一个int型的数组,长度为2,第一个元素是父view消费的x方向的滚动距离;第二个元素是父view消费的y方向的滚动距离,如果这两个值不为0,则子view需要对滚动的量进行一些修正。正因为有了这个参数,使得我们处理滚动事件的时候,思路更加清晰,不会像以前一样被一堆的滚动参数搞混。


对NestedScroll的介绍暂时到这里,下一次将讲一下CoordinatorLayout的使用(其中让人较难理解的Behavior对象),以及在SegmentFault Android客户端中的实践。谢谢支持。

分享到:
评论

相关推荐

    仿QQ下拉刷新

    【仿QQ下拉刷新】是一种常见的移动应用交互设计,它让用户在顶部下拉时触发页面内容的刷新。这种设计在QQ等社交应用中被广泛采用,后来成为了许多Android和iOS应用的标准特性。实现这一功能主要涉及到滚动视图、动画...

    Android 开源的下拉刷新 Eclipse版本

    在Eclipse中,开发者需要将提供的库导入到项目中,然后在需要下拉刷新功能的Activity或Fragment中引用相关组件。通过设置监听器和处理回调,开发者可以实现数据的刷新逻辑,如重新加载网络数据。 总的来说,这个...

    Activity实现下拉刷新

    这可能是项目中与下拉刷新相关的类或资源文件,比如自定义的下拉刷新组件,或者包含了处理刷新逻辑的代码。 综上所述,实现Activity的下拉刷新涉及多个步骤,包括集成SwipeRefreshLayout、设置监听器、处理数据...

    IOS下拉刷新Demo实现

    在iOS开发中,下拉刷新(Pull-to-Refresh)是一种常见的用户交互模式,它允许用户通过在列表顶部向下拉动来加载更多数据或更新现有数据。本教程将介绍如何使用EGOTableViewPullRefresh开源库在iOS应用中实现下拉刷新...

    ScrollView实现下拉刷新

    "ScrollView实现下拉刷新"这个主题聚焦于如何在滚动视图中添加一个下拉刷新功能,这通常用于列表或者网格视图,使得用户可以更新内容而无需离开当前页面。这种特性在许多应用程序中非常常见,比如社交媒体应用和新闻...

    仿网易下拉刷新

    在移动应用开发中,"仿网易下拉刷新"是一种常见的用户体验设计,主要用于更新内容或加载新数据。这种功能让用户能够通过简单的手势从顶部向下拉动列表,触发数据的刷新操作。通常,这种设计会伴随着动画效果,如加载...

    微信小程序scroll-view下拉刷新(附带下拉刷新效果)

    在本教程中,我们将探讨如何在`scroll-view`中实现下拉刷新(Pull-to-Refresh)功能,同时提供一个具体的效果展示。 首先,`scroll-view`是微信小程序提供的一个可滚动视图容器,它支持水平滚动和垂直滚动。通过...

    最简单的下拉刷新

    下拉刷新功能是移动应用和网页中常见的交互设计,它允许用户通过向下拉动内容区域来刷新数据。在Android开发中,实现下拉刷新通常需要对ListView或者RecyclerView进行扩展,但根据给定的描述,这里介绍的方法是相对...

    仿美团下拉刷新

    在移动应用开发中,"仿美团下拉刷新"是一个常见的功能设计,主要目的是提供一个用户友好的界面,让用户能够轻松地获取更新的数据。这个功能在美团、大众点评等生活服务类应用中广泛应用,增强了用户的交互体验。下面...

    下拉刷新的实现

    在移动应用开发中,"下拉刷新"是一个常见的功能,特别是在列表或滚动视图中,用户可以通过下拉屏幕顶部来获取最新的数据。这个功能让用户在不离开当前界面的情况下获取更新,提高了用户体验。本文将深入探讨如何实现...

    iScroll 5下拉刷新

    iScroll 5下拉刷新。 iScroll 5 更新之后的pull-to-refresh的demo没了,无奈,google下一个国外程序员写的上下拉刷新,自己精简了下,只保留了下拉刷新。

    微信小程序 下拉刷新,tab切换 (源码)

    微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab...

    移动端 下拉刷新 & 上拉加载 组件

    下拉刷新 上拉加载 上拉加载 底部点击加载 下拉刷新+上拉加载 下拉刷新+上拉加载 使用requirejs 下拉刷新+上拉加载 自定义dom 下拉刷新+上拉加载 固定头部 下拉刷新+上拉加载 tab一个实例 下拉刷新+上拉加载...

    自定义listview下拉刷新上拉加载更多以及与google官方的下拉刷新结合使用

    在Android开发中,ListView是常用的数据展示控件,但原生的ListView并不支持下拉刷新和上拉加载更多的功能。为了实现这些高级特性,开发者通常需要进行自定义或者使用第三方库。本教程将探讨如何自定义ListView实现...

    Android 之WebView实现下拉刷新和其他相关刷新功能

    有时候,为了提升用户体验,我们希望在WebView中实现下拉刷新的功能,就像原生的ListView或RecyclerView那样。本篇文章将深入探讨如何在Android的WebView中实现这一特性。 首先,下拉刷新是一种常见的用户界面设计...

    android开发WebView下拉刷新

    SwipeRefreshLayout和腾讯的X5内核的WebView相结合的下拉刷新,亲测华为荣耀android6.0 测试通过,由于百度某些页面单独处理过,开启了滚动条,否则下拉和下拉刷新冲突..2016年9月7日19:40:50

    Android自定义上拉加载下拉刷新控件

    在Android开发中,上拉加载和下拉刷新是常见的组件功能,用于提升用户体验,使得用户在滚动列表到顶部时能够方便地获取更多数据,而在滚动到底部时加载更多内容。本示例“Android自定义上拉加载下拉刷新控件”提供了...

    html5下拉刷新控件

    在提供的压缩包文件中,"scroll"可能是一个与下拉刷新相关的JavaScript文件,它可能包含了实现上述步骤的代码。"not.txt"可能是说明文档或其他不相关的文本文件。 总的来说,下拉刷新是提高用户体验的一种常见方式...

    一个快速和强大的前端下拉刷新

    在前端开发中,下拉刷新(Pull-to-Refresh)是一种常见的交互设计,用户可以通过在页面顶部或底部向下拉动来触发数据的更新。这种功能在移动应用和网页中广泛使用,特别是在内容流、列表或者时间线类的应用场景。"一...

Global site tag (gtag.js) - Google Analytics