颤动动画不起作用

时间:2018-06-07 14:27:39

标签: dart flutter flutter-animation

我正在尝试在Flutter中创建一个放射状菜单,并希望我的菜单按钮每次按下时都有一个旋转动画。我跟随TensorProgramming在Youtube上关于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");
}
}

1 个答案:

答案 0 :(得分:7)

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

话虽如此,我已经实施了我认为你想要做的事情。我删除了你在那里的一些东西,以便它实际构建,所以你需要重新添加它们。

您遇到的主要问题如下:

  1. 侦听器中的SetState

    ..addListener(() {
      setState(() {});
    });
    
  2. 这并不理想,因为它会强制整个小部件重建动画的每个刻度。这将导致非常基本的小部件出现严重的性能问题。请改用AnimatedBuilder。或者,如果您正在寻找动画结束时使用..addStateListener

    1. 角度在弧度上是颤动的。我没有为Pi常数导入Math,但你可能应该这样做。

    2. 您有一个实际上没有调用openMenucloseMenu的点按,因此肯定不会做任何事情= D。

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

    4. 您没有将任何内容传递给animationControllerOpenClose.forward来电。这意味着它将从当前的任何位置激活到1.0状态,即使它已经是1.0。我刚刚传入0,但你可能想做一些关于打开/关闭的事情(如果用户在动画或其他东西时点击)。

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

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

      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的构建函数中构建了尽可能少的小部件。在那里建造的越少,性能越好。因为图标本身不会作为旋转的一部分而改变,所以您可以简单地将其作为子项传递。

      我猜这可能会出现,所以只是一个FYI - 您可以使用动画交叉淡入淡出小部件来进行图标之间的转换(只需将其放入AnimatedBuilder的孩子中):

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