我创建了一个分为两个gridviews的列表,因为我只希望显示前3个项目,并带有一个按钮以便以后显示更多项目。我不知道这样做是否正确,但对我有用。
但是显示和隐藏项目的方法非常激进,因此我设法使动画出现,但我无法使其消失。然后q第一次出现,即使我隐藏并使动画再次出现,它也不再起作用。
我想知道如何使该动画正常工作,以及我是否以这种方式走上正轨,或者是否应该与众不同?
此gif显示了当前的动画效果。
我将代码放在dartpad中以便于查看:
https://dartpad.dev/526a5719cae7d8be0772f1e87ef02ced
以及下面的完整代码:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
@override
_MyWidget createState() => _MyWidget();
}
class _MyWidget extends State<MyWidget> with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 800),
);
_animation = Tween(
begin: 0.0,
end: 1.0,
).animate(_animationController);
super.initState();
}
@override
dispose() {
_animationController.dispose();
super.dispose();
}
var _isExpanded = false;
_toggleExpanded() {
_animationController.forward();
setState(() {
_isExpanded = !_isExpanded;
});
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(children: <Widget>[
GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.0,
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
),
itemCount: 3,
itemBuilder: (context, index) {
return ItemCategory(
title: "Teste $index",
icon: Icons.apps,
coloritem: Colors.deepPurple,
onpressbtn: "teste $index",
);
},
),
Visibility(
visible: _isExpanded,
child: FadeTransition(
opacity: _animation,
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.0,
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
),
itemCount: 5,
itemBuilder: (context, index) {
var indx = index+3;
return ItemCategory(
title: "Teste $indx",
icon: Icons.apps,
coloritem: Colors.deepPurple,
onpressbtn: "teste $index",
);
},
),
),
),
IconButton(
icon: _isExpanded
? Icon(Icons.keyboard_arrow_up)
: Icon(Icons.keyboard_arrow_down),
tooltip: 'Open More options',
onPressed: _toggleExpanded,
),
]),
);
}
}
// These are sample items to be displayed in the gridview.
class ItemCategory extends StatelessWidget {
ItemCategory({this.title, this.icon, this.coloritem, this.onpressbtn});
final String title;
final IconData icon;
final MaterialColor coloritem;
final String onpressbtn;
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8.5),
child: InkWell(
onTap: () {},
splashColor: Colors.amber,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
icon,
size: 70.0,
color: coloritem,
),
Text(title, style: new TextStyle(fontSize: 17.0))
],
),
),
),
);
}
}
答案 0 :(得分:2)
将_animationController.reset()
添加到_toggleExpanded()
并将Future.delayed
设置为_isExpanded
时使用false
:
_toggleExpanded() {
if (_isExpanded) {
_animationController.reverse();
Future.delayed(Duration(milliseconds: 800), () => setState(() {
_isExpanded = false;
}));
}
else {
_animationController.reset();
_animationController.forward();
setState(() {
_isExpanded = true;
});
}
}
答案 1 :(得分:1)
正向动画第一次工作是因为它从0开始并变为1。在随后的时间,它仍为1,因此启动控制器将使其立即停止,因为它从结尾开始值。您可以通过调用controller.reset()
或将起始值传递到forward
(即controller.forward(from: 0)
)来解决此问题。
要使反向动画正常工作,还需要有一个调用controller.reverse()
的方法。这将导致动画反向播放,因此您需要将动画设置为0。像forward
一样,您还需要告诉控制器从哪里开始使用controller.reverse(from: 1)
进行动画制作。
但是,您将遇到另一个问题。如果仅在调用_isExpanded
的同时将reverse
设置为false,则将播放淡入淡出的动画,但可折叠面板将关闭,从而无法看到它。而不是根据按钮的按下来设置面板的可见性,而应基于动画的当前状态。通过听控制器的动画状态更改,如果动画值不是0,则可以使面板可见。
以下是建议采取的措施:
class _MyWidget extends State<MyWidget> with SingleTickerProviderStateMixin {
AnimationStatus _currentStatus = AnimationStatus.dismissed;
...
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 800),
)..addStatusListener((status) {
setState(() => _currentStatus = status);
});
...
}
...
_toggleExpand() {
_animationController.forward(from: 0);
setState(() {
_isExpanded = true;
});
}
_toggleCollapse() {
_animationController.reverse(from: 1);
_isExpanded = false;
}
...
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(children: <Widget>[
...
Visibility(
visible: _currentStatus != AnimationStatus.dismissed,
...
),
IconButton(
...
onPressed: _isExpanded ? _toggleCollapse : _toggleExpand,
),
]),
);
}
}