Вызывать собственную функцию виджета вне ее - PullRequest
0 голосов
/ 28 декабря 2018

У меня есть виджет с отслеживанием состояния, который может быть в двух ситуациях, первый - это Контейнер с первым текстом в нем, например, «Register», второй - контейнер другого цвета с другим текстом, дляпример "подтвердить".Проблема в том, что переход между этими двумя ситуациями осуществляется с использованием анимации, а это не логика на лету, например:

color: isSituation1 ? Colors.blue : Colors.red.

Это на самом деле что-то вроде этого:

color: Color.lerp(Colors.blue, Colors.red, _animation1.value)  

и у меня есть функция, которая запускается, когда пользователь нажимает на контейнер, который пересылает контроллер анимации, например:

_controller1.forward()

, и это виджет, называемый, скажем, Button1

В виджете с состоянием My HomePage у меня есть еще одна кнопка, которая должна запускать обратный процесс в виджете Button1, поэтому это будет:

_controller1.reverse()

Я попытался создать функцию в виджете Button1, но затем не могу запустить ее извне.Как я могу это сделать, если это возможно?

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

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

class HomePage extends StatefulWidget {
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  VoidCallback _reverseAnimation;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          RaisedButton(
            child: Text('Reverse animation'),
            onPressed: () => _reverseAnimation(),
          ),
          Button1((controller) => _reverseAnimation = controller),
        ],
      ),
    );
  }
}

class Button1 extends StatefulWidget {
  final ValueChanged<VoidCallback> callback;
  Button1(this.callback);
  _Button1State createState() => _Button1State();
}

class _Button1State extends State<Button1> with SingleTickerProviderStateMixin {
  AnimationController _someAnimationController;

  void _reverseAnimation() {
    _someAnimationController?.reverse();
  }

  @override
  void initState() {
    super.initState();
    if (widget.callback != null) {
      widget.callback(_reverseAnimation);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: RaisedButton(
        child: Text('Start animation'),
        onPressed: () => _someAnimationController.forward(),
      ),
    );
  }
}
0 голосов
/ 28 декабря 2018

Таким образом, вы хотите вызывать методы вашего CustomWidget из другого виджета.Вы можете определить ControllerClass, который вы будете генерировать при создании нового экземпляра вашего CustomWidget.Этот экземпляр ControllerClass будет содержать функции вашего CustomWidget, и вы сможете вызывать их извне.

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

class ModalRoundedProgressBar extends StatefulWidget {
  final String _textMessage;
  final double _opacity;
  final Color _color;
  final Function _handlerCallback;

  ModalRoundedProgressBar({
    @required Function handleCallback(ProgressBarHandler handler), //callback to get a controller
    String message = "",
    double opacity = 0.7,
    Color color = Colors.black54,
  })  : _textMessage = message,
        _opacity = opacity,
        _color = color,
        _handlerCallback = handleCallback;

  @override
  State createState() => _ModalRoundedProgressBarState();
}

class _ModalRoundedProgressBarState extends State<ModalRoundedProgressBar> {
  bool _isShowing = false;
  @override
  void initState() {
    super.initState();
    // init controller. 
    ProgressBarHandler handler = ProgressBarHandler();
    handler.show = this.show;
    handler.dismiss = this.dismiss;
    widget._handlerCallback(handler); // callback call.
  }

  @override
  Widget build(BuildContext context) {
    if (!_isShowing) return Stack();

    return Material(
      color: Colors.transparent,
      child: Stack(
        children: <Widget>[
          Opacity(
            opacity: widget._opacity,
            child: ModalBarrier(
              dismissible: false,
              color: Colors.black54,
            ),
          ),

          Center(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                CircularProgressIndicator(),
                Text(widget._textMessage),
              ],
            ),
          ),
        ],
      ),
    );
  }

  void show() {
    setState(() => _isShowing = true);
  }

  void dismiss() {
    setState(() => _isShowing = false);
  }
}

  class ProgressBarHandler { 
      Function show; // will point to widget show method
      Function dismiss; // will point to another method.
   }


// ...in another external widget you can do...
// ... code your things and:
var controller;
var progressBar = ModalRoundedProgressBar(
  handleCallback: ((handler){ controller = handler; } ),);

//calling show method with controller
RaisedButton(
    onPressed: () { controller.show(); }
);


//calling dismiss method with controller
RaisedButton(
    onPressed: () { controller.dismiss(); }
);
...