【Android】MotionLayout实现动画效果

news2024/9/22 4:01:57

【Android】MotionLayout实现开场动画

在移动应用开发中,动画不仅仅是美化界面的工具,它更是提升用户体验的关键手段。Android 平台一直以来都提供了丰富的动画框架,但随着应用复杂性的增加,开发者对动画的需求也变得更加复杂和多样化。为了更好地应对这些需求,Google 在 ConstraintLayout 的基础上推出了 MotionLayout

效果展示

先来看看MotionLayout可以实现的效果吧~

basic-horizontal-mot -original-original

来看看笔者用MotionLayout做的蒟蒻效果:

6748a7b1411f56f328fa -original-original

关于MotionLayout

如何去制作这样一个流畅的动画效果呢?我们直接进入本篇博客的主题:MotionLayout

MotionLayout简述

首先来简单介绍一下MotionLayout。MotionLayout 是 Android ConstraintLayout 的扩展,集布局和动画于一体,旨在简化复杂的界面过渡和动画效果的实现。与传统的动画框架相比,MotionLayout 更加声明性、更易于可视化,并且能够处理非常复杂的动画场景。通过 MotionLayout,开发者可以在布局文件中定义多个状态,并在这些状态之间进行平滑的过渡,从而实现丰富的动画效果,例如转场动画、导航菜单的展开与收起等。

QQ_1725026153876

这是Google官方文档中MotionLayout的介绍,我们可以看到它继承于ConstraintLayout,这在本文的后半部分,具体的代码操作中会有所体现,学习MotionLayout的使用可能需要对ConstraintLayout有一定的了解。

那么,MotionLayout是如何去实现动画的呢?所谓的声明性,可视性又是什么呢?又该如何定义多个状态,进行平滑过渡呢?我们接着往下看。

MotionScene

要做到动画效果的实现,我们离不开一个关键的配置文件:MotionScene。

它是一个 XML 文件,定义了动画的所有相关信息,包括状态、过渡、关键帧等。MotionScene 通过描述 ConstraintSet(状态集)、Transition(过渡)、KeyFrame(关键帧)等来组织和管理动画的逻辑。

MotionScene 的整体结构可以分为以下几个主要部分:

  1. ConstraintSet: 定义不同的布局状态(开始状态和结束状态)。
  2. Transition: 定义状态之间的过渡及其控制方式。
  3. KeyFrame: 定义动画过程中的关键变化点。
  4. OnSwipe: 定义与用户手势交互的动画触发器。

ConstraintSet

ConstraintSet 是 MotionScene 的基础部分,用于定义组件在不同状态下的布局约束。在 MotionScene 中,通常至少定义两个 ConstraintSet,分别对应 startend 状态。

每一个 ConstraintSet 都包含了布局中所有控件的约束信息。通过定义多个 ConstraintSet,你可以控制动画在不同状态下的表现。(一个ConstraintSet即为一个状态下,UI控件的集合)

以下是一些常用的属性:

ConstraintSet 中每个 Constraint 的属性基本与 ConstraintLayout 的属性相同。以下是一些常用属性:

  • layout_constraintStart_toStartOf: 将组件的开始边缘与另一个组件的开始边缘对齐。
  • layout_constraintEnd_toEndOf: 将组件的结束边缘与另一个组件的结束边缘对齐。
  • layout_constraintTop_toTopOf: 将组件的顶部与另一个组件的顶部对齐。
  • layout_constraintBottom_toBottomOf: 将组件的底部与另一个组件的底部对齐。
  • layout_widthlayout_height: 定义组件的宽度和高度。
  • rotation: 设置组件的旋转角度。
  • alpha: 设置组件的透明度。

开始状态与结束状态(Start and End States)

MotionLayout 的动画本质上是在两个状态之间进行转换:开始状态(start)和结束状态(end)。这两个状态定义了动画的起点和终点,分别通过 ConstraintSet 在 XML 中描述。

  • 开始状态(Start State):这是动画的初始状态,定义了组件的布局、大小、位置、旋转角度等属性。
  • 结束状态(End State):这是动画的最终状态,描述了动画结束时组件应达到的目标属性。

