`
gg163
  • 浏览: 6946 次
文章分类
社区版块
存档分类
最新评论

浅析:Android 嵌套滑动机制(NestedScrolling)

阅读更多

谷歌在发布安卓 Lollipop版本之后,为了更好的用户体验,GoogleAndroid的滑动机制提供了NestedScrolling特性

NestedScrolling的特性可以体现在哪里呢?
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

比如你使用了Toolbar,下面一个ScrollView,向上滚动隐藏Toolbar,向下滚动显示Toolbar,这里在逻辑上就是一个NestedScrolling —— 因为你在滚动整个Toolbar在内的View的过程中,又嵌套滚动了里面的ScrollView
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

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

dispatchTouchEventonInterceptTouchEventonTouchEvent

 

这种分发机制让移动应用安全检测平台-爱内测(ineice.com)发现有一个漏洞,据爱内测的CTO介绍:

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

 

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

 

但是Google新的NestedScrolling机制就很好的解决了这个问题。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

我们看看如何实现这个NestedScrolling,首先有几个类(接口)我们需要关注一下

NestedScrollingChild

NestedScrollingParent

NestedScrollingChildHelper

NestedScrollingParentHelper

以上四个类都在support-v4包中提供,LollipopView默认实现了几种方法。

 

实现接口很简单,这边我暂时用到了NestedScrollingChild系列的方法(因为Parentsupport-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需要开启整个流程(内部主要是找到合适的能接受nestedScrollparent),通知父View,我要和你配合处理TouchEvent

 

二、dispatchNestedPreScroll

在子ViewonInterceptTouchEvent或者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后调用。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

四、stopNestedScroll

结束整个流程。

整个对应流程是这样

view   view

startNestedScroll onStartNestedScrollonNestedScrollAccepted

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需要对滚动的量进行一些修正。正因为有了这个参数,使得我们处理滚动事件的时候,思路更加清晰,不会像以前一样被一堆的滚动参数搞混。

1
0
分享到:
评论

相关推荐

    浅析Android手机传感器机制及应用设计举例.pdf

    《浅析Android手机传感器机制及应用设计举例》这篇文章主要探讨了Android智能手机中传感器的工作机制以及如何利用这些传感器进行应用设计。Android系统为开发者提供了丰富的传感器接口,使得开发者能够充分利用手机...

    2020年第二季度上海房地产市场浅析:行情全面复苏,市场依然理性.zip

    2020年第二季度上海房地产市场浅析:行情全面复苏,市场依然理性

    浅析:图像修复中的TV模型(附件包)

    标题中的“浅析:图像修复中的TV模型”指的是在图像处理领域中,使用Total Variation (TV) 模型进行图像修复的技术。TV模型是一种优化方法,常用于图像去噪、图像恢复和图像重建等问题,其核心思想是尽可能保持图像...

    浅析Wakelock机制与Android电源管理.pdf

    浅析Wakelock机制与Android电源管理.pdf 摘要: 本文浅析了Android电源管理机制,特别是Wakelock机制在Android电源管理中的应用。Android电源管理是Android操作系统中的一项重要功能,旨在有效地管理电源,延长设备...

    浅析Wakelock机制与Android电源管理

    浅析Wakelock机制与Android电源管理 Android电源管理是移动设备中非常重要的一方面,在Android系统中,Wakelock机制是电源管理的核心机制之一。Wakelock机制是Android系统中的一个重要组件,用于管理Android设备的...

    武汉大学2011年计算机考研复试线浅析:

    武汉大学 2011 复试线浅析(计算机)

    Android框架浅析之锁屏(Keyguard)机制原理

    ### Android框架浅析之锁屏(Keyguard)机制原理 #### 一、锁屏界面的组成 锁屏(Keyguard)是Android系统中的一个重要组成部分,它主要用于保护用户的隐私数据不被未授权访问。锁屏功能主要由两个部分组成:解锁...

    深入浅析Android消息机制

    在Android系统中,消息机制是实现线程间通信的关键组件,尤其对于UI线程与工作线程之间的交互至关重要。本文将深入探讨Android消息机制的核心组件:Handler、Looper和MessageQueue,以及它们如何协同工作。 首先,`...

    Android平台安全机制浅析.pdf

    在信息技术行业中,Android作为全球最受欢迎的智能手机操作系统平台之一,其安全机制是一个热门且重要的研究领域。从文中给出的信息来看,Android平台的安全机制可以从其系统架构出发进行分析,主要涉及Linux机制、...

    2021-2022收藏资料浅析:印刷技术未来发展的七大趋势预测.doc

    2021年09月16日

    Android防止内存溢出浅析.zip

    - **垃圾回收(GC)**:Android系统有自动垃圾回收机制,用于回收不再使用的对象,释放内存。 2. **内存溢出原因** - **大对象**:占用大量内存的大对象可能导致内存不足,例如大尺寸的位图图像。 - **内存泄漏*...

    2021-2022年收藏的精品资料浅析:国内模具产业发展资源整合五大途径.doc

    精品教育教学资料

    HTML5缓存机制浅析:移动端Web加载性能优化

    摘要:本文作者,腾讯游戏平台与社区产品部安卓开发组高级工程师贺辉超详细分析了各种缓存机制的原理、用法及特点,并针对Android移动端Web性能加载优化的需求,帮助开发者选择如何利用适当缓存机制来提高Web的加载...

    Android后台监听实现机制浅析

    根据给定文件的信息,本文将重点探讨Android后台监听的实现机制以及如何利用这些机制来加强Android平台的安全性。首先,我们需要了解Android系统的基本结构和特点,随后深入剖析后台监听的关键技术,包括`...

    Android代码-各种实例库

    示例索引 博客:NDK-JNI实战教程(三) 从比Hello World稍复杂点儿的NDK例子说说模板 ...博客:Android应用ViewDragHelper详解及部分源码浅析 博客文章链接---------实例代码工程 说明 示例均使用Android Studio演示。

    Android软件前景浅析

    - **技术创新**:Android不断推出新的版本和技术更新,如增强现实(AR)、人工智能(AI)等,以满足用户日益增长的需求。 综上所述,Android作为一款基于Linux内核的开放式移动操作系统,凭借其开放性、灵活性以及...

    基于Linux的Android OS平台应用浅析.pdf

    - **库(Libraries)**:Android包含了多种C++链接库,如SQLite用于数据库管理,OpenGL用于3D图形处理,媒体库处理音频和视频,以及LibWebCore用于网页渲染等。 - **Linux内核(Linux Kernel)**:提供了基础...

    浅析在Android系统中JSON和GSON的用法.pdf

    浅析在Android系统中JSON和GSON的用法.pdf

    C++11中std::declval的实现机制浅析

    C++11中std::declval的实现机制浅析 std::declval是C++11中引入的一个新的函数模板,用于获得类型的右值引用(rvalue reference)。该函数模板的实现机制非常有趣,下面我们来详细介绍其实现机制。 首先,std::...

Global site tag (gtag.js) - Google Analytics