【译文】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

相关文章
|
6天前
|
Android开发
DrawerLayout怎样禁止滑动
DrawerLayout怎样禁止滑动
25 4
|
Android开发 Java
Android开源DiscreteSeekbar:动画气泡指示当前滑动值
 Android开源DiscreteSeekbar:动画气泡指示当前滑动值 Android本身提供的SeekBar用以调控值以及回调传回当前选择的值。
1338 0
|
Android开发
NestedScrollView嵌套WebView导致底部有空白
NestedScrollView嵌套WebView导致底部有空白
446 0
|
Android开发
页面切换时为什么会自动跳到recyclerView的位置?
页面切换时为什么会自动跳到recyclerView的位置?
150 0
|
iOS开发
iOS ScrollView嵌套tableview左右滑动时禁止上下滑动
iOS ScrollView嵌套tableview左右滑动时禁止上下滑动
1471 0
|
移动开发 Dart
【新年快乐第二弹】在 Flutter 中使用交错网格视图创建瀑布流布局
马上过新年了,想好如何过年了吗?,今天我带大家在瀑布流布局中写新年快乐。 在 Web 和移动开发世界中,当我们想要显示大小不相同的项目网格时,瀑布流布局很有用。一个轴使用严格的网格布局,通常是列。在另一个轴上,项目具有不同的高度,但可以灵活排列以填满可用空间。使用瀑布流布局的一个著名例子是 Pinterest。他们为他们的网站和移动应用程序实现了这种布局,以显示不同大小的图像。
246 0
|
Android开发 开发者 Kotlin
【RecyclerView】 十五、使用 ItemTouchHelper 实现 RecyclerView 拖动排序 ( ItemTouchHelper 简介 )
【RecyclerView】 十五、使用 ItemTouchHelper 实现 RecyclerView 拖动排序 ( ItemTouchHelper 简介 )
255 0
|
vr&ar 图形学
【Unity3D 灵巧小知识点】☀️ | Unity UGUI组件Scroll View禁止 左右 或 上下 滑动
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。 也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
【Unity3D 灵巧小知识点】☀️ | Unity UGUI组件Scroll View禁止 左右 或 上下 滑动
|
Android开发 容器 数据格式
Android实践(一)| Fragment实现底部导航栏(解决重叠问题)
最初学习Android的时候,是边学习边做着一个小项目的,因为项目需求,需要实现一个底部导航栏的功能,由于基础知识受限,百度了很多博客,大致就找到两种实现方案:第一种就是直接用Fragment实现(点击切换),第二种是ViewPager+Fragment实现(除了点击切换,还支持左右滑动切换)。
2264 0