我从https://medium.com/flutter-community/flutter-working-with-animatedsize-35253ff8f16a那里获得了以下代码
它使用的是AnimatedSize,但是动画仅在容器展开时起作用,而在容器回缩时不起作用。这是默认行为吗?我想同时扩大和震撼地制作动画。
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
double _height = 80.0;
double _width = 80.0;
var _color = Colors.blue;
bool _resized = false;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedSize(
curve: Curves.easeIn,
vsync: this,
duration: new Duration(seconds: 1),
child: new GestureDetector(
onTap: () {
setState(() {
if (_resized) {
_resized = false;
_color = Colors.blue;
_height = 80.0;
_width = 80.0;
} else {
_resized = true;
_color = Colors.blue;
_height = 320.0;
_width = 320.0;
}
});
},
child: new Container(
width: _width,
height: _height,
color: _color,
),
),
),
],
),
),
);
}
}
答案 0 :(得分:3)
AnimatedContainer不允许宽度或高度为null,这是一个问题。另外,您无法指定对齐方式。两者在处理文本时都很有用。
我使用带有动画控制器的ClipRect修复了此问题。在下面的动画中,您可以在收尾反弹的中心线左侧看到单词“ laboris”。这表明在关闭容器期间,文本正居中,只需注意“ laboris”即可。
我创建了一个AnimatedClipRect小部件类,您可以轻松实现自己。您可以指定对齐方式,曲线,持续时间,以及是否需要水平和/或垂直动画。现在,它假设您只想完全关闭或打开它:
class AnimatedClipRect extends StatefulWidget {
@override
_AnimatedClipRectState createState() => _AnimatedClipRectState();
final Widget child;
final bool open;
final bool horizontalAnimation;
final bool verticalAnimation;
final Alignment alignment;
final Duration duration;
final Duration reverseDuration;
final Curve curve;
final Curve reverseCurve;
///The behavior of the controller when [AccessibilityFeatures.disableAnimations] is true.
final AnimationBehavior animationBehavior;
AnimatedClipRect({
this.child,
this.open,
this.horizontalAnimation = true,
this.verticalAnimation = true,
this.alignment = Alignment.center,
this.duration,
this.reverseDuration,
this.curve = Curves.linear,
this.reverseCurve,
this.animationBehavior = AnimationBehavior.normal,
});
}
class _AnimatedClipRectState extends State<AnimatedClipRect> with TickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;
@override
void initState() {
_animationController = AnimationController(
duration: widget.duration ?? const Duration(milliseconds: 500),
reverseDuration: widget.reverseDuration ?? (widget.duration ?? const Duration(milliseconds: 500)),
vsync: this,
value: widget.open ? 1.0 : 0.0,
animationBehavior: widget.animationBehavior);
_animation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: _animationController,
curve: widget.curve,
reverseCurve: widget.reverseCurve ?? widget.curve,
));
super.initState();
}
@override
Widget build(BuildContext context) {
widget.open ? _animationController.forward() : _animationController.reverse();
return ClipRect(
child: AnimatedBuilder(
animation: _animationController,
builder: (_, child) {
return Align(
alignment: widget.alignment,
heightFactor: widget.verticalAnimation ? _animation.value : 1.0,
widthFactor: widget.horizontalAnimation ? _animation.value : 1.0,
child: child,
);
},
child: widget.child,
),
);
}
}
基本用法示例,将要设置动画的任何内容放入其子级:
// declare bool _open somewhere
Column(
children: <Widget>[
AnimatedClipRect(
open: _open,
horizontalAnimation: false,
verticalAnimation: true,
alignment: Alignment.center,
duration: Duration(milliseconds: 1000),
curve: Curves.bounceOut,
reverseCurve: Curves.bounceIn,
child: Container(
color: Colors.lightGreenAccent,
padding: EdgeInsets.all(8),
child: Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'),
),
),
RaisedButton(
child: Text("open/close"),
onPressed: () {
setState(() => _open ^= true);
}),
],
)
您可以看到,您只需更改_open并执行setState((){})即可触发动画。
答案 1 :(得分:1)
AnimatedContainer
是您所需要的,不需要AnimatedSize
。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
double _height = 80.0;
double _width = 80.0;
var _color = Colors.blue;
bool _resized = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
if (_resized) {
_resized = false;
_color = Colors.blue;
_height = 80.0;
_width = 80.0;
} else {
_resized = true;
_color = Colors.blue;
_height = 320.0;
_width = 320.0;
}
});
},
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: _width,
height: _height,
color: _color,
),
),
],
),
),
);
}
}
或者,如果您需要AnimatedSize
,则可以添加一个颜色为AnimatedSize
的父容器。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
double _height = 320.0;
double _width = 320.0;
var _color = Colors.blue;
bool _resized = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
if (_resized) {
_resized = false;
_color = Colors.blue;
_height = 80.0;
_width = 80.0;
} else {
_resized = true;
_color = Colors.blue;
_height = 320.0;
_width = 320.0;
}
});
},
child: Container(
color: _color,
child: AnimatedSize(
curve: Curves.easeIn,
vsync: this,
duration: Duration(seconds: 1),
child: Container(
width: _width,
height: _height,
),
),
),
),
),
);
}
}
答案 2 :(得分:0)
Animated Size 给了我和你一样的问题,但后来我查看了 AnimatedCrossFade 的源代码,它使用了 Animated Size 并且它在收缩和扩展时都使用了动画大小。使用 LayoutBuilder 作为 AnimatedSize 的孩子,并将实际的孩子放在 LayoutBuilder 中。我不确定它为什么会起作用,但这就是 AnimatedCrossFade 的情况。