Flutter Nested Widget回调/异步问题

时间:2017-10-13 15:59:42

标签: dart flutter

来自Flutter issue发布的Yueh Chou

  

不确定事件是否会冒泡到父窗口小部件并触发   包含所有嵌套小部件和回调的动画。

     

在原始文件中

     

按下BackWidget的孙子小部件(例如FlatButton)   将触发ModalDialog调用并按下按钮将进行调用   异步调用。翻转效果将在成功结束时发生   异步呼叫。

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")
    ],
  ),
);

1 个答案:

答案 0 :(得分:8)

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

  • RootWidget应该是有状态的。将flipped州存储在那里。
  • BackWidget应该是无国籍的。它所要做的就是通知RootWidget按下按钮。
  • FlipWidget应使用flipped检测didUpdateWidget的更改。
  • 不要将State存储到Widget的成员变量中,如果可以避免,请避免在您的State上添加mutator方法...这通常是表示您需要在窗口小部件树中将状态存储得更高,并使用构造函数参数将其传递下来。

详细了解Widget Framework Tourinteractivity tutorial中的StatefulWidgetStatelessWidget

enter image description here

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,
                  );
                }
            ),
          ],
        ),
      ),
    );
  }
}