如何使用 Flutter AnimationController 和 Transform 旋转图像?
How to rotate an image using Flutter AnimationController and Transform?
我有星星 png 图片,我需要使用 Flutter AnimationController 和 Transformer 旋转星星。我找不到图像旋转动画的任何文档或示例。
知道如何使用 Flutter AnimationController 和 Transform 旋转图像吗?
更新:
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 5000),
);
animationController.forward();
animationController.addListener(() {
setState(() {
if (animationController.status == AnimationStatus.completed) {
animationController.repeat();
}
});
});
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
height: 80.0,
width: 80.0,
child: new Image.asset('images/StarLogo.png'),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value,
child: _widget,
);
},
),
);
}
}
这是我旋转图像的例子。我不知道 - 但也许它适合你
AnimationController rotationController;
@override
void initState() {
rotationController = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);
super.initState();
}
//...
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
child: ImgButton(...)
//...
rotationController.forward(from: 0.0); // it starts the animation
UPD - 如何用 Transform.rotate
解决问题
在你的例子中,所有的工作都和你写的完全一样——它将图像从 0.0 旋转到 1.0(它是 AnimationController
的默认参数)。对于整圈,您必须将上部参数设置为 2 * pi
(来自 math
包)
import 'dart:math';
//...
animationController = AnimationController(vsync: this, duration: Duration(seconds: 5), upperBound: pi * 2);
完整示例(空安全):
按“开始”使星形图标旋转,直到您按“停止”。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
duration: const Duration(milliseconds: 5000),
vsync: this,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: Center(
child: Column(
children: <Widget>[
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Icon(Icons.stars),
),
ElevatedButton(
child: Text("go"),
onPressed: () => _controller.forward(),
),
ElevatedButton(
child: Text("reset"),
onPressed: () => _controller.reset(),
),
],
),
),
);
}
}
分步指南:
首先,让您的小部件状态 class 实现 SingleTickerProviderStateMixin
。
其次,定义一个AnimationController
并且不要忘记处理它。如果您还没有使用 null-safe,请删除 late
关键字。
late AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
duration: const Duration(milliseconds: 5000),
vsync: this,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
然后用 RotationTransition
包裹你的 Widget
。
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Icon(Icons.stars),
),
最后,调用 AnimationController
到 start/stop 动画的方法。
- 运行动画一次,使用
.forward
- 循环动画,使用
.repeat
- 立即停止,使用
.stop
- 停止并将其设置回原始旋转,使用
.reset
- 停止并动画到旋转值,使用
.animateTo
这里我一次旋转 3 张图片...保存在资产文件夹中的图片...如果您愿意也可以使用网络图片...我在这里以 3 种速度旋转 3 张图片...
import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';
class SplashScreen extends StatefulWidget {
_SplashScreen createState() => new _SplashScreen();
}
class _SplashScreen extends State<StatefulWidget>
with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 5),
);
animationController.repeat();
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/splash_circle3.png'))),
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/splash_circle2.png'))),
child: new AnimatedBuilder(
animation: animationController,
child: Container(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/splash_circle1.png'))),
)),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 4,
child: _widget,
);
}),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 5,
child: _widget,
);
},
),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 6,
child: _widget,
);
},
),
);
}
}
这里我将动画生成器放在 Stack 中。然后你可以动画图像向右旋转(顺时针)和向左旋转(逆时针)。
import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';
class SplashScreen extends StatefulWidget {
_SplashScreen createState() => new _SplashScreen();
}
class _SplashScreen extends State<StatefulWidget>
with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 5),
);
animationController.repeat();
}
@override
Widget build(BuildContext context)
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new Stack(children: <Widget>[
new AnimatedBuilder(
animation: animationController,
child :Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle3.png'),fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 10,
child: _widget,
);
},
),
new AnimatedBuilder(
animation: animationController,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle2.png'),fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: -animationController.value * 10,
child: _widget,
);
},
),
new AnimatedBuilder(
animation: animationController,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle1.png'), fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 10,
child: _widget,
);
}),
],),
);
}
}
屏幕截图(空安全)
完整代码:
import 'dart:math' as math;
class _FooPageState extends State<FooPage> with SingleTickerProviderStateMixin{
late final AnimationController _controller = AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
child: FlutterLogo(size: 200),
),
),
);
}
}
_controller = AnimationController(duration: const Duration(seconds: 3), vsync: this);
_animation = Tween(begin: 0.0, end: 250.0).animate(_controller)
..addListener(() {
setState(() {});
})
..addStatusListener((state) {
if (state == AnimationStatus.completed) {
print("complete");
}
});
_controller.forward();
new Future.delayed(
const Duration(seconds: 5),
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignScreen()),
));
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 5000),
);
animationController.repeat();
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: RotationTransition(
child: Icon(Icons.refresh),
turns: controller,
)
);
}
}
full example just call
ImageAnimateRotate( your widget )
class ImageAnimateRotate extends StatefulWidget {
final Widget child;
const ImageAnimateRotate({Key? key, required this.child}) : super(key: key);
@override
_ImageAnimateRotateState createState() => _ImageAnimateRotateState();
}
class _ImageAnimateRotateState extends State<ImageAnimateRotate> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 20))..repeat();
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
child: widget.child,
),
);
}
}
Flutter 也有小部件 AnimatedRotation (docs) 这使得旋转东西更容易。
你只需要一个double来设置旋转的状态。它以旋转的百分比工作,如果将其转换为度数,它将是 0.0 = 0deg
、1.0 = 360deg
double turns = 0.0;
AnimatedRotation(
duration: const Duration(milliseconds: 500),
turns: turns,
child: const Icon(Icons.refresh),
)
旋转只需要更新状态,Flutter会自动执行动画
void _changeRotation() {
setState(() => turns += 1.0 / 8.0);
}
从 Flutter 文档中获取的用于旋转 flutter Logo 的完整示例
class LogoRotate extends StatefulWidget {
const LogoRotate({Key? key}) : super(key: key);
@override
State<LogoRotate> createState() => LogoRotateState();
}
class LogoRotateState extends State<LogoRotate> {
double turns = 0.0;
void _changeRotation() {
setState(() => turns += 1.0 / 8.0);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _changeRotation,
child: const Text('Rotate Logo'),
),
Padding(
padding: const EdgeInsets.all(50),
child: AnimatedRotation(
turns: turns,
duration: const Duration(seconds: 1),
child: const FlutterLogo(),
),
),
],
);
}
}
我有星星 png 图片,我需要使用 Flutter AnimationController 和 Transformer 旋转星星。我找不到图像旋转动画的任何文档或示例。
知道如何使用 Flutter AnimationController 和 Transform 旋转图像吗?
更新:
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 5000),
);
animationController.forward();
animationController.addListener(() {
setState(() {
if (animationController.status == AnimationStatus.completed) {
animationController.repeat();
}
});
});
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
height: 80.0,
width: 80.0,
child: new Image.asset('images/StarLogo.png'),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value,
child: _widget,
);
},
),
);
}
}
这是我旋转图像的例子。我不知道 - 但也许它适合你
AnimationController rotationController;
@override
void initState() {
rotationController = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);
super.initState();
}
//...
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
child: ImgButton(...)
//...
rotationController.forward(from: 0.0); // it starts the animation
UPD - 如何用 Transform.rotate
在你的例子中,所有的工作都和你写的完全一样——它将图像从 0.0 旋转到 1.0(它是 AnimationController
的默认参数)。对于整圈,您必须将上部参数设置为 2 * pi
(来自 math
包)
import 'dart:math';
//...
animationController = AnimationController(vsync: this, duration: Duration(seconds: 5), upperBound: pi * 2);
完整示例(空安全):
按“开始”使星形图标旋转,直到您按“停止”。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
duration: const Duration(milliseconds: 5000),
vsync: this,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: Center(
child: Column(
children: <Widget>[
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Icon(Icons.stars),
),
ElevatedButton(
child: Text("go"),
onPressed: () => _controller.forward(),
),
ElevatedButton(
child: Text("reset"),
onPressed: () => _controller.reset(),
),
],
),
),
);
}
}
分步指南:
首先,让您的小部件状态 class 实现 SingleTickerProviderStateMixin
。
其次,定义一个AnimationController
并且不要忘记处理它。如果您还没有使用 null-safe,请删除 late
关键字。
late AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
duration: const Duration(milliseconds: 5000),
vsync: this,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
然后用 RotationTransition
包裹你的 Widget
。
RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Icon(Icons.stars),
),
最后,调用 AnimationController
到 start/stop 动画的方法。
- 运行动画一次,使用
.forward
- 循环动画,使用
.repeat
- 立即停止,使用
.stop
- 停止并将其设置回原始旋转,使用
.reset
- 停止并动画到旋转值,使用
.animateTo
这里我一次旋转 3 张图片...保存在资产文件夹中的图片...如果您愿意也可以使用网络图片...我在这里以 3 种速度旋转 3 张图片...
import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';
class SplashScreen extends StatefulWidget {
_SplashScreen createState() => new _SplashScreen();
}
class _SplashScreen extends State<StatefulWidget>
with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 5),
);
animationController.repeat();
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/splash_circle3.png'))),
child: new AnimatedBuilder(
animation: animationController,
child: new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/splash_circle2.png'))),
child: new AnimatedBuilder(
animation: animationController,
child: Container(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/splash_circle1.png'))),
)),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 4,
child: _widget,
);
}),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 5,
child: _widget,
);
},
),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 6,
child: _widget,
);
},
),
);
}
}
这里我将动画生成器放在 Stack 中。然后你可以动画图像向右旋转(顺时针)和向左旋转(逆时针)。
import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';
class SplashScreen extends StatefulWidget {
_SplashScreen createState() => new _SplashScreen();
}
class _SplashScreen extends State<StatefulWidget>
with SingleTickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 5),
);
animationController.repeat();
}
@override
Widget build(BuildContext context)
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: new Stack(children: <Widget>[
new AnimatedBuilder(
animation: animationController,
child :Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle3.png'),fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 10,
child: _widget,
);
},
),
new AnimatedBuilder(
animation: animationController,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle2.png'),fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: -animationController.value * 10,
child: _widget,
);
},
),
new AnimatedBuilder(
animation: animationController,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage('assets/images/splash_circle1.png'), fit: BoxFit.cover)),
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 10,
child: _widget,
);
}),
],),
);
}
}
屏幕截图(空安全)
完整代码:
import 'dart:math' as math;
class _FooPageState extends State<FooPage> with SingleTickerProviderStateMixin{
late final AnimationController _controller = AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
child: FlutterLogo(size: 200),
),
),
);
}
}
_controller = AnimationController(duration: const Duration(seconds: 3), vsync: this); _animation = Tween(begin: 0.0, end: 250.0).animate(_controller) ..addListener(() { setState(() {}); }) ..addStatusListener((state) { if (state == AnimationStatus.completed) { print("complete"); } }); _controller.forward(); new Future.delayed( const Duration(seconds: 5), () => Navigator.push( context, MaterialPageRoute(builder: (context) => SignScreen()), ));
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 5000),
);
animationController.repeat();
}
@override
Widget build(BuildContext context) {
return new Container(
alignment: Alignment.center,
color: Colors.white,
child: RotationTransition(
child: Icon(Icons.refresh),
turns: controller,
)
);
}
}
full example just call ImageAnimateRotate( your widget )
class ImageAnimateRotate extends StatefulWidget {
final Widget child;
const ImageAnimateRotate({Key? key, required this.child}) : super(key: key);
@override
_ImageAnimateRotateState createState() => _ImageAnimateRotateState();
}
class _ImageAnimateRotateState extends State<ImageAnimateRotate> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 20))..repeat();
}
@override
Widget build(BuildContext context) {
return Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, child) {
return Transform.rotate(
angle: _controller.value * 2 * math.pi,
child: child,
);
},
child: widget.child,
),
);
}
}
Flutter 也有小部件 AnimatedRotation (docs) 这使得旋转东西更容易。
你只需要一个double来设置旋转的状态。它以旋转的百分比工作,如果将其转换为度数,它将是 0.0 = 0deg
、1.0 = 360deg
double turns = 0.0;
AnimatedRotation(
duration: const Duration(milliseconds: 500),
turns: turns,
child: const Icon(Icons.refresh),
)
旋转只需要更新状态,Flutter会自动执行动画
void _changeRotation() {
setState(() => turns += 1.0 / 8.0);
}
从 Flutter 文档中获取的用于旋转 flutter Logo 的完整示例
class LogoRotate extends StatefulWidget {
const LogoRotate({Key? key}) : super(key: key);
@override
State<LogoRotate> createState() => LogoRotateState();
}
class LogoRotateState extends State<LogoRotate> {
double turns = 0.0;
void _changeRotation() {
setState(() => turns += 1.0 / 8.0);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _changeRotation,
child: const Text('Rotate Logo'),
),
Padding(
padding: const EdgeInsets.all(50),
child: AnimatedRotation(
turns: turns,
duration: const Duration(seconds: 1),
child: const FlutterLogo(),
),
),
],
);
}
}