将“行”布局容器中的子窗口小部件从其当前位置滑动

时间:2019-03-27 10:46:05

标签: flutter flutter-animation

我有一个包含x个Button小部件的行。因此,当用户单击其中一个按钮时,我需要淡出其他按钮,然后将单击的按钮滑动到行布局的开始位置(0,0)。我设法使淡出动画起作用。

final _opacityTween = Tween<double>(begin: 1, end: 0);
_opacityAnimation = _opacityTween.animate(CurvedAnimation(
        parent: _controller,
        curve: new Interval(0.00, 0.50, curve: Curves.linear)
        // curve: Curves.ease
        ));

// And using the opacityAnimation value in Opacity widget.

return Opacity(
        opacity: _opacityAnimation.value,
        child: child,
      );

但是,我未能使用Animation类和小部件将子小部件滑动到Row的开始位置。基本上,我不确定哪种类对实现这种动画有用。我可以使用补间并将结束位置设置为(0,0)并使用平移来实现它,但是由于不确定孩子的位置,因此我不确定在初始化动画时如何设置动画的开始位置

1 个答案:

答案 0 :(得分:1)

尝试此解决方案。我认为这几乎是您所需要的。您只需要添加SizeTransition小部件。 询问您是否有任何问题。

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {

    int _pressedButton;

    Animation<double> _animation;
    AnimationController _controller;

    @override
    void initState() {
        super.initState();
        _controller = AnimationController(
            duration: const Duration(milliseconds: 500),
            vsync: this,
        );
        _animation = Tween<double>(begin: 1.0, end: 0.0)
            .animate(_controller)
            ..addListener(() {
                setState(() { });
            });
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text("Test"),
            ),
            body: Column(
                children: <Widget>[
                    Row(
                        children: <Widget>[
                            _animatedButton(1),
                            _animatedButton(2),
                            _animatedButton(3),
                            _animatedButton(4)
                        ]
                    ),
                    Text(_pressedButton != null ? "$_pressedButton button pressed" : "No button pressed"),
                    RaisedButton(
                        child: Text("Reset"),
                        onPressed: () {
                            _controller.reset();
                        }
                    )
                ]
            )
        );
    }

    Widget _animatedButton(int button) {
        if (button != _pressedButton) {
            return SizeTransition(
                sizeFactor: _animation,
                axis: Axis.horizontal,
                child: Opacity(
                    opacity: _animation.value,
                    child: _button(button)
                )
            );
        } else {
            return _button(button);
        }
    }

    Widget _button(int button) {
        return RaisedButton(
            onPressed: () => onButtonClick(button),
            child: Text("Button $button")
        );
    }

    void onButtonClick(int button) {
        setState(() {
            _pressedButton = button;
        });
        _controller.forward();
    }

}

更新1

再检查一种执行所需操作的方法。下面的代码中几乎没有什么不同的东西。

  1. 将SingleTickerProviderStateMixin更改为TickerProviderStateMixin。
  2. 使用两个动画控制器和动画(用于淡出未选中的按钮和向左滑动选中的按钮)。
  3. 按顺序运行动画(请参见补间动画侦听器)。
  4. 添加bool _buttonSelected以跟踪动画的完成。
  5. 使用_buttonSelected构建正确的小部件(小部件_buttonsWidget())

    _MyHomePageState类使用TickerProviderStateMixin {

    int _pressedButton = -1;
    bool _buttonSelected = false;
    
    Animation<double> _animationFadeOut;
    AnimationController _controllerFadeOut;
    Animation<double> _animationSlideLeft;
    AnimationController _controllerSlideLeft;
    
    @override
    void initState() {
        super.initState();
        _initFadeOutAnimation();
        _initSlideLeftAnimation();
    }
    
    void _initFadeOutAnimation() {
        _controllerFadeOut = AnimationController(
            duration: const Duration(milliseconds: 500),
            vsync: this,
        );
        _animationFadeOut = Tween<double>(begin: 1.0, end: 0.0)
            .animate(_controllerFadeOut)
            ..addListener(() {
                setState(() {
                    if (_controllerFadeOut.isCompleted && !_controllerSlideLeft.isAnimating) {
                        _controllerSlideLeft.forward();
                    }
                });
            });
    }
    
    void _initSlideLeftAnimation() {
        _controllerSlideLeft = AnimationController(
            duration: const Duration(milliseconds: 500),
            vsync: this,
        );
        _animationSlideLeft = Tween<double>(begin: 1.0, end: 0.0)
            .animate(_controllerSlideLeft)
            ..addListener(() {
                setState(() {
                    if (_controllerSlideLeft.isCompleted) {
                        _buttonSelected = true;
                    }
                });
            });
    }
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text("Test"),
            ),
            body: Column(
                children: <Widget>[
                    _buttonsWidget(),
                    Text(_pressedButton != null ? "$_pressedButton button pressed" : "No button pressed"),
                    RaisedButton(
                        child: Text("Reset"),
                        onPressed: () {
                            _controllerFadeOut.reset();
                            _controllerSlideLeft.reset();
                            _pressedButton = -1;
                            _buttonSelected = false;
                        }
                    )
                ]
            )
        );
    }
    
    Widget _buttonsWidget() {
        if (_buttonSelected) {
            return Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[_buttonWidget(_pressedButton)]
            );
        } else {
            return Row(
                children: <Widget>[
                    _animatedButtonWidget(1),
                    _animatedButtonWidget(2),
                    _animatedButtonWidget(3),
                    _animatedButtonWidget(4)
                ]
            );
        }
    }
    
    Widget _animatedButtonWidget(int button) {
        if (button == _pressedButton) {
            return _buttonWidget(button);
        } else {
            return SizeTransition(
                sizeFactor: _animationSlideLeft,
                axis: Axis.horizontal,
                child: Opacity(
                    opacity: _animationFadeOut.value,
                    child: _buttonWidget(button)
                )
            );
        }
    }
    
    Widget _buttonWidget(int button) {
        return RaisedButton(
            onPressed: () => _onButtonClick(button),
            child: Text("Button $button")
        );
    }
    
    void _onButtonClick(int button) {
        setState(() {
            _pressedButton = button;
        });
        _controllerFadeOut.forward();
    }
    

    }