dart - Flutter 嵌套小部件回调/异步问题

来自 Flutter issue发表者Yueh Chou :

Not sure if the event will bubble up to the parent widget and trigger the animation with all the nested widgets and callbacks.

In the Original files,

Pressing on a grandchild widget(e.g. FlatButton) of a BackWidget it will trigger a ModalDialog call and pressing the button will make an async call. The Flip Effect will take place at the end of a successful async call.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';


void main() {
  runApp(new MaterialApp(
      home: new Container(color: Colors.white, child: new RootWidget())));
}

class RootWidget extends StatelessWidget {
  FlipWidget mainFlipWidget;

  @override
  Widget build(BuildContext context) {
    mainFlipWidget = new FlipWidget(
      frontWidget: frontWidget,
      backWidget: new BackWidget(
        onPressedButton: () {
          _flipMainButton();
        },
      ),
    );
    return new Center(child:mainFlipWidget);
  }

  _flipMainButton() {
    mainFlipWidget.doTheFlip();
  }
}

class BackWidget extends StatefulWidget {
  BackWidget({
    this.onPressedButton,
  });

  final VoidCallback onPressedButton;
   Widget buttonFlipWidget;
  _BackWidgetState createState() => new _BackWidgetState();
}

class _BackWidgetState extends State<BackWidget> {

  @override
  Widget build(BuildContext context) {
    widget.buttonFlipWidget = new Container(
      height: 180.0,
      color: Colors.grey[200],
      child:new FlatButton(
        onPressed: () {
          triggerCb();
        },
        child: new Text('Press me'),
      ),
    );
    return widget.buttonFlipWidget;
  }

  triggerCb() {
      widget.onPressedButton();
  }
}

class FlipWidget extends StatefulWidget {
  FlipWidget({
    @required this.frontWidget,
    @required this.backWidget,
  });

  final Widget frontWidget;
  final Widget backWidget;
  final _FlipWidgetState _state = new _FlipWidgetState();

  doTheFlip () {
    _state.doTheFlip();
  }

  _FlipWidgetState createState() => _state;
}

class _FlipWidgetState extends State<FlipWidget> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _frontScale;
  Animation<double> _backScale;

  void initState() {
    super.initState();
    _controller = new AnimationController(vsync: this, duration: const Duration(milliseconds: 1500),);
    _frontScale = new Tween(
      begin: 1.0,
      end: 0.0,
    ).animate(new CurvedAnimation(parent: _controller, curve: new Interval(0.0, 0.5, curve: Curves.easeIn),
    ));
    _backScale = new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.5, 1.0, curve: Curves.easeOut),
    );
  }

  @override
  Widget build(BuildContext context) {
//    ThemeData theme = Theme.of(context);
    return new Scaffold(
      body: new Center(
        child: new Stack(
          children: [
            new AnimatedBuilder(
              child: widget.frontWidget,
              animation: _backScale,
              builder: (BuildContext context, Widget child) {
                final Matrix4 transform = new Matrix4.identity()
                  ..scale(_backScale.value, 1.0, 1.0);

                return new Transform(
                  transform: transform,
                  alignment: FractionalOffset.center,
                  child: child,
                );
              },
            ),
            new AnimatedBuilder(
                child: widget.backWidget,
                animation: _frontScale,
                builder: (BuildContext context, Widget child) {
                  final Matrix4 transform = new Matrix4.identity()
                    ..scale(_frontScale.value, 1.0, 1.0);
                  return new Transform(
                    transform: transform,
                    alignment: FractionalOffset.center,
                    child: child,
                  );
                }
            ),
          ],
        ),
      ),
    );
  }

  doTheFlip() {
    setState(() {
      if (_controller.isCompleted || _controller.velocity > 0)
        _controller.reverse();
      else
        _controller.forward();
    });
  }
}

final Widget frontWidget = new Container(
  color: Colors.white,
  height: 180.0,
  child: new Column(
    children: [
      new Text("Front Side of the card")
    ],
  ),
);

最佳答案

