我正在为我的 Flutter 项目设计一个 AnimatedContainer,当按下浮动操作按钮时,会以动画方式打开一个窗口。但是,我有一个小问题:当我关闭窗口时,一个对象在右下角出现并消失。我注意到当我删除 AnimatedContainer 中的填充时,这个问题就消失了,但我仍然需要填充。我该如何解决这个问题?
动画容器:
class _ArtiButonuState extends State<ArtiButonu> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return Stack(
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 300),
curve: Curves.bounceIn,
right: MediaQuery.of(context).size.width / 2 - 166,
bottom: MediaQuery.of(context).padding.bottom + 108.0,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 72.0),
decoration: BoxDecoration(
color: Colors.white.withOpacity(_isExpanded ? 0.9 : 0.0),
borderRadius: BorderRadius.circular(10.0),
),
...
我的整个浮动操作按钮代码:
class ArtiButonu extends StatefulWidget {
const ArtiButonu({super.key});
@override
_ArtiButonuState createState() => _ArtiButonuState();
}
class _ArtiButonuState extends State<ArtiButonu> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return Stack(
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 300),
curve: Curves.bounceIn,
right: MediaQuery.of(context).size.width / 2 - 166,
bottom: MediaQuery.of(context).padding.bottom + 108.0,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 72.0),
decoration: BoxDecoration(
color: Colors.white.withOpacity(_isExpanded ? 0.9 : 0.0),
borderRadius: BorderRadius.circular(10.0),
),
child: _isExpanded ? ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: _isExpanded ? 5.0 : 0.0, sigmaY: _isExpanded ? 5.0 : 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildOption(Icons.phone, 'Şoförü Ara'),
_buildOption(Icons.insert_comment, 'Şoföre Mesaj At'),
_buildOption(Icons.phone, 'Hostesi Ara'),
_buildOption(Icons.insert_comment, 'Hostese Mesaj At'),
],
),
),
) : Container(),
),
),
Positioned(
right: MediaQuery.of(context).size.width / 2 - 28,
bottom: MediaQuery.of(context).padding.bottom + 64.0,
child: Column(
children: [
FloatingActionButton(
backgroundColor: _isExpanded ? MyColors.mesajlarProfilTextColor : MyColors.yellow,
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
shape: const CircleBorder(),
elevation: 0,
child: AnimatedCrossFade(
duration: Duration(milliseconds: 300),
firstCurve: Curves.easeInOut,
secondCurve: Curves.easeInOut,
sizeCurve: Curves.easeInOut,
crossFadeState: _isExpanded ? CrossFadeState.showFirst : CrossFadeState.showSecond,
firstChild: const Icon(Icons.clear, color: Colors.white, size: 36.0),
secondChild: const Icon(Icons.add_rounded, color: Colors.white, size: 48.0),
),
),
],
),
),
],
);
}
Widget _buildOption(IconData icon, String label) {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: InkWell(
onTap: () {
print('Butona tıklandı');
},
child: Row(
children: [
FloatingActionButton(
shape: CircleBorder(),
backgroundColor: MyColors.yellow,
onPressed: () {},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: Colors.white),
],
),
),
const SizedBox(
width: 8.0,
),
Text(
label,
style: const TextStyle(
color: MyColors.mesajlarProfilTextColor,
fontFamily: 'Poppins SemiBold',
),
)
],
),
),
);
}
}
您设置动画的方式存在一些问题:
在 AnimatedPositioned() 中,您的位置是用不变的数字定义的(AnimatedPositioned.right 和 AnimatedPositioned.bottom)。如果您希望弹出菜单的位置具有动画效果,则需要以某种方式更改右侧和底部的值。使用小部件的状态是完美的。所以,你可以这么说(将“0”更改为你希望动画开始的任何数字):
动画定位( 持续时间:常量持续时间(毫秒:300), 曲线:Curves.bounceIn, 右:_isExpanded ? MediaQuery.of(context).size.width / 2 - 166 : 0, 底部:_isExpanded ? MediaQuery.of(上下文).padding.bottom + 108.0:0, 子:AnimatedContainer()
AnimatedContainer 小部件仅对其属性进行动画处理。它不会为其子级或其任何子级的后代设置动画Docs。这意味着您的 AnimatedContainer() 唯一的动画就是其背景的不透明度。
还有一点,尽管我现在认为这并不重要。您已经为 AnimatedPosition (Curves.bounceIn) 定义了曲线,但没有为 AnimatedContainer 定义了曲线,这意味着它默认为 Curves.linear)。解决上述问题后,这可能会使动画看起来很奇怪,因为各种效果会有不同的曲线。我建议对两者都使用相同的曲线,除非您特别想要这种效果。
我会解决所有这些问题,然后看看你会剩下什么。我猜你所看到的小盒子是 Container(),它是 _isExpanded = false 之后 AnimatedContainer() 的子级,同时其不透明度正在降低。最后,它消失了,因为不透明度为零。由于 Container() 具有来自 AnimatedContainer() 的填充,因此它具有一定的大小。我认为,这意味着动画完成后容器实际上仍然存在,只是不可见。当你去掉 AnimatedContainer 的填充时,容器就没有大小了,所以你看不到它。 这才是真正的要点:我建议您真正指定您正在寻找的效果,然后重新设计您的小部件以支持该效果。如果您只是希望菜单从窗口底部增长,您可以将 ClipRRect() 与 AnimatedAlign() 子项(或者可能是 AnimatedPosition() 子项)一起使用。这会让你的菜单看起来像是从屏幕下方向上滑动的。当然,有很多不同的选项,它们都有不同的执行方式。
我认为最重要的不是将小部件从 ClipRRect() 切换到 Container(),而是对位置和/或大小进行动画处理以获得您想要的效果。