在动画开始时,组件处于 start 状态,随着用户的操作或代码控制,MotionLayout 会将组件逐步过渡到 end 状态。这个转换过程是通过 Transition 来定义和控制的。

例如:笔者制作的动画效果的配置文件如下:

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:alpha="0.7"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintBottom_toTopOf="parent" />
        <Constraint
            android:id="@+id/rv_msg"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            motion:layout_constraintStart_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="@id/linearLayout" />
        <Constraint
            android:id="@+id/linearLayout"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_marginBottom="10dp"
            motion:layout_constraintTop_toBottomOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/toolbar"
            motion:layout_constraintEnd_toEndOf="parent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:alpha="0.7"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
        <Constraint
            android:id="@+id/rv_msg"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toTopOf="@id/linearLayout"
            motion:layout_constraintTop_toBottomOf="@+id/toolbar"
            motion:layout_constraintStart_toStartOf="parent" />
        <Constraint
            android:id="@+id/linearLayout"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_marginBottom="10dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>
  • start 状态下,所有元素(toolbarrv_msglinearLayout)都在屏幕外部,因此不可见。
  • end 状态下,所有元素都移入屏幕内,toolbar 位于顶部,rv_msgtoolbar 下面,并占据屏幕的中间部分,linearLayout 位于屏幕底部。

当 MotionLayout 执行从 startend 的过渡时,toolbarrv_msglinearLayout 将从屏幕外部滑动到它们在 end 状态下的位置,创建一个滑动进入的动画效果。

Transition

Transition 是 MotionLayout 中的关键概念,用于定义从一个状态(ConstraintSet)到另一个状态的过渡动画。Transition 不仅控制动画的时间和插值器,还可以定义触发动画的条件和动画的具体行为(例如响应触摸事件或特定的时间)。

basic-horizontal-mot -original-original

例如,在这个实例中,可以通过滑动来控制方块控件的位置,这一操作可以定义在Transition中。

在笔者制作的动画效果中,Transition如下:

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@id/start"
        motion:duration="2000"
        motion:autoTransition="animateToEnd">
    </Transition>	
  • app:constraintSetStart: 定义动画的起始状态,这个属性引用了一个 ConstraintSet
  • app:constraintSetEnd: 定义动画的结束状态,这个属性也引用了一个 ConstraintSet
  • app:duration: 动画的持续时间,以毫秒为单位。

除了基本属性,Transition 还提供了一些高级属性和功能,帮助你更细致地控制动画行为。

触摸事件(OnSwipe 和 OnClick)

你可以通过 OnSwipeOnClick 来定义触摸事件,触发 Transition 的执行。

OnSwipe: 定义了在滑动手势下如何触发 Transition,例如上下滑动或左右滑动。

<OnSwipe
    app:dragDirection="dragUp"
    app:touchAnchorId="@id/imageView"
    app:touchAnchorSide="bottom" />
  • app:dragDirection: 指定滑动的方向,例如 dragUp 表示向上滑动。
  • app:touchAnchorId: 触摸事件的锚点,即滑动时要跟踪的视图。
  • app:touchAnchorSide: 指定锚点的哪一侧被用作触摸参考点。

OnClick: 定义点击事件触发 Transition,例如点击某个按钮时触发动画。

<OnClick
    app:targetId="@id/button"
    app:clickAction="transitionToEnd" />
  • app:targetId: 触发点击事件的目标视图 ID。
  • app:clickAction: 定义点击后的动作,例如 transitionToEnd 表示触发从 startend 的过渡。
自动过渡(AutoTransition)

Transition 还支持自动过渡,即在满足特定条件时自动触发动画。你可以通过以下属性控制自动过渡:

  • app:autoTransition
    设置自动过渡的类型。
    • jumpToEnd: 动画直接跳到结束状态。
    • animateToEnd: 动画自动播放到结束状态。
    • jumpToStart: 动画直接跳回开始状态。
    • animateToStart: 动画自动回到开始状态。

