【译文】AppBarLayout的越界滚动行为

简介:

很不幸,Youtube音乐应用在我们国家不可使用,我尝试着通过各种盗版网站来获取该应用,但我仍然无法看到在这个应用上发生了什么。感谢这位redditor,在我的请求下,他在/r/materialdesign打开了一个thread并且发表一段录制的视频,我才有机会看到这个行为。

Youtube视频app的真实截图,可能的行为Youtube视频app的真实截图,可能的行为

根据我所看到的,我首先想到的就是专辑封面是放到一个AppBarLayout里面,并且在滚动区域拖到边界的时候尺寸会发生变化。让我们假定这个 猜想是正确的并且用“Behavior”这个术语表示它。依鄙人之见,如果我的猜想是正确的,谷歌应该会在Material Design文档的滚动部分提供一个越界滚动的使用说明。

我们的目标就是保证AppBarLayout.Behavior的完整性,在此基础上再创建一个扩展的行为。因此:

public class OverscrollScalingViewAppBarLayoutBehavior extends AppBarLayout.ScrollingViewBehavior

因为这是默认的AppBarLayout.Behavior,所以建议只有在依赖视图是AppBarLayout的时候起作用。

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
 return dependency instanceof AppBarLayout;
}

接下来,我们需要获取想要在拖到边界时要改变尺寸的视图的一个实例。最好的方法就是在onLayoutChild()方法中获取:

@Override
public boolean onLayoutChild(CoordinatorLayout parent ....) {
    boolean superLayout = super.onLayoutChild(parent, abl, layoutDirection);
    if (mTargetScalingView == null) {
        mTargetScalingView = parent.findViewByTag(TAG);
        if(mTargetScalingView != null){
             mScaleImpl.obtainInitialValues();
         }
     }
    return superLayout;
}

而且我们需要保证只有在垂直滚动的时候起作用:

@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,... int nestedScrollAxes) {
    return nestedScrollAxes == View.SCROLL_AXIS_VERTICAL;
}

如果我们先前没有在程序中显示设置,会设置ViewScaler为默认的Scaler。

在内容滚动的瞬间,真正重要的问题就有头绪了。CoordinatorLayout.Behavior提供了一个onNestedScroll() 方法,当滚动进行的时候这个方法会被调用,并且当内容滚动到边界的时候也会调用。最后两个参数dyUnconsumed和dxUnconsumed提供了 未被该行为的目标视图填满的像素值。

这个方法对我们实现尺寸改变来说太重要了。所以我列出了哪些情况需要改变尺寸,哪些情况不需要:

需要改变尺寸

  1. 存在未填满的像素,如dyUnconsumed小于0
  2. AppBarLayout是展开的,getTopAndBottomOffset() >= mScaleImpl.getInitialParentBottom()

不需要改变尺寸

  1. AppBarLayout中没有子视图可以改变尺寸
  2. 有填充的像素,如dyConsumed不等于

@Override
public void onNestedScroll(CoordinatorLayout ... int dxUnconsumed, int dyUnconsumed) {
    if (mTargetScalingView == null || dyConsumed != 0) {
        mScaleImpl.cancelAnimations();
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        return;
    }

    if (dyUnconsumed < 0 && getTopAndBottomOffset() >= mScaleImpl.getInitialParentBottom()) {
        int absDyUnconsumed = Math.abs(dyUnconsumed);
        mTotalDyUnconsumed += absDyUnconsumed;
        mTotalDyUnconsumed = Math.min(mTotalDyUnconsumed, mTotalTargetDyUnconsumed);
        mScaleImpl.updateViewScale();
    } else {
        mTotalDyUnconsumed = 0;
        mScaleImpl.setShouldRestore(false);
        if (dyConsumed != 0) {
            mScaleImpl.cancelAnimations();
        }
        super.onNestedScroll(coordinatorLayout, .... dxUnconsumed, dyUnconsumed);
    }
}

当嵌套的overscroll停止的时候,我们需要将视图的边界和大小重置到它们的原始值。

@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
    mScaleImpl.retractScale();
    super.onStopNestedScroll(coordinatorLayout, child, target);

}

ViewScaler

这个类实现了AppBarLayout应该如何改变它的底部以及视图应该 如何改变尺寸的逻辑。大多数行为都依赖累积的未填充的像素。我们可以为最大累积值设置一个约束值,这样可以很容的找到要如何改变AppBarLayout 底部和改变视图的尺寸。ParentScaler是ViewScaler的父类,它能让AppBarLayout近乎平滑的改变尺寸。我就不在这里贴大量 代码了,如果你有兴趣,可以从这里获取代码

