【问题标题】:Flutter Animation Not Working颤振动画不起作用
【发布时间】:2018-11-17 12:29:17
【问题描述】:

我正在尝试在 Flutter 中制作一个径向菜单,并希望我的菜单按钮每次按下时都有一个旋转动画。我在 Youtube 上关注了 TensorProgramming 的 Flutter 动画基础教程,但由于某种原因我的动画无法正常工作。下面我包含了我的 RadialMenuWidget 的代码。

我已经正确处理了动画控制器,使用 SingleTickerProviderStateMixin 扩展了小部件的状态。 P.S 我在模拟器上运行,当我热重载时,图标的旋转有时会发生变化。

我们将不胜感激!

import 'package:flutter/material.dart';
import 'package:savings/utils/colors.dart';
import 'package:savings/widgets/themed_radial_menu_item.dart';

class CustomThemedRadialMenu extends StatefulWidget {
final List<CustomThemedRadialMenuItem> items;

 CustomThemedRadialMenu({@required this.items});

@override
_CustomThemedRadialMenuState createState() => 
_CustomThemedRadialMenuState();
}

class _CustomThemedRadialMenuState extends State<CustomThemedRadialMenu>
   with SingleTickerProviderStateMixin {
   Animation animationOpenClose;
   AnimationController animationControllerOpenClose;

 bool isOpen;

@override
void initState() {
  isOpen = false;

  animationControllerOpenClose =
      AnimationController(duration: new Duration(seconds: 5), vsync: this);

  animationOpenClose =
      Tween(begin: 0.0, end: 360.0).animate(animationControllerOpenClose)
        ..addListener(() {
          setState(() {});
        });

  animationControllerOpenClose.repeat();

  super.initState();
  }

 @override
 Widget build(BuildContext context) {
  ///A list of the items and the center menu button
  final List<Widget> menuContents = <Widget>[];

 for (int i = 0; i < widget.items.length; i++) {
   ///Menu items
   menuContents.add(widget.items[1]);

    ///Menu Close/Open button
    menuContents.add(new InkWell(
      onTap: () {},
      child: Container(
       padding: new EdgeInsets.all(10.0),
        decoration: new BoxDecoration(
           color: Colors.white,
          border: new Border.all(color: darkHeadingsTextColor),
          shape: BoxShape.circle,
        ),
        child: new Transform.rotate(
            angle: animationControllerOpenClose.value,
            child: isOpen ? new Icon(Icons.clear) : new Icon(Icons.menu)),
      ),
    ));
  }

  return new Stack(
    alignment: Alignment.center,
   children: menuContents,
 );
}

@override
void dispose() {
  animationControllerOpenClose.dispose();

  super.dispose();
 }

closeMenu() {
  animationControllerOpenClose.forward();
  setState(() {
    isOpen = false;
  });

  print("RadialMenu Closed");
}

openMenu() {
  animationControllerOpenClose.forward();
  setState(() {
    isOpen = true;
  });

 print("RadialMenu Opened");
}
}