您应该对此代码进行一些更改。

  • RootWidget 应该是有状态的。将 flipped 状态存储在那里。
  • BackWidget 应该是无状态的。它所要做的就是通知 RootWidget 该按钮已被按下。
  • FlipWidget 应该使用 didUpdateWidget 检测对 flipped 的更改。
  • 不要将 State 存储到 Widget 的成员变量中,如果可以避免的话,请避免在 State 上放置 mutator 方法它...这通常表明您需要将状态存储在小部件树中的较高位置,并使用构造函数参数将其向下传递。

在 Widget Framework Tour 中了解有关 StatefulWidgetStatelessWidget 的更多信息和 interactivity tutorial .

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new Container(
      color: Colors.white,
      child: new RootWidget(),
    ),
  ));
}

class RootWidget extends StatefulWidget {
  @override
  _RootWidgetState createState() => new _RootWidgetState();
}

class _RootWidgetState extends State<RootWidget> {
  bool _flipped = false;

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new FlipWidget(
        flipped: _flipped,
        frontWidget: new Container(
          color: Colors.white,
          height: 180.0,
          child: new Column(
            children: [
              new Text("Front Side of the card")
            ],
          ),
        ),
        backWidget: new BackWidget(
          onPressedButton: () {
            setState(() {
              _flipped = !_flipped;
            });
          },
        ),
      ),
    );
  }
}

class BackWidget extends StatelessWidget {
  BackWidget({
    this.onPressedButton,
  });
  final VoidCallback onPressedButton;

  @override
  Widget build(BuildContext context) {
    return new Container(
      height: 180.0,
      color: Colors.grey[200],
      child:new FlatButton(
        onPressed: onPressedButton,
        child: new Text('Press me'),
      ),
    );
  }
}

class FlipWidget extends StatefulWidget {
  FlipWidget({
    @required this.frontWidget,
    @required this.backWidget,
    @required this.flipped,
  });

  final Widget frontWidget;
  final Widget backWidget;
  final bool flipped;

  @override
  _FlipWidgetState createState() => new _FlipWidgetState();
}

class _FlipWidgetState extends State<FlipWidget> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _frontScale;
  Animation<double> _backScale;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1500)
    )..value = widget.flipped ? 1.0 : 0.0;
    _frontScale = new Tween(
      begin: 1.0,
      end: 0.0,
    ).animate(new CurvedAnimation(parent: _controller, curve: new Interval(0.0, 0.5, curve: Curves.easeIn),
    ));
    _backScale = new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.5, 1.0, curve: Curves.easeOut),
    );
  }

  @override
  void didUpdateWidget(FlipWidget oldWidget) {
    if (widget.flipped != oldWidget.flipped) {
      if (widget.flipped) {
        _controller.forward();
      } else {
        _controller.reverse();
      }
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Stack(
          children: [
            new AnimatedBuilder(
              child: widget.frontWidget,
              animation: _backScale,
              builder: (BuildContext context, Widget child) {
                final Matrix4 transform = new Matrix4.identity()
                  ..scale(_backScale.value, 1.0, 1.0);

                return new Transform(
                  transform: transform,
                  alignment: FractionalOffset.center,
                  child: child,
                );
              },
            ),
            new AnimatedBuilder(
                child: widget.backWidget,
                animation: _frontScale,
                builder: (BuildContext context, Widget child) {
                  final Matrix4 transform = new Matrix4.identity()
                    ..scale(_frontScale.value, 1.0, 1.0);
                  return new Transform(
                    transform: transform,
                    alignment: FractionalOffset.center,
                    child: child,
                  );
                }
            ),
          ],
        ),
      ),
    );
  }
}

https://stackoverflow.com/questions/46733809/

相关文章:

flutter - 在 Flutter 的嵌套 Navigator 结构中,如何获取特定的 Navi

flutter - 如何在 flutter 应用程序中无上下文导航?

dart - 如何将 showModalBottomSheet 设置为全高?

google-maps - 使用 Flutter Google Maps 插件自定义标记

flutter - 在创建带有 float 应用栏的应用时使用 StreamBuilder

dart - 成功验证后不会调用 Flutter TextFormField onSave()

flutter - 如何从 Dart 中的 future 返回错误?

dart - 如何在没有用户交互的情况下发送短信?

dart - 在 flutter 中使用其 GlobalKey 获取 Widget 的高度

flutter - 如何在 Flutter 应用中获取屏幕大小?