Сдвиньте дочерний виджет в контейнере макета строки из его текущей позиции - PullRequest
0 голосов
/ 27 марта 2019

У меня есть строка, которая состоит из х количество виджетов кнопок. Поэтому, когда пользователь нажимает на одну из кнопок, мне нужно потушить другие кнопки и переместить нажатую кнопку в начальное положение (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 для перемещения дочернего виджета в начальную позицию строки. По сути, я не уверен, какие классы могут быть полезны для достижения такой анимации. Я могу использовать Tween и установить конечную позицию в (0, 0) и использовать Translation для достижения этого, однако я не уверен, как установить начальную позицию анимации, когда я инициализирую ее, так как позиция ребенка неизвестна .

1 Ответ

1 голос
/ 27 марта 2019

Попробуйте это решение. Я думаю, это почти то, что вам нужно. Вам просто нужно добавить виджет 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 _button, выбранный для отслеживания завершения анимации.
  5. Используйте _buttonSelected для создания правильного виджета (Widget _buttonsWidget ())
class _MyHomePageState extends State<MyHomePage> with 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();
  }
}

...