Android:用MotionLayout布局简单实现过度动画

先看效果:

(懒得视频转gif,就截三张图吧)

动画前:

动画中:

动画结束:

这里4个view分别做了动画:

  1. 文字由黑色变红色
  2. 拖动圆形块由做到右
  3. 宽度改变块的宽度变宽
  4. 左下角弹出四个view

先了解一下背景:

MotionLayout继承自ConstraintLayout,所以布局里面的内容不需要改变,直接替换掉ConstraintLayout也是没有问题的。

实现步骤:

替换完之后布局会报问题,根据提示,让它自己生成我们的场景文件,并且会有一个属性:

app:layoutDescription="@xml/activity_main_scene"

再加一个id,后面会用到,整块如下:

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/motion_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    app:layoutDescription="@xml/activity_main_scene">


</androidx.constraintlayout.motion.widget.MotionLayout>

layout里面的view如果需要做位置动画变换的话可以先不声明类似layout_constraintStart_toStartOf这种位置,因为生成的场景文件里面声明优先级会比较高。

activity_main_scene文件如下:

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--原view的各种属性,比如位置大小透明度之类的-->
    <ConstraintSet android:id="@+id/start">
        <!--声明view的各个属性,注意这里的id要跟布局里面声明的那个view一致,以表同一个view。-->
        <Constraint android:id="@id/tv1" >
            <!--布局,view有的属性这里才有-->
            <Layout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
           <!--view没有的属性这里声明,如java里面的setXxxx的形式-->     
            <CustomAttribute
                app:attributeName="TextColor"
                app:customColorValue="#000000" />
        </Constraint>
        </Constraint>
        <!--可以有多个,比如:-->
        <Constraint android:id="@id/btn1" >
        ...
        </Constraint>
    </ConstraintSet>

    <!--动画完成之后view的各种属性,中间的变换过程它自己会计算-->
    <ConstraintSet android:id="@+id/end">
        <Constraint android:id="@id/tv1" >
            <Layout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
            <CustomAttribute
                app:attributeName="TextColor"
                app:customColorValue="#ff0000" />
        </Constraint>
    </ConstraintSet>

    <!--声明动画,指定哪个ConstraintSet是开始动画,哪个ConstraintSet是结束动画,并且可以指定动画时间、插值器等-->
    <Transition
        app:constraintSetEnd="@id/end"
        app:constraintSetStart="@id/start"
        app:duration="700">
        <!-- 滑动触发动画-->
        <OnSwipe app:touchRegionId="@id/tv2" app:touchAnchorSide="top" app:dragDirection="dragEnd"/>
        <!-- 点击触发动画 -->
        <OnClick app:targetId="@id/tv_btn" app:clickAction="toggle"/>
    </Transition>
    
</MotionScene>

一些说明看注释,简单点理解就是,在start的ConstraintSet块里面,声明view(一个view对应一个Constraint)的各种属性,到了end那里对应的view的属性值不同,中间它就会自己过滤。

比如,宽度由start的android:layout_width="100dp"到end的android:layout_width="match_parent",他就会自己伸缩这个宽度,同理位置也是这样,还有大小、旋转角度之类的都可以。

另外根据我个人总结再补充Transition的几点:

1、除了滑动触发和点击触发,还有个KeyFrameSet的方式,不过我还没研究

2、定义Constraint的id不需要用加号如@+id/tv1,改成@id/tv1,我看网上很多都是有那个+号,加上之后在我这里动画就不生效了

3、滑动触发动画的控件用touchRegionId指定,网上用说touchAnchorId,但是我试了touchAnchorId是整一个界面滑动

4、touchAnchorSide定义哪一边我貌似没有看出区别

5、dragDirection:滑动方向,这个效果挺明显

6、点击触发动画这里好像只能指定一个按钮,不过我用代码实现点击事件触发动画也不是难事:

btn.setOnClickListener {
    if(motion_layout.targetPosition == 1.0f){
        motion_layout.transitionToStart()
    }else{
        motion_layout.transitionToEnd()
    }
}

就可以啦。as自带的layout界面可以预览动画,但是我不太会用,貌似怎么点都没有效果,不研究了,老老实实自己敲。知道的大佬可以留言一起学习。

最后附上项目的demo地址(虽然是用kotlin项目,但是xml直接用在java的项目上是完全可以的,按钮点击事件一样的方法。GitHub太慢了,所以我上传的码云gitee):

https://gitee.com/xaehu/MotionLayoutStudyDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值