Flutter页面过渡动画插件loop_transition的使用
Flutter页面过渡动画插件loop_transition的使用
loop_transition
包提供了一个名为 LoopTransition
的多功能小部件,允许你为子部件应用可重复的动画过渡。这些过渡可以循环指定次数,从而在你的用户界面中创建动态效果。
特性
- 应用于子部件的可重复动画过渡。
- 提供多种内置过渡函数(如淡入淡出、旋转、滑动、缩放、闪烁)。
- 允许使用
LoopTransitionBuilder
自定义过渡。 - 支持通过
pause
属性暂停和恢复播放。 - 通过以下属性控制动画行为:
repeat
: 动画循环的次数(-1 表示无限循环)。pause
: 是否暂停动画。continuity
: 控制动画在暂停时是否保持连续性。mirror
: 动画是否向前播放然后向后播放,形成镜像效果。reverse
: 控制初始动画方向(向前或向后)。transition
: 定义动画行为的LoopTransitionBuilder
函数。curve
: 控制动画缓动的动画曲线。delay
: 动画开始前的延迟时间。duration
: 每个方向(正向和反向,如果适用)的动画持续时间。backwardDelay
: 向后动画开始前的延迟时间(在镜像效果中适用)。backwardDuration
: 向后动画的持续时间(镜像效果中适用)。
- 在各种动画生命周期阶段触发回调:
onStart
: 在第一次动画播放开始时调用一次。onPause
: 动画每次暂停时调用。onContinue
: 动画每次恢复时调用。onCycle
: 每次动画完成一个循环迭代时调用(正向和反向,如果适用)。onComplete
: 当所有指定循环都完成时调用一次(如果repeat
不设置为 -1 表示无限循环)。
使用方法
要了解更多关于 loop_transition
中使用的类和其他引用,请参阅 API 文档。
导入包
import 'package:loop_transition/loop_transition.dart';
创建可重复的过渡小部件
LoopTransition(
// 重复动画循环 3 次(除了最初的循环)
repeat: 3,
// 开始动画
pause: false,
// 当 `pause` 设置为 `true` 然后 `false` 时,重置动画以继续
continuity: false,
// 启用镜像效果
mirror: true,
// 初始动画逆向播放(可选)
reverse: true,
// 使用内置的淡入淡出过渡动画(你可以使用自定义的 LoopTransitionBuilder 来实现更复杂的动画)
transition: LoopTransition.fade,
// 使用曲线来使动画平滑(可选)
curve: Curves.easeInOut,
// 动画开始前延迟 1 秒
delay: const Duration(seconds: 1),
// 设置动画持续时间为 500 毫秒,每个方向(正向和反向,如果适用)
duration: const Duration(milliseconds: 500),
// 设置向后动画开始前的延迟时间(可选)
backwardDelay: const Duration(milliseconds: 200),
// 设置向后动画的持续时间(可选)
backwardDuration: const Duration(milliseconds: 500),
// 动画生命周期事件的回调(可选)
onStart: () => debugPrint('Animation Started'),
onPause: () => debugPrint('Animation Paused'),
onContinue: () => debugPrint('Animation Continued'),
onCycle: (cycle) => debugPrint('Animation Cycle: $cycle'),
onComplete: () => debugPrint('Animation Completed'),
// 允许链式效果
wrapper: (child, status) {
if (status.isCompleted) {
return LoopTransition(
delay: const Duration(milliseconds: 300),
duration: const Duration(milliseconds: 700),
transition: LoopTransition.shimmer(colors: [
Colors.black87,
Colors.blue,
Colors.black87,
Colors.black87,
]),
child: child,
);
}
return child;
},
// 动画子部件
child: const MyWidget(
text: 'This is the widget that will be animated',
),
)
内置过渡
该包提供了多种内置过渡,可以直接使用:
LoopTransition.fade
: 子部件在动画周期中淡入淡出。LoopTransition.spin
: 子部件围绕中心点旋转。LoopTransition.slide
: 子部件滑动到指定位置。LoopTransition.zoom
: 子部件放大缩小。LoopTransition.shimmer
: 子部件上创建闪烁效果。LoopTransition.shakeX
: 子部件水平震动。LoopTransition.shakeY
: 子部件垂直震动。
自定义过渡
为了获得更多控制,可以使用 LoopTransitionBuilder
定义自己的过渡函数:
final myCustomTransition = (child, animation) {
// 实现你的自定义动画逻辑
return Container(child: child); // 包裹子部件
};
LoopTransition(
transition: myCustomTransition,
child: MyWidget(),
),
示例代码
以下是完整的示例代码:
import 'package:flutter/material.dart';
import 'package:loop_transition/loop_transition.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Loop Transition Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Wrap(
spacing: 20,
children: [
const LoopTransition(
curve: Curves.bounceInOut,
duration: Duration(milliseconds: 1500),
reverse: true,
child: FlutterLogo(size: 64),
),
LoopTransition(
mirror: true,
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 1500),
backwardDuration: const Duration(milliseconds: 500),
transition: LoopTransition.zoom(.5, 1.2),
child: const Icon(
Icons.favorite,
size: 64,
color: Colors.red,
shadows: [
Shadow(
blurRadius: 5.0,
color: Colors.red,
offset: Offset(0, 0),
),
],
),
),
],
),
const SizedBox(height: 20),
const Wrap(
spacing: 20,
children: [
LoopTransition(
duration: Duration(milliseconds: 1500),
transition: LoopTransition.spin,
child: Icon(
Icons.settings,
size: 64,
),
),
PausableTransition(),
LoopTransition(
duration: Duration(milliseconds: 1500),
reverse: true,
transition: LoopTransition.spin,
child: Icon(
Icons.settings,
size: 64,
),
),
],
),
const SizedBox(height: 20),
Wrap(
spacing: 20,
children: [
const LoopTransition(
curve: Curves.bounceOut,
delay: Duration(milliseconds: 1000),
duration: Duration(milliseconds: 700),
transition: LoopTransition.shakeX,
child: Text('Shake Horizontally'),
),
LoopTransition(
curve: Curves.bounceOut,
delay: const Duration(milliseconds: 1000),
duration: const Duration(milliseconds: 700),
transition: LoopTransition.shake(
direction: Axis.vertical,
distance: 7,
),
child: const Text('Shake Vertically'),
),
],
),
const SizedBox(height: 20),
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 20,
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 20,
),
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.circular(15),
),
child: LoopTransition(
curve: Curves.linear,
delay: const Duration(milliseconds: 1000),
duration: const Duration(milliseconds: 900),
transition: LoopTransition.shimmer(
colors: [
Colors.white,
Colors.amber,
Colors.green,
Colors.white,
Colors.white,
],
),
child: DefaultTextStyle.merge(
style:
Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
shadows: [
const Shadow(
blurRadius: 1.0,
color: Colors.white,
offset: Offset(0, 0),
),
],
),
child: IconTheme.merge(
data: const IconThemeData(size: 34),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
children: [
Transform.translate(
offset: const Offset(0, 1.5),
child: const ThreeArrows(),
),
const Text('Slide to unlock'),
],
),
),
),
),
),
const InteractiveThreeArrows(),
],
),
],
),
),
);
}
}
class PausableTransition extends StatefulWidget {
const PausableTransition({super.key});
[@override](/user/override)
State<PausableTransition> createState() => _PausableTransitionState();
}
class _PausableTransitionState extends State<PausableTransition> {
bool paused = false;
void toggle([bool? value]) {
setState(() {
paused = value ?? !paused;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return GestureDetector(
onTap: toggle,
child: MouseRegion(
onEnter: (_) => toggle(true),
onExit: (_) => toggle(false),
child: LoopTransition(
pause: paused,
repeat: 10,
mirror: true,
reverse: true,
onStart: () => debugPrint('Animation Started'),
onPause: () => debugPrint('Animation Paused'),
onContinue: () => debugPrint('Animation Continued'),
onCycle: (cycle) => debugPrint('Animation Cycle: $cycle'),
onComplete: () => debugPrint('Animation Completed'),
duration: const Duration(milliseconds: 1000),
transition: LoopTransition.spin,
wrapper: (child, status) {
if (status.isCompleted) {
return LoopTransition(
pause: paused,
mirror: true,
continuity: false,
delay: const Duration(milliseconds: 300),
duration: const Duration(milliseconds: 700),
backwardDuration: const Duration(milliseconds: 500),
transition: LoopTransition.shimmer(colors: [
Colors.black87,
Colors.blue,
Colors.black87,
Colors.black87,
]),
child: const Icon(
Icons.check,
size: 64,
),
);
}
return child;
},
child: const Icon(
Icons.refresh,
size: 64,
),
),
),
);
}
}
class InteractiveThreeArrows extends StatelessWidget {
const InteractiveThreeArrows({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return LoopTransition(
mirror: true,
curve: Curves.easeInCubic,
delay: const Duration(milliseconds: 300),
duration: const Duration(milliseconds: 900),
backwardDelay: Duration.zero,
transition: LoopTransition.slide(const Offset(0, -.3)),
child: LoopTransition(
curve: Curves.linear,
delay: const Duration(milliseconds: 1000),
duration: const Duration(milliseconds: 900),
transition: LoopTransition.shimmer(
colors: [
Colors.blue,
Colors.white,
Colors.blue,
Colors.blue,
],
end: Alignment.topCenter,
begin: Alignment.bottomCenter,
direction: AxisDirection.up,
),
child: const ThreeArrows(
direction: AxisDirection.up,
size: 32,
),
),
);
}
}
class ThreeArrows extends StatelessWidget {
const ThreeArrows({
super.key,
this.direction = AxisDirection.right,
this.size,
});
final AxisDirection direction;
final double? size;
int get turns {
switch (direction) {
case AxisDirection.down:
return 1;
case AxisDirection.left:
return 2;
case AxisDirection.up:
return 3;
default:
return 0;
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return IconTheme.merge(
data: IconThemeData(
size: size,
shadows: const [
Shadow(
blurRadius: 1.0,
color: Colors.white,
offset: Offset(0, 0),
),
],
),
child: RotatedBox(
quarterTurns: turns,
child: const Wrap(
children: [
Align(
widthFactor: .3,
child: Icon(Icons.keyboard_arrow_right),
),
Align(
widthFactor: .3,
child: Icon(Icons.keyboard_arrow_right),
),
Align(
widthFactor: .3,
child: Icon(Icons.keyboard_arrow_right),
),
],
),
),
);
}
}
更多关于Flutter页面过渡动画插件loop_transition的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter页面过渡动画插件loop_transition的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter应用中使用loop_transition
插件来实现页面过渡动画的一个示例。loop_transition
插件提供了一种循环过渡动画效果,可以让页面切换看起来更加生动和吸引人。
首先,确保你已经在pubspec.yaml
文件中添加了loop_transition
依赖:
dependencies:
flutter:
sdk: flutter
loop_transition: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,我们来看一个完整的示例代码,展示如何使用loop_transition
进行页面过渡动画。
main.dart
import 'package:flutter/material.dart';
import 'package:loop_transition/loop_transition.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
routes: {
'/second': (context) => SecondScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
LoopPageRoute(
builder: (context) => SecondScreen(),
transitionDuration: Duration(seconds: 1),
reverseTransitionDuration: Duration(seconds: 1),
loopDuration: Duration(seconds: 2),
pattern: const [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
),
);
},
child: Text('Go to Second Screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
),
);
}
}
解释
- 依赖引入:在
pubspec.yaml
中添加了loop_transition
依赖。 - 主应用:
MyApp
是一个简单的MaterialApp
,设置了首页为HomeScreen
,并定义了到SecondScreen
的路由。 - 首页:
HomeScreen
包含一个按钮,点击按钮时,使用Navigator.push
方法通过LoopPageRoute
导航到SecondScreen
。 - LoopPageRoute:
builder
:构建目标页面(这里是SecondScreen
)。transitionDuration
:正向过渡动画的持续时间。reverseTransitionDuration
:反向过渡动画的持续时间。loopDuration
:循环动画的总持续时间。pattern
:定义了动画的关键帧,这些值决定了动画在不同时间点的进度。
通过上述代码,当你从HomeScreen
导航到SecondScreen
时,会看到一个循环过渡动画效果。当你点击返回按钮时,也会看到相应的反向过渡动画。
你可以根据需要调整transitionDuration
、reverseTransitionDuration
、loopDuration
和pattern
的值,以达到你想要的动画效果。