KeyFrame

KeyFrame 是 MotionLayout 中用于精确控制动画过程的工具。它允许你在动画的特定时间点(关键帧)对视图的属性进行自定义设置,以实现复杂的动画效果。KeyFrame 可以让你在动画过程中定义位置、属性变化、周期性动画等,从而获得更细致的动画表现。

其实就是实现帧动画

在 MotionLayout 中,KeyFrame 用于指定在动画过程中的某些关键时间点上视图的状态。这些关键时间点通常是动画的百分比位置(0% 到 100%),即动画开始到结束的过程中的特定位置。

可以实现如下的效果:

动画效果

KeyFrame 类型

MotionLayout 提供了几种不同类型的 KeyFrame,每种类型用于不同的动画控制需求:

  1. KeyPosition
  2. KeyAttribute
  3. KeyCycle
1. KeyPosition

KeyPosition 主要用于控制视图的位置变化。通过 KeyPosition,你可以定义在动画的特定时刻视图的位置(xy 坐标)。

属性

  • app:framePosition: 关键帧的位置,范围从 0 到 100,表示动画的百分比。
  • app:motionTarget: 关键帧作用的目标视图。
  • app:percentX: 目标视图在动画时刻的相对 X 坐标(0.0 到 1.0)。
  • app:percentY: 目标视图在动画时刻的相对 Y 坐标(0.0 到 1.0)。

示例

<KeyPosition
    app:framePosition="50"
    app:motionTarget="@id/targetView"
    app:percentX="0.5"
    app:percentY="0.5" />

在这个示例中,KeyPosition 定义了在动画的 50% 位置上,targetView 的位置应为相对父视图的中心(50% X 和 50% Y)。

2. KeyAttribute

KeyAttribute 用于控制视图的属性变化,例如尺寸、透明度、旋转等。你可以在关键帧中定义这些属性在特定时刻的值。

属性

  • app:framePosition: 关键帧的位置,范围从 0 到 100,表示动画的百分比。
  • app:motionTarget: 关键帧作用的目标视图。
  • app:attributeName: 要设置的属性名称(如 alpharotationscaleXscaleY 等)。
  • app:attributeValue: 属性在关键帧时刻的值。

示例

<KeyAttribute
    app:framePosition="50"
    app:motionTarget="@id/targetView"
    app:attributeName="alpha"
    app:attributeValue="0.5" />
3. KeyCycle

KeyCycle 用于控制周期性动画,即动画过程中的重复效果。它允许你创建周期性的动画效果,如摆动或波动。

属性

  • app:framePosition: 关键帧的位置,范围从 0 到 100,表示动画的百分比。
  • app:motionTarget: 关键帧作用的目标视图。
  • app:cycle: 循环次数或周期。
  • app:waveShape: 波形形状,例如 sinetriangle 等。
  • app:wavePeriod: 波形周期。

示例

<KeyCycle
    app:framePosition="50"
    app:motionTarget="@id/targetView"
    app:waveShape="sine"
    app:wavePeriod="1"
    app:rotation="360" />

怎么创建MotionLayout

可以像写ConstraintLayout一样,直接在创建的时候就选择使用MotionLayout,但是笔者更加推荐先写一个ConstraintLayout,再转换为MotionLayout的方法。(对喜欢改UI的人比较友好)

首先我们拿到一个ConstraintLayout

QQ_1725028634488

右侧工具栏,启动!ComponentTree,启动!右键main然后点击Convert to MotionLayout,就可以自动转换成MotionLayout啦,同时也会自动创建一个MotionScene配置文件。

不想写代码怎么办

那么这个时候可能就有同学会问了,虽然已经把需要写的代码简化成这样了,但我还是不想写,怎么办?(谁问你了?)

不要慌,请看VCR:

QQ_1725028790092

我们把右侧工具栏拉出来,发现了…一个AndroidStudio自带的图形化工具!

