1. 程式人生 > 實用技巧 >widget管理狀態的三種方式

widget管理狀態的三種方式

1.自身管理自己

_TapboxAState 類:

  • 管理TapboxA的狀態。
  • 定義_active:確定盒子的當前顏色的布林值。
  • 定義_handleTap()函式,該函式在點選該盒子時更新_active,並呼叫setState()更新UI。
  • 實現widget的所有互動式行為。
// TapboxA 管理自身狀態.

//------------------------- TapboxA ----------------------------------

class TapboxA extends StatefulWidget {
  TapboxA({Key key}) : super(key: key);

  

2.父類管理自己

栗子:

在以下示例中,TapboxB通過回撥將其狀態匯出到其父元件,狀態由父元件管理,因此它的父元件為StatefulWidget。但是由於TapboxB不管理任何狀態,所以TapboxBStatelessWidget

ParentWidgetState類:

  • 為TapboxB 管理_active狀態。
  • 實現_handleTapboxChanged(),當盒子被點選時呼叫的方法。
  • 當狀態改變時,呼叫setState()更新UI。

TapboxB 類:

  • 繼承StatelessWidget類,因為所有狀態都由其父元件處理。
  • 當檢測到點選時,它會通知父元件。

// ParentWidget 為 TapboxB 管理狀態.                                                 
                                                                                
//------------------------ ParentWidget -------------------------------- class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState()
=> new _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { bool _active = false; void _handleTapboxChanged(bool newValue) { setState(() { _active = newValue; }); } @override Widget build(BuildContext context) { return new Container( child: new TapboxB( active: _active, onChanged: _handleTapboxChanged, ), ); } } //------------------------- TapboxB ---------------------------------- class TapboxB extends StatelessWidget { TapboxB({Key key, this.active: false, @required this.onChanged}) : super(key: key); final bool active; final ValueChanged<bool> onChanged; //回撥函式 void _handleTap() { onChanged(!active); } Widget build(BuildContext context) { return new GestureDetector( onTap: _handleTap, child: new Container( child: new Center( child: new Text( active ? 'Active' : 'Inactive', style: new TextStyle(fontSize: 32.0, color: Colors.white), ), ), width: 200.0, height: 200.0, decoration: new BoxDecoration( color: active ? Colors.lightGreen[700] : Colors.grey[600], ), ), ); } }

再加上主app的程式碼,將home頁設為ParentWidget:

void main() => runApp(new MyApp());                                                                      
                                                                                                         
class MyApp extends StatelessWidget {                                                                    
  @override                                                                                              
  Widget build(BuildContext context) {                                                                   
    return new MaterialApp(//程式主體Material App             c                                              
      title: 'Flutter Demo',                                                                             
      initialRoute: "/",                                                                                 
      theme: new ThemeData(                                                                              
        primarySwatch: Colors.blue,                                                                      
      ),                                                                                                  
        //註冊路由表                                                                                          
        routes:{                                                                                         
          //"new_page":(context) => NewRoute(),                                                          
          //"new_page":(context) => EchoRoute(),                                                         
          //"/":(context) => MyHomePage(title: 'Flutter Demo Home Page'), //註冊首頁路由                       
          //"Counter":(context) => CounterWidget(),                                                      
        },                                                                                               
        //home: new MyHomePage(title: 'Flutter Demo Home Page'),                                         
        home:ParentWidget(),                                                                             
    );                                                                                                    
  }                                                                                                      
}                                                                                                        
                                                                                                         

執行截圖如下:

3.

混合狀態管理

//---------------------------- ParentWidget ----------------------------

class ParentWidgetC extends StatefulWidget {
  @override
  _ParentWidgetCState createState() => new _ParentWidgetCState();
}

class _ParentWidgetCState extends State<ParentWidgetC> {
  bool _active = false;  //這裡儲存實際tapboxC是否啟用的bool值

  void _handleTapboxChanged(bool newValue) {//更改tapboxC啟用狀態時回撥的函式
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {//父類widget的build函式:生成一個容器,裡面有一個tapboxC,該盒子的active用父類的_active初始化(false)
    print("_parentWidgetCState Build");  //onChanged屬性指明為父類中的_handleTapboxChanged,即盒子的active是由父類控制的    
    return new Container(
      child: new TapboxC(
        active: _active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}


//----------------------------- TapboxC ------------------------------

class TapboxC extends StatefulWidget {
  TapboxC({Key key, this.active: false, @required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

  @override
  _TapboxCState createState() => new _TapboxCState();
}
//TapboxCState類
class _TapboxCState extends State<TapboxC> { bool _highlight = false;//盒子是否高亮 void _handleTapDown(TapDownDetails details) {//處理按下 setState(() { _highlight = true; }); } void _handleTapUp(TapUpDetails details) {//處理滑鼠抬起 setState(() { _highlight = false; }); } void _handleTapCancel() {  //處理不會造成點選的按下取消 setState(() { _highlight = false; }); } void _handleTap() { widget.onChanged(!widget.active); } @override Widget build(BuildContext context) { // 在按下時新增綠色邊框,當抬起時,取消高亮 return new GestureDetector( onTapDown: _handleTapDown, // 處理按下事件 onTapUp: _handleTapUp, // 處理抬起事件 onTap: _handleTap,  //處理按下取消 onTapCancel: _handleTapCancel, child: new Container( child: new Center( child: new Text(widget.active ? 'Active' : 'Inactive', style: new TextStyle(fontSize: 32.0, color: Colors.white)), ), width: 200.0, height: 200.0, decoration: new BoxDecoration(//按下螢幕出現的四周邊框 color: widget.active ? Colors.lightGreen[700] : Colors.grey[600], border: _highlight ? new Border.all( color: Colors.teal[700], width: 10.0, ) : null, ), ), ); } }