动画容器填充问题

问题描述 投票:0回答:1

我正在为我的 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',
              ),
            )
          ],
        ),
      ),
    );
  }
}
flutter flutter-animation
1个回答
0
投票

您设置动画的方式存在一些问题:

  • 在 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(),而是对位置和/或大小进行动画处理以获得您想要的效果。

© www.soinside.com 2019 - 2024. All rights reserved.