可以在这里自由注册Constraint中的组件,也可以自由设置start以及end状态中组件的位置,大小,角度等等属性。

QQ_1725028892570

点击左上角的箭头,还可以直接设置Transition的属性,添加关键帧等等。

(但是这个只能作为便利开发的一种手段,笔者亲测感觉这个东西不是太好用,主要体现在设置填入的时候总是不及时反馈,有时候设置了许多东西,运行发现并未设置上,叫人抓狂得很)

结语

参考文档:

突破传统动画:探索MotionLayout的独特优势-腾讯云开发者社区-腾讯云 (tencent.com)

MotionLayout examples | Views | Android Developers (google.cn)

Android | MotionLayout入门级使用教程(一)_motionlayout的使用-CSDN博客

希望这篇文章可以给大家的UI开发做一些思路上的扩展~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2091159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Navicat最新版简体中文版破解激活永久详细教程】

2024 Navicat Premium最新版简体中文版破解激活永久图文详细教程 1.未安装过的用户可直接跳过该步骤&#xff0c;如果已安装Navicat&#xff0c;记得先卸载干净&#xff0c;防止破解失效&#xff0c;卸载完成后执行补丁压缩包中的Navicat.bat脚本&#xff08;一闪而过表示正常&…

背包问题——分组背包

样题&#xff1a; 枚举第i组选第几个物品 #include <bits/stdc.h> using namespace std; const int N 110; int f[N],w[N][N],v[N][N],s[N];int main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int n,V,cnt 0; cin >> n >> V;for(int i 1; i &…

HTML爱心流星雨

目录 写在前面 完整代码 代码分析 推荐系列 写在后面 写在前面 如何用HTML代码实现爱心流星雨的动态效果&#xff1f;本期博主将带着大家探索神奇的HTML。 完整代码 <!doctype html> <html> <head><meta charset"utf-8"><title&g…

axios取消请求CancelToken的原理解析及用法示例

文章目录 一、axios的实例与请求流程二、CancelToken 的作用三、CancelToken 的实现原理四、取消请求的流程五、CancelToken用法六、利用拦截器取消请求1、axios请求拦截器2、axios响应拦截器3、利用路由导航守卫取消请求 一、axios的实例与请求流程 下图是axios实例属性的简图…

Scrach游戏制作:时机的活儿~(可自改难度)(免费源码)

游戏演示&#xff1a; 这是个时机di活儿~_哔哩哔哩_bilibili 作品制作流程&#xff1a; 自由移动不断切换造型传送&#xff08;碰撞检测&#xff09;火车&&棒球的旋转增加关卡难度游戏结束 1. 自由移动&#xff08;对猫猫编程&#xff09; 自由移动是让角色能够朝上下…

Camtasia 2024 v2024.0.6 for Mac 中文版 屏幕录像视频录制编辑软件

TechSmith Camtasia for Mac 中文版 是一款专业的屏幕录像及视频录制编辑软件。以业界领先的清晰度重新定义了屏幕录制&#xff0c;将屏幕、摄像头、麦克风和系统音频捕获为独立音轨&#xff0c;实现终极控制和灵活性。通过拖放过渡、标注等功能&#xff0c;以及改进的工作流程…

WCT系列(四):BLASTSyncEngine

WCT系列&#xff08;一&#xff09;&#xff1a;WindowContainerTransaction类详解 WCT系列&#xff08;二&#xff09;&#xff1a;SyncTransactionQueue类详解 WCT系列&#xff08;三&#xff09;&#xff1a;WindowOrganizerController WCT系列&#xff08;四&#xff09;&a…

图片拼图怎么做?4个方法打造具有高级感的拼图作品

被阿勒泰的日落治愈了&#xff0c;旅行中的每一刻都值得珍藏。 这次的阿勒泰之行&#xff0c;我不仅带回了一堆美好的回忆&#xff0c;还有手机里满满的精彩瞬间。从壮丽的山川到静谧的湖泊&#xff0c;从晨曦初现到夜幕降临&#xff0c;每一帧都是大自然的馈赠。但是&#xf…

