Как запустить функцию при изменении маршрута?

#flutter

Вопрос:

Я сделал виджет кругового меню, который открывается для отображения параметров меню, когда пользователь нажимает на него, он переходит на другой экран, но если пользователь нажмет кнопку «Назад» на Android, он вернется на экран меню, при этом круговое меню все еще открыто(также увеличивается расстояние от подменю до основного круга): Я обрезал видео, просто чтобы показать кнопку

(Я обрезал видео только для того, чтобы показать кнопку, треугольник, направленный вниз, является частью следующего экрана)

Я хочу закрывать круговое меню всякий раз, когда пользователь выбирает любую опцию в подменю, поэтому в основном я хочу запустить функцию close() перед изменением маршрутов или любым другим способом закрыть кнопку

 import 'package:flutter/material.dart';
import 'package:frontend/utils/degrees_to_radians.dart';
import 'package:frontend/utils/indexed_iterables.dart';

class CircularMenu extends StatefulWidget {
  final Widget menuIcon;
  final List<Widget>? children;
  CircularMenu({Key? key, this.children, required this.menuIcon})
      : super(key: key);

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

class _CircularMenuState extends State<CircularMenu>
    with TickerProviderStateMixin {
  bool _isOpen = false;
  bool _isAnimating = false;

  late AnimationController _animationController;
  late AnimationController _subMenuPositionController;
  late Animation<double> _sizeAnimation;
  late Animation<double> _subMenuPositionAnimation;

  void open() {
    setState(() {
      _isOpen = true;
      _animationController.forward();
      _subMenuPositionController.forward();
    });
  }

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(milliseconds: 400), vsync: this);

    _subMenuPositionController =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this);

    _sizeAnimation = TweenSequence([
      TweenSequenceItem<double>(
          tween: Tween<double>(begin: 1, end: 0.4)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 50),
      TweenSequenceItem<double>(
          tween: Tween<double>(begin: 0.4, end: 0.9)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 50),
      TweenSequenceItem<double>(
          tween: Tween<double>(begin: 0.9, end: 0.3)
              .chain(CurveTween(curve: Curves.easeInOut)),
          weight: 50),
    ]).animate(_animationController);
      /* ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _subMenuPositionController.forward();
        }
      });
 */
    _subMenuPositionAnimation = Tween<double>(begin: 0, end: 75)
        .chain(CurveTween(curve: Curves.bounceIn))
        .animate(_subMenuPositionController);

    super.initState();
  }


  void close() {
    setState(() {
      _isOpen = false;
      _animationController.reverse();
      _subMenuPositionController.reverse();
    });
  }



  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: _animationController,
        builder: (context, _) {
          return Container(
            child: Stack(
              alignment: Alignment.center,
              children: [
                if(widget.children != null)
                ..._renderSubMenu(
                    widget.children!, _subMenuPositionAnimation.value),

                //Center Button
                FractionallySizedBox(
                  widthFactor: _sizeAnimation.value,
                  heightFactor: _sizeAnimation.value,
                  child: Container(
                    child: RawMaterialButton(
                      fillColor: Colors.blue,
                      shape: CircleBorder(),
                      onPressed: () {
                        if (_isAnimating) return;

                        if (_isOpen) {
                          close();
                        } else {
                          open();
                        }
                      },
                      child: Center(child: _isOpen ? Icon(Icons.close) : widget.menuIcon),
                    ),
                  ),
                ),
              ],
            ),
          );
        });
  }

  List<Widget> _renderSubMenu(List<Widget> children, double distance) {
    List<Widget> _subMenu = [];
    double _angleRatio = 360 / children.length;

    children.forEachIndexed((child, index) {
      _subMenu.add(
        Transform.translate(
            offset: Offset.fromDirection(
                convertDegreesToRadians(index * _angleRatio), distance),
            child: GestureDetector(
                            child: child)),
      );
    });

    return _subMenu;
  }
}
 

Ответ №1:

вы должны просто передать близкий обратный вызов элементам подменю и вызвать его после нажатия навигатора, не дожидаясь завершения нажатия. хотя вам следует изменить список детей на список конструктора, чтобы вы могли настроить обратный вызов на определенную кнопку.

также вы должны сначала изменить состояние, а затем проверить, установлен ли виджет, прежде чем устанавливать его состояние, что-то вроде этого:

   void close() {
      _isOpen = false;
      _animationController.reverse();
      _subMenuPositionController.reverse();
      if (mounted) {
        setState(() {});
      }
  }
 

Комментарии:

1. я завершил рабочий пример, вы можете увидеть его здесь dartpad.dev/…