2017-10-13 32 views
1

從張貼Yueh Chou一個Flutter issue撲嵌套的widget回調/異步問題

不知道該事件會冒泡到父控件和觸發 所有的嵌套小部件和回調的動畫。

在原始文件,

按上一個孫子小部件BackWidget它 會引發ModalDialog呼叫(例如FlatButton),並按下按鈕將作出 異步調用。翻轉效果將在成功的 異步調用結束時發生。

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

一些變化,你應該對這個代碼。

  • RootWidget應該是有狀態的。在那裏存儲flipped狀態。
  • BackWidget應該是無狀態的。它所要做的就是通知RootWidget該按鈕被按下。
  • FlipWidget應該使用didUpdateWidget檢測到對flipped的更改。
  • 不要將State存儲到Widget的成員變量中,並避免在您的State上放置增變器方法(如果可以避免的話)......這通常表示您需要將更高級的狀態存儲在小部件樹中並用構造函數參數傳遞給它。

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