C++ 设计模式——职责链模式

目录 C 设计模式——职责链模式1. 主要组成成分2. 逐步构建职责链模式步骤1&#xff1a;定义处理者接口步骤2&#xff1a;定义抽象处理者步骤3: 创建具体处理者步骤4: 配置职责链 3. 备忘录模式 UML 图UML 图解析 4. 单纯与非单纯的职责链模式4.1 敏感词过滤器父类4.2 具体过滤…

C++:类的定义、实例化

目录 一、类的定义 1.1 类的定义格式 1.2 访问限定符 1.3 类域 二、实例化 2.1 实例化概念 2.2 对象大小 一、类的定义 1.1 类的定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省…

设备上的实时自定义手势识别

这篇论文的标题是《On-device Real-time Custom Hand Gesture Recognition》&#xff0c;主要研究了如何在移动设备上实时识别自定义手势。以下是论文的主要内容概述&#xff1a; 摘要&#xff1a; 论文指出现有的手势识别系统大多限于预定义的手势集&#xff0c;但用户和开发…

鸿蒙(HarmonyOS)常见的三种弹窗方式

最近有一个想法&#xff0c;做一个针对鸿蒙官方API的工具箱项目&#xff0c;介绍常用的控件&#xff0c;以及在项目中如何使用&#xff0c;今天介绍Harmony中如何实现弹窗功能。 警告弹窗 警告弹窗是一个App中非常常用的弹窗&#xff0c;例如&#xff1a; 删除一条记录&…

帕金森患者在运动时有哪些类型的运动推荐?

帕金森病患者在进行运动时&#xff0c;可以考虑以下几种类型的运动&#xff1a; 有氧运动&#xff1a;如散步、慢跑、爬山、骑自行车、健美操、广场舞等&#xff0c;这些运动有助于改善心肺功能&#xff0c;同时也能提升肌肉力量和灵活性。 柔性运动&#xff1a;包括瑜伽、太极…

<Rust>egui学习之小部件(七):如何在窗口中添加颜色选择器colorpicker部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第七篇博…

笔记整理—内核!启动!

常规启动时&#xff0c;各镜像都在SD卡中的各种分区中&#xff0c;内核放在kernel分区&#xff0c;从SD卡到DDR的连接处&#xff08;内核不需要进行重定位&#xff0c;直接从链接处启动&#xff09;。uboot从sd卡分区读使用movi命令。 使用fastboot指令可以查看分区情况&#x…

【赵渝强老师】MongoDB的MMAPv1存储引擎

在MongoDB 3.2版本以前&#xff0c;MongoDB使用MMAPv1作为默认的存储引擎。在MMAPv1的存储引擎中&#xff0c;包含以下的组成部分&#xff1a; Database 每个Database由一个.ns名称空间文件及若干个数据文件组成。数据文件从0开始编号&#xff0c;依次为.0、.1、.2等。数据文件…

小心GitHub账号被盗

最近有小伙伴反馈在 GitHub 上解压了不明文件之后&#xff0c;GitHub 账号被盗了。 事情是这样的&#xff1a; 有小伙伴在 GitHub 某仓库的 issue 中正常和人讨论问题&#xff0c;有个人光速回复了一条消息&#xff0c;给了一个链接&#xff0c;让下载一个名为 fix.rar 的文件…

C++系列-STL容器之list

STL容器之list list容器的基本结构list容器的特点list容器的优点list容器的缺点 list容器的构造函数list容器的常用接口list大小及空否list访问list迭代器相关list增删查改push and popinsert其它 list赋值操作 list容器的基本结构 list容器的内部结构是双向循环链表&#xff…

Java笔试面试题AI答之面向对象(8)

文章目录 43. 解释Java接口隔离原则和单一原则如何理解 &#xff1f;单一职责原则&#xff08;Single Responsibility Principle, SRP&#xff09;接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09; 44. Java 有没有 goto? 如果有&#xff0c;一般用…

004.Python爬虫系列_web请求全过程剖析(重点)

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…