Flutter 共性元素动画
在 Flutter 中,共性元素动画(Shared Element Transitions)用于在页面导航或组件切换时创建视觉上更流畅和连贯的动画效果。这种动画可以使用户感受到两个界面之间的“物理联系”,比如图片从缩略图到全屏的扩大效果。
前置知识点整理
Navigator
在 Flutter 中,`Navigator` 是一个用于管理应用页面的堆栈控件。通过 `Navigator`,您可以在应用中实现页面导航。`MaterialPageRoute` 是 Flutter 提供的一种常用的页面路由,它遵循 Material Design 的动画和过渡规范。
代码示例
Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return const Page();
},
fullscreenDialog: true
));
代码解析
`Navigator.of(context)`
- `Navigator.of(context)` 获取与指定 `BuildContext` 关联的 `Navigator` 实例。`Navigator` 是一个用于管理应用页面导航的控件。
- `context` 是当前小部件树中的上下文,通常在小部件的 `build` 方法中可以直接获取。
`push` 方法:
`push` 方法用于将新的路由(页面)推入导航堆栈的顶部。这会导致新页面显示在当前页面之上。
`MaterialPageRoute`:
- MaterialPageRoute` 是一种实现 `PageRoute` 的类,用于在 Material Design 样式的应用中创建路由。
- 它提供了标准的页面切换动画和过渡效果。
`builder` 参数:
- `builder` 是一个回调函数,接收一个 `BuildContext` 参数,并返回一个要显示的新页面的小部件。
- 在这个例子中,`builder` 返回一个 `Page` 实例。`const` 修饰符表示 `Page` 是不可变的,并且是编译时常量。
`fullscreenDialog` 参数:
- `fullscreenDialog: true` 指定新页面是否应该以全屏对话框的形式出现。
- 当 `fullscreenDialog` 设置为 `true` 时,新页面通常会从屏幕底部滑入,并带有关闭按钮(通常是一个“关闭”图标),这与典型的页面过渡动画有所不同,通常用于需要用户特别注意的内容页面。
使用场景
- 标准页面导航: 使用 `MaterialPageRoute` 是创建标准 Material 设计风格页面的常用方法。它自动处理页面切换的动画和过渡效果。
- 全屏对话框: 设置 `fullscreenDialog` 为 `true` 可以用于显示用户需要特别注意的内容,比如设置页面、表单页面等。它通常用于在移动应用中模拟对话框或模态视图。
注意事项
- 航堆栈: 每次调用 `push` 方法时,新页面都会被添加到导航堆栈的顶部。当用户按下返回按钮或调用 `Navigator.pop(context)` 时,堆栈顶部的页面会被移除。
- 上下文的使用: 确保 `context` 是当前页面的上下文,并且在适当的位置(如 `build` 方法中)使用它,以便正确获取 `Navigator` 实例。
这段代码展示了如何在 Flutter 应用中使用 `Navigator` 和 `MaterialPageRoute` 进行页面导航,并通过 `fullscreenDialog` 参数实现全屏对话框效果。
InkWell
`InkWell` 是 Flutter 中用于实现“水波纹”点击效果的一个小部件。当用户在支持 `Material` 设计的应用中点击某个组件时,`InkWell` 可以提供一个视觉反馈。这种点击效果通常用于提升用户体验,使交互更加直观。
`InkWell` 的主要属性
- `child`:`InkWell` 的子小部件。通常是您希望作为点击目标的部件,比如一个文本、图标或者容器。
- `onTap`:点击时触发的回调函数。当用户点击 `InkWell` 时,`onTap` 中的代码将被执行。
- `onDoubleTap`:双击时触发的回调函数。
- `onLongPress`:长按时触发的回调函数。
- `onTapDown`:手指按下时触发的回调函数。
- `onTapCancel`:点击被取消时触发的回调函数。
- `borderRadius`:边界的圆角半径。在具有圆角的组件上使用时很有用。
- `splashColor`:点击时水波纹的颜色。
- `highlightColor`:点击时的高亮颜色。
- `hoverColor`:悬停时的颜色(通常在桌面应用中使用)。
使用场景
- 按钮:用作自定义按钮的点击效果。
- 列表项:在列表中为每个项目添加点击反馈。
- 卡片:为图片或卡片提供点击反馈。
- 图标:为图标添加点击效果。
`InkWell` 是一个简单而强大的工具,用于实现点击反馈效果,使得 Flutter 应用的交互更加自然和直观。
Image.asset
`Image.asset` 是 Flutter 中用于加载和显示本地资源图片的一个构造方法。它是 `Image` 小部件的一种常用方式,用于从应用的资产中加载图片。
`Image.asset` 的主要属性
- `String name`:图片资源的路径,相对于 `pubspec.yaml` 中定义的资产路径。
- `Key key`:小部件的唯一标识符,用于优化 Flutter 的小部件树。
- `double scale`:图片的比例因子,如果没有指定,Flutter 会根据设备的分辨率自动计算。
- `ImageFrameBuilder frameBuilder`:用于构建每一帧的自定义小部件。
- `ImageLoadingBuilder loadingBuilder`:用于在图片加载时显示自定义的加载指示器。
- `BoxFit fit`:规定图片的缩放和剪裁方式。例如:`BoxFit.cover`、`BoxFit.contain` 等。
- `AlignmentGeometry alignment`:控制图片的对齐方式,默认是 `Alignment.center`。
- `ImageRepeat repeat`:控制图片的重复方式,例如:`ImageRepeat.repeat` 或 `ImageRepeat.noRepeat`。
- `bool matchTextDirection`:是否根据文本方向自动镜像图像。
- `bool gaplessPlayback`:图像在更新过程中是否保持显示。
使用步骤
在 `pubspec.yaml` 中声明资产:
- 在 Flutter 项目中使用本地图片前,必须在 `pubspec.yaml` 文件中声明图片资产。
flutter:
assets:
- assets/images/my_image.png
组织项目目录:
- 通常将图片存放在 `assets/images/` 目录中或其他自定义目录。
使用 `Image.asset` 加载图片。
使用场景
- 应用图标:在应用的不同部分显示标识性图像。
- 背景图像:作为其他 UI 元素的背景。
- 产品展示:显示本地存储的产品图像。
- 图形资产:例如图标、插图等静态资源。
通过 `Image.asset`,您可以方便地在 Flutter 应用中加载和显示本地图片资源。确保在 `pubspec.yaml` 中正确声明资产路径,并适当地组织项目目录,以便更好地管理图片资源。
Hero
Flutter 提供了一个简单的方式来实现共性元素动画,那就是使用 `Hero` 小部件。`Hero` 小部件可以在两个路由(页面)之间创建共享元素动画。
基本步骤
1.包装共享元素:在两个页面中,将共享的元素用 `Hero` 小部件包装。
2.指定相同的 tag:确保在两个 `Hero` 小部件上使用相同的 `tag` 标识。
3.导航:在导航到新的页面时,Flutter 自动处理共享元素的动画。
代码示例
import 'package:flutter/material.dart';
class MyHonorDemoPage extends StatelessWidget {
const MyHonorDemoPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("MyHonorDemoPage"),
),
body: Center(
child: InkWell(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return const MyHonorPage();
},
fullscreenDialog: true));
},
child: Hero(
tag: "image",
child: Image.asset(
"static/my_icon.png",
fit: BoxFit.cover,
width: 100,
height: 100,
),
),
),
),
);
}
}
class MyHonorPage extends StatelessWidget {
const MyHonorPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: InkWell(
onTap: () {
Navigator.of(context).pop();
},
child: Container(
alignment: Alignment.center,
child: Hero(
tag: "image",
child: Image.asset(
"static/my_icon.png",
fit: BoxFit.cover,
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).width,
),
),
),
),
);
}
}
注意事项
1.Tag 唯一性:确保每对共享元素的 `tag` 是唯一的,以避免动画错误。
2.动画时间:可以通过 `PageRoute` 自定义动画时间和曲线。