如何"undispose" 动画控制器进行复用?
How to "undispose" animation controller for reuse?
我是 Flutter 的新手,在使用生命周期方法和动画控制器时遇到了一些麻烦。
当我按下底部按钮时它开始播放动画,当我按下中间的圆圈时它停止动画,如果我再次按下底部按钮我得到错误:
AnimationController.stop() 在 AnimationController.dispose() 之后调用
调用 dispose 后不应使用 AnimationController 方法。
'package:flutter/src/animation/animation_controller.dart':
断言失败:第 767 行 pos 7:'_ticker != null'
我希望动画重新开始播放。感谢您的任何建议!
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'model/app_state_model.dart';
import 'dart:developer' as developer;
import 'package:flutter_spinkit/flutter_spinkit.dart';
class ProductListTab extends StatefulWidget {
@override
_ProductListTabState createState() => _ProductListTabState();
}
class _ProductListTabState extends State<ProductListTab>
with SingleTickerProviderStateMixin {
var _isActive = true;
var _time = " ";
var _resultBox;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 3,
child: Container(
color: Colors.lightBlue,
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Align(
alignment: Alignment(0, .6),
child: Container(
width: 150,
height: 150,
child: OutlinedButton(
//elevation: 0.0,
style: OutlinedButton.styleFrom(
shape: CircleBorder(),
backgroundColor: Colors.blue),
onPressed: () {
setState(() {
_time = "999";
});
},
child: AnimatedSwitcher(
duration: Duration(seconds: 1),
child: ResultBox(time: _time),
))),
)),
)),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(30),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CupertinoButton(
child: Text(_isActive ? 'Cancel' : 'Ready'),
onPressed: () {
setState(() {
_isActive = !_isActive;
_time = null;
});
},
color: Colors.amber,
)
],
),
),
)
],
);
}
}
class ResultBox extends StatefulWidget {
final String time;
const ResultBox({
String this.time,
Key key,
}) : super(key: key);
@override
_ResultBoxState createState() => _ResultBoxState();
}
class _ResultBoxState extends State<ResultBox>
with SingleTickerProviderStateMixin {
AnimationController _controller;
void initState() {
this._controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
_controller.reset();
}
Widget build(BuildContext context) {
var _resultRow;
if (widget.time != null) {
_resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(
widget.time,
style: TextStyle(color: Colors.white, fontSize: 50),
),
Text(
"ms",
style: TextStyle(color: Colors.white, fontSize: 20),
),
]);
} else {
_resultRow = SpinKitWave(color: Colors.white, controller: _controller);
}
return FittedBox(
fit: BoxFit.fitWidth,
child: _resultRow,
);
}
Widget dispose() {
this._controller.dispose();
}
}
如果您查看您在评论中发送的 SpinkitWave class:
https://github.com/jogboms/flutter_spinkit/blob/master/lib/src/wave.dart
你会看到下面是它的initState方法:
@override
void initState() {
super.initState();
_controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration))..repeat();
}
这是在说,如果用户传入了一个 AnimationController 作为参数,则使用该 AnimationController,如果没有则创建一个新的 AnimationController 并使用用户传入的持续时间。因此,如果您需要 AnimationController 是为了控制 SpinKitWave 小部件,那么我建议您最好将持续时间传递给它,然后让它在内部管理 AnimationController。即使用以下创建小部件。
// As you no longer need to handle the state of the AnimationController you can
// convert the ResultBox into a StatelessWidget
class ResultBox extends StatelessWidget {
final String time;
const ResultBox({
this.time,
Key key,
}) : super(key: key);
Widget build(BuildContext context) {
var _resultRow;
if (widget.time != null) {
_resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(
widget.time,
style: TextStyle(color: Colors.white, fontSize: 50),
),
Text(
"ms",
style: TextStyle(color: Colors.white, fontSize: 20),
),
]);
} else {
// The controller argument has been removed here and the duration
// argument added
_resultRow = SpinKitWave(color: Colors.white, duration: const Duration(seconds: 1);
}
return FittedBox(
fit: BoxFit.fitWidth,
child: _resultRow,
);
}
}
我是 Flutter 的新手,在使用生命周期方法和动画控制器时遇到了一些麻烦。
当我按下底部按钮时它开始播放动画,当我按下中间的圆圈时它停止动画,如果我再次按下底部按钮我得到错误:
AnimationController.stop() 在 AnimationController.dispose() 之后调用 调用 dispose 后不应使用 AnimationController 方法。 'package:flutter/src/animation/animation_controller.dart': 断言失败:第 767 行 pos 7:'_ticker != null'
我希望动画重新开始播放。感谢您的任何建议!
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'model/app_state_model.dart';
import 'dart:developer' as developer;
import 'package:flutter_spinkit/flutter_spinkit.dart';
class ProductListTab extends StatefulWidget {
@override
_ProductListTabState createState() => _ProductListTabState();
}
class _ProductListTabState extends State<ProductListTab>
with SingleTickerProviderStateMixin {
var _isActive = true;
var _time = " ";
var _resultBox;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 3,
child: Container(
color: Colors.lightBlue,
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Align(
alignment: Alignment(0, .6),
child: Container(
width: 150,
height: 150,
child: OutlinedButton(
//elevation: 0.0,
style: OutlinedButton.styleFrom(
shape: CircleBorder(),
backgroundColor: Colors.blue),
onPressed: () {
setState(() {
_time = "999";
});
},
child: AnimatedSwitcher(
duration: Duration(seconds: 1),
child: ResultBox(time: _time),
))),
)),
)),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(30),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CupertinoButton(
child: Text(_isActive ? 'Cancel' : 'Ready'),
onPressed: () {
setState(() {
_isActive = !_isActive;
_time = null;
});
},
color: Colors.amber,
)
],
),
),
)
],
);
}
}
class ResultBox extends StatefulWidget {
final String time;
const ResultBox({
String this.time,
Key key,
}) : super(key: key);
@override
_ResultBoxState createState() => _ResultBoxState();
}
class _ResultBoxState extends State<ResultBox>
with SingleTickerProviderStateMixin {
AnimationController _controller;
void initState() {
this._controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
_controller.reset();
}
Widget build(BuildContext context) {
var _resultRow;
if (widget.time != null) {
_resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(
widget.time,
style: TextStyle(color: Colors.white, fontSize: 50),
),
Text(
"ms",
style: TextStyle(color: Colors.white, fontSize: 20),
),
]);
} else {
_resultRow = SpinKitWave(color: Colors.white, controller: _controller);
}
return FittedBox(
fit: BoxFit.fitWidth,
child: _resultRow,
);
}
Widget dispose() {
this._controller.dispose();
}
}
如果您查看您在评论中发送的 SpinkitWave class: https://github.com/jogboms/flutter_spinkit/blob/master/lib/src/wave.dart
你会看到下面是它的initState方法:
@override
void initState() {
super.initState();
_controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration))..repeat();
}
这是在说,如果用户传入了一个 AnimationController 作为参数,则使用该 AnimationController,如果没有则创建一个新的 AnimationController 并使用用户传入的持续时间。因此,如果您需要 AnimationController 是为了控制 SpinKitWave 小部件,那么我建议您最好将持续时间传递给它,然后让它在内部管理 AnimationController。即使用以下创建小部件。
// As you no longer need to handle the state of the AnimationController you can
// convert the ResultBox into a StatelessWidget
class ResultBox extends StatelessWidget {
final String time;
const ResultBox({
this.time,
Key key,
}) : super(key: key);
Widget build(BuildContext context) {
var _resultRow;
if (widget.time != null) {
_resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Text(
widget.time,
style: TextStyle(color: Colors.white, fontSize: 50),
),
Text(
"ms",
style: TextStyle(color: Colors.white, fontSize: 20),
),
]);
} else {
// The controller argument has been removed here and the duration
// argument added
_resultRow = SpinKitWave(color: Colors.white, duration: const Duration(seconds: 1);
}
return FittedBox(
fit: BoxFit.fitWidth,
child: _resultRow,
);
}
}