前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ConstraintLayout2.0一篇写不完之嵌套滚动怎么滚

ConstraintLayout2.0一篇写不完之嵌套滚动怎么滚

作者头像
用户1907613
发布2021-09-08 12:24:11
1.1K0
发布2021-09-08 12:24:11
举报
文章被收录于专栏:Android群英传Android群英传

在ConstraintLayout1.x阶段,它主要提供的能力是对静态布局的支撑,那么到2.x之后,MotionLayout的拓展,让它对动态布局的支持有了进一步的优化,在1.x阶段不能实现的嵌套滚动布局布局方式,现在也就非常简单了。

在没有ConstraintLayout的时候,要实现嵌套滚动布局,通常都是使用CoordinatorLayout来实现,但是这个东西的使用局限性比较大,能非常简单的实现的嵌套布局,就那么几种,如果要实现一些特别的滚动效果,就需要自定义behavior来实现,这样一来,嵌套滚动布局就成了一个比较复杂的布局方式了,而MotionLayout的出现,就可以完美的解决这样一个布局难题。

在ConstraintLayout2.x中,有两种方式来实现嵌套滚动布局。

CoordinatorLayout配合MotionLayout

这种方式实际上还是借助CoordinatorLayout,是一种比较早期的实现方案,如果是对CoordinatorLayout比较熟悉的开发者,可以很快改造现有代码来适配MotionLayout的嵌套滚动。

这种方案的布局结构如下:

CoordinatorLayout

--------AppBarLayout

----------------MotionLayout

--------NestedScrollView

可以发现,这种方式,实际上就是利用MotionLayout来替代之前在AppBarLayout里面的CollapsingToolbarLayout,借助MotionLayout来实现之前CollapsingToolbarLayout的一些折叠效果。

这种方式的一般套路结构如下。

image-20210223105619990

在AppBarLayout中,我们通过MotionLayout控制动画效果。

那么在这里,一般又有两个套路,一是直接使用MotionLayout,然后在代码里面通过AppBarLayout.OnOffsetChangedListener的回调,设置MotionLayout的progress,另一种是直接自定义MotionLayout,实现AppBarLayout.OnOffsetChangedListener,这样通用性比较强,示例如下。

class CollapsibleToolbar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), AppBarLayout.OnOffsetChangedListener {

    override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) {
        progress = -verticalOffset / appBarLayout?.totalScrollRange?.toFloat()!!
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        (parent as? AppBarLayout)?.addOnOffsetChangedListener(this)
    }
}

❝这两种方式没有本质上的不同,但是对于MotionEditor来说,如果使用自定义的MotionLayout,在非根布局下创建约束的时候会有一些问题(修改属性也会存在一些问题),所以,如果使用自定义MotionLayout的话,建议通过include的方式,引用新的根布局为自定义MotionLayout的方式来使用,而直接使用MotionLayout的方式,则没有这个限制,希望MotionEditor能早日改善这个问题。PS:好消息,Android Studio Arctic Fox已经修复了这个问题。 ❞

单纯MotionLayout实现

MotionLayout的出现,就是为了能替代动态的布局模型,所以,如果还使用CoordinatorLayout,那么就违背了开发者的初心了,所以,我们的目的就是去除CoordinatorLayout,而仅使用MotionLayout来实现嵌套滚动效果,实现滚动布局的大一统。

这种套路的一般结构如下所示。

MotionLayout

--------MotionLayout

--------NestedScrollView

我们可以发现,这里有两层MotionLayout,外层的MotionLayout,用于控制头部的伸缩布局,而内部的MotionLayout,则用于控制头部的滚动时效果。

这样一来,整个嵌套滚动的格局一下子就打开了,再也没了之前使用CoordinatorLayout的高度限制,效果限制,所有的内容,都可以通过约束来进行设置,再通过MotionLayout来进行动态约束,从而实现嵌套滚动布局。

对于外层的MotionLayout,它的Scene提供两个能力,一个是控制头部从200dp,变为56dp,即提供一个伸缩的功能,另一个重要的而且很容易被忽视的作用,就是给内层MotionLayout提供progress数据,有了这个progress,内部MotionLayout才能联动,这个和使用CoordinatorLayout配合MotionLayout使用要设置progress是一个道理。

我们来看下最外层的Scene,代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start">

        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@+id/motionLayout"
            motion:touchAnchorSide="bottom" />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <ConstraintOverride
            android:id="@id/motionLayout"
            android:layout_height="200dp"
            motion:motionProgress="0" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <ConstraintOverride
            android:id="@id/motionLayout"
            android:layout_height="56dp"
            motion:motionProgress="1" />
    </ConstraintSet>
</MotionScene>

对于非layout_constraintXXX_toXXXOf的约束,可以使用ConstraintOverride来直接覆写,这样可以少写很多重复的约束,这里的约束改变实际上只有两个,即layout_height从200变为56,而另一个重要的点,就是motionProgress的指定,motionProgress的作用就是设置motionProgress,如果不设置这个,那么progress数据是没办法传递到内部MotionLayout的,从而会导致内部无法联动。

解决完外部的MotionLayout之后,内部的MotionLayout就迎刃而解了,因为它真的就是一个平平常常的MotionLayout,你想要对它内部的元素做任何的改动,都和之前直接使用MotionLayout没有任何区别。

我们来看这个简单的例子,如图所示。

image-20210817161849272

头部伸缩配上文字的移动,一个简简单单的类CoordinatorLayout布局,外部的Scene我们已经解决了,再来看看内部的Scene,算了不看了,没什么必要,就是简单的体力劳动。

整个套路的布局结构如下所示。

image-20210817162156160

总体看来,MotionLayout是不是实现了大一统,它将滚动的布局效果,转化为了多层MotionLayout的Scene分解,利用progress串联起来,设计思路不可谓不精,一旦你熟练掌握了MotionLayout的各种基础布局,那么即使再复杂的布局,也能分而治之。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CoordinatorLayout配合MotionLayout
  • 单纯MotionLayout实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档