Bonus

大神们,这里有个MatrixScaler类,我没有时间去完成它。如果想要改变尺寸的视图是ImageView,并且设置了ScaleType为MATRIX,这个类将可以用使用矩阵的方式来改变图像的尺寸。

Demo

相关文章
|
Kubernetes 应用服务中间件 Linux
Docker 容器编排(compose)
介绍 compose 安装和 yaml 文件编写,实现容器的批量编排。
1217 11
Docker 容器编排(compose)
|
6月前
|
存储 弹性计算 缓存
阿里云 ECS 通用型 g7 实例(ecs.g7.large)2核8G云服务器活动价格及性能测评
阿里云 ECS 通用型 g7 实例(规格 ecs.g7.large)是面向企业级通用场景的经典机型,以 2 核 8G 的 CPU 内存配比、灵活带宽选择及 40GB ESSD 云盘为核心配置,依托成熟的硬件架构与稳定性能,适配从中小型应用到轻量企业服务的多元需求。作为阿里云第七代通用型实例的代表,它在计算、内存、网络与存储维度实现均衡优化,同时具备安全加固特性,适合对性能稳定性有基础要求的业务场景。本文从配置细节、性能特点、适用场景等维度展开解析,帮助用户直观理解该实例的核心价值。
|
6月前
|
域名解析 存储 弹性计算
阿里云服务器购买与使用参考:云服务器购买、域名注册、备案流程
阿里云服务器购买与使用涵盖ECS选购、域名注册、备案及绑定等流程。ECS选购提供包年包月/按量付费模式,用户可根据需求选择地域、实例规格及镜像存储等配置。域名注册支持多种后缀,提供创建信息模板、实名认证等服务。备案攻略包括准备材料、在线提交申请及审核流程。最后,通过域名解析与服务器绑定,实现网站访问。购买前可先在权益中心领券以获得更多减免。
|
7月前
|
人工智能 供应链
1688严选升级,推出AI智能诊断与优化的成长指南!
1688严选升级,推出AI智能诊断与优化的成长体系,新增“严选潜力品”层级,商品分层管理,前台无标但收取5%技术服务费。加入需满90天方可退出,商家应谨慎评估成本,避免全店入驻,建议局部试点,理性利用流量红利,防止利润被侵蚀。
|
7月前
|
人工智能 文字识别 自然语言处理
金融行业RPA案例大全:银行_证券_保险全场景落地实践(附数据)
凌晨两点的金融城灯火通明,RPA“数字员工”正悄然变革行业。从银行对账到证券清算、保险理赔,重复工作被高效替代。实在智能的实在Agent作为第三代RPA,融合AI与大模型,实现智能决策与自主学习,助力金融机构降本增效,推动服务迈向智能化。
696 2
|
6月前
|
JavaScript 前端开发 容器
油猴脚本:快速打开粘贴的多个网址
本文介绍一款实用的油猴脚本,可批量打开粘贴的网址链接。脚本支持设置时间间隔,防止浏览器崩溃,提升工作效率。内容涵盖功能说明、代码解析与优化建议,适合日常办公使用。
571 0
|
人工智能 自然语言处理 运维
AI中台助力企业智能化转型
本文主要和大家分享 “AI中台如何助力企业数字化以及智能化转型”,以及我在构建 AI中台方面的一些心得和经验。
AI中台助力企业智能化转型
|
数据安全/隐私保护 网络虚拟化 开发者
Appuploader:常见错误及解决方法指南
Appuploader是一款用于上传、管理和分享iOS应用的客户端工具。使用Appuploader可以让您更加便捷地管理和分享您的应用程序,同时也能够提高工作效率。本文将介绍一些常见的Appuploader错误及其解决方法。
|
敏捷开发 人工智能 监控
《游戏工业化》(下)走进游戏工业化
《游戏工业化》(下)走进游戏工业化
《游戏工业化》(下)走进游戏工业化
|
设计模式 算法 前端开发
GitHub上最火的、最值得前端学习的几个数据结构与算法项目!没有之一!
GitHub上最火的、最值得前端学习的几个数据结构与算法项目!没有之一!
982 0
GitHub上最火的、最值得前端学习的几个数据结构与算法项目!没有之一!