【问题讨论】:

    标签: dart flutter flutter-animation


    【解决方案1】:

    您的操作存在一些问题。但是一个快速的 FYI - 如果你清理你的代码并提出一个封装的问题,人们更有可能帮助你。这将需要删除任何未包含的类,最好发布一个可以粘贴到单个文件中并按原样运行的解决方案。

    话虽如此,我已经实现了我认为您正在尝试做的事情。我已经删除了你在其中的一些东西,以便它实际构建,所以你需要重新添加它们。

    您遇到的主要问题如下:

    1. 在监听器中设置状态

      ..addListener(() {
        setState(() {});
      });
      

    这并不理想,因为它会强制整个小部件重建动画的每一个刻度。对于不是很基本的小部件,这将导致严重的性能问题。请改用AnimatedBuilder。或者,如果您正在寻找动画结束的时间,请使用 ..addStateListener

    1. 角度以弧度表示。我没有费心为 Pi 常数导入数学,但您可能应该这样做。

    2. 你有一个实际上没有调用 openMenucloseMenu 的 on-tap,所以它肯定不会做任何事情 =D。

    3. 您将动画控制器设置为重复。这意味着它将永远持续下去。

    4. 您没有向animationControllerOpenClose.forward 调用传递任何内容。这意味着它将从当前所在的任何位置动画到 1.0 状态,即使那已经是 1.0。我刚刚传入 0,但您可能想要围绕打开/关闭做一些事情(如果用户在动画或其他情况下点击)。

    5. (切线问题)您似乎在每个菜单小部件之后添加了一个新的菜单打开/关闭按钮。这可能是您想要做的,但我猜您只想添加一个。

    无论如何,这是一个有效的例子。每次点击时,它都会更改图标然后旋转。

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: "Spinnig Menu",
          theme: ThemeData(
            primaryColor: Colors.red,
          ),
          home: new Scaffold(
            body: new SafeArea(
              child: new Column(
                children: <Widget>[new CustomThemedRadialMenu()],
              ),
            ),
          ),
        );
      }
    }
    
    class CustomThemedRadialMenu extends StatefulWidget {
    
      @override
      _CustomThemedRadialMenuState createState() => _CustomThemedRadialMenuState();
    }
    
    class _CustomThemedRadialMenuState extends State<CustomThemedRadialMenu> with SingleTickerProviderStateMixin {
      Animation animationOpenClose;
      AnimationController animationControllerOpenClose;
    
      bool isOpen;
    
      @override
      void initState() {
        isOpen = false;
        animationControllerOpenClose = AnimationController(duration: new Duration(seconds: 5), vsync: this);
        animationOpenClose = Tween(begin: 0.0, end: 3.14159 * 2).animate(animationControllerOpenClose);
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        ///A list of the items and the center menu button
        final List<Widget> menuContents = <Widget>[];
    
        ///Menu Close/Open button
        menuContents.add(new InkWell(
          onTap: () {
            if (isOpen) {
              closeMenu();
            } else {
              openMenu();
            }
          },
          child: Container(
              padding: new EdgeInsets.all(10.0),
              decoration: new BoxDecoration(
                color: Colors.white,
                border: new Border.all(color: Colors.black38),
                shape: BoxShape.circle,
              ),
              child: new AnimatedBuilder(
                animation: animationControllerOpenClose,
                builder: (context, child) {
                  return new Transform.rotate(angle: animationOpenClose.value, child: child);
                },
                child: isOpen ? new Icon(Icons.clear) : new Icon(Icons.menu),
              )),
        ));
    
        return new Stack(
          alignment: Alignment.center,
          children: menuContents,
        );
      }
    
      @override
      void dispose() {
        animationControllerOpenClose.dispose();
    
        super.dispose();
      }
    
      closeMenu() {
        animationControllerOpenClose.forward(from: 0.0);
        setState(() {
          isOpen = false;
        });
    
        print("RadialMenu Closed");
      }
    
      openMenu() {
        animationControllerOpenClose.forward(from: 0.0);
        setState(() {
          isOpen = true;
        });
    
        print("RadialMenu Opened");
      }
    }
    

    值得注意的是,我在 AnimatedBuilder 的构建函数中构建了尽可能少的小部件。那里构建的越少,性能就越好。因为图标本身不会随着旋转而改变,所以您可以简单地将其作为子项传入。

    我猜这可能接下来会出现,所以仅供参考 - 您可以使用动画交叉淡入淡出小部件在图标之间进行转换(只需将其放入 AnimatedBuilder 的孩子):

    new AnimatedCrossFade(
                firstChild: new Icon(Icons.clear),
                secondChild: new Icon(Icons.menu),
                crossFadeState: isOpen ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                duration: Duration(milliseconds: 300)),
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-15
      • 2019-05-01
      • 2021-06-18
      • 1970-01-01
      • 2021-05-25
      • 2021-02-20
      • 2021-04-04
      • 1970-01-01
      相关资源
      最近更新 更多