Flutter組件狀態(tài)管理的3種方法
前言
前面講了Flutter布局,布局只是靜態(tài)的。在Flutter中,組件分為StatelesslWidget和StatefulWidget。
- StatelesslWidget
沒有狀態(tài),是一成不變的。比如圖標(biāo),文字,按鈕等
- StatefulWidget
有狀態(tài)的組件,頁(yè)面數(shù)據(jù)是動(dòng)態(tài)的,或者會(huì)隨著用戶操作變化,比如多選框,文本輸入框等。
有狀態(tài)組件
重點(diǎn)來了,如何使用實(shí)現(xiàn)一個(gè)有狀態(tài)的組件呢?
- 有狀態(tài)的組件一般由兩個(gè)類構(gòu)成,一個(gè)StatefulWidget子類和一個(gè)State子類.
- State類包含了組件的
build()
方法,并且負(fù)責(zé)維護(hù)組件狀態(tài) - 當(dāng)這個(gè)組件的狀態(tài)變化了,可以調(diào)用
setState()
方法來刷新頁(yè)面
狀態(tài)管理
由誰(shuí)來負(fù)責(zé)狀態(tài)管理呢?是組件本身,還是他的父類,兩者都有又或是其他對(duì)象?答案是都可以。也就是說有三種方法實(shí)現(xiàn)狀態(tài)管理:
1.組件自己管理自己的狀態(tài)
2.組件的父組件管理狀態(tài)
3.混搭管理
那么如何決定該用那種方式來進(jìn)行狀態(tài)管理呢?一般來講有以下原則:
1.如果是用戶數(shù)據(jù),比如多選框是否被選中,一般是由選擇第2種方法
2.如果動(dòng)效,比如放大縮小,那一般用第1種方法
PS:如果你實(shí)在迷芒,就直接選擇用第2種方法,用父類管理狀態(tài)。
舉例
組件自己管理自己的狀態(tài)
如下代碼:_TapboxAState
這個(gè)State
子類為TapboxA
維護(hù)狀態(tài),內(nèi)部定義了一個(gè)_active
變量來決定當(dāng)前是否為激活的狀態(tài),內(nèi)部還定義了一個(gè)_handleTap()
回調(diào)函數(shù),來處理用戶點(diǎn)擊后的邏輯,并且調(diào)用了setState()
生命周期方法,重新刷新頁(yè)面。
import 'package:flutter/material.dart'; // TapboxA 自己管理狀態(tài) void main() => runApp(const MyApp()); //------------------------- TapboxA ---------------------------------- class TapboxA extends StatefulWidget { ? const TapboxA({Key? key}) : super(key: key); ? @override ? _TapboxAState createState() => _TapboxAState(); } class _TapboxAState extends State<TapboxA> { ? bool _active = false; ? void _handleTap() { ? ? setState(() { ? ? ? _active = !_active; ? ? }); ? } ?? ? @override ? Widget build(BuildContext context) { ? ? return GestureDetector( ? ? ? onTap: _handleTap, ? ? ? child: Container( ? ? ? ? child: Center( ? ? ? ? ? child: Text( ? ? ? ? ? ? _active ? 'Active' : 'Inactive', ? ? ? ? ? ? style: const TextStyle(fontSize: 32.0, color: Colors.white), ? ? ? ? ? ), ? ? ? ? ), ? ? ? ? width: 200.0, ? ? ? ? height: 200.0, ? ? ? ? decoration: BoxDecoration( ? ? ? ? ? color: _active ? Colors.lightGreen[700] : Colors.grey[600], ? ? ? ? ), ? ? ? ), ? ? ); ? } } //------------------------- MyApp ---------------------------------- class MyApp extends StatelessWidget { ? const MyApp({Key? key}) : super(key: key); ? @override ? Widget build(BuildContext context) { ? ? return MaterialApp( ? ? ? title: 'Flutter Demo', ? ? ? home: Scaffold( ? ? ? ? appBar: AppBar( ? ? ? ? ? title: const Text('Flutter Demo'), ? ? ? ? ), ? ? ? ? body: const Center( ? ? ? ? ? child: TapboxA(), ? ? ? ? ), ? ? ? ), ? ? ); ? } }
父組件管理狀態(tài)
更多時(shí)候我們需要父組件來決定子組件什么時(shí)候來更新狀態(tài),子組件只需要根據(jù)父組件傳過來的參數(shù)進(jìn)行合理的展示即可。這種情況下子組件并不需要維護(hù)狀態(tài),所以子組件是一個(gè)StatelessWidget
,父組件ParentWidget
才是StatefulWidget
。代碼如下:
父組件維護(hù)了一個(gè)_active
變量用來標(biāo)記是否為激活狀態(tài),并且實(shí)現(xiàn)了回調(diào)函數(shù)_handleTapboxChanged
用來反轉(zhuǎn)激活狀態(tài),供子組件調(diào)用。子組件TapboxB
是一個(gè)無(wú)狀態(tài)組件,只需要在被點(diǎn)擊的時(shí)候通知父組件來管理狀態(tài)。
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class ParentWidget extends StatefulWidget { ? const ParentWidget({Key? key}) : super(key: key); ? @override ? _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { ? bool _active = false; ? void _handleTapboxChanged(bool newValue) { ? ? setState(() { ? ? ? _active = newValue; ? ? }); ? } ? @override ? Widget build(BuildContext context) { ? ? return SizedBox( ? ? ? child: TapboxB( ? ? ? ? active: _active, ? ? ? ? onChanged: _handleTapboxChanged, ? ? ? ), ? ? ); ? } } //------------------------- TapboxB ---------------------------------- class TapboxB extends StatelessWidget { ? const TapboxB({ ? ? Key? key, ? ? this.active = false, ? ? required this.onChanged, ? }) : super(key: key); ? final bool active; ? final ValueChanged<bool> onChanged; ? void _handleTap() { ? ? onChanged(!active); ? } ? @override ? Widget build(BuildContext context) { ? ? return GestureDetector( ? ? ? onTap: _handleTap, ? ? ? child: Container( ? ? ? ? child: Center( ? ? ? ? ? child: Text( ? ? ? ? ? ? active ? 'Active' : 'Inactive', ? ? ? ? ? ? style: const TextStyle(fontSize: 32.0, color: Colors.white), ? ? ? ? ? ), ? ? ? ? ), ? ? ? ? width: 200.0, ? ? ? ? height: 200.0, ? ? ? ? decoration: BoxDecoration( ? ? ? ? ? color: active ? Colors.lightGreen[700] : Colors.grey[600], ? ? ? ? ), ? ? ? ), ? ? ); ? } } //------------------------- MyApp ---------------------------------- class MyApp extends StatelessWidget { ? const MyApp({Key? key}) : super(key: key); ? @override ? Widget build(BuildContext context) { ? ? return MaterialApp( ? ? ? title: 'Flutter Demo', ? ? ? home: Scaffold( ? ? ? ? appBar: AppBar( ? ? ? ? ? title: const Text('Flutter Demo'), ? ? ? ? ), ? ? ? ? body: const Center( // ? ? ? ? ?child: TapboxA(), ? ? ? ? ? child: ParentWidget(), ? ? ? ? ), ? ? ? ), ? ? ); ? } }
混搭管理
混搭管理狀態(tài),就是因?yàn)橛行┣闆r下我們需要父組件管理一部分狀態(tài),子組件獨(dú)立管理另一部分狀態(tài)。在本次,我們根據(jù)上例添加一個(gè)動(dòng)效,按鈕按下時(shí)要顯示高亮狀態(tài)(前文講過,動(dòng)效一類的狀態(tài)一般要組件本身管理),抬起時(shí)取消高亮。
如下代碼:ParentWidget
負(fù)責(zé)維護(hù)_active
狀態(tài)來標(biāo)志是否被激活,子組件TapboxC
負(fù)責(zé)維護(hù)_highlight
狀態(tài)用來控制是否高亮顯示。
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class ParentWidget extends StatefulWidget { ? const ParentWidget({Key? key}) : super(key: key); ? @override ? _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { ? bool _active = false; ? void _handleTapboxChanged(bool newValue) { ? ? setState(() { ? ? ? _active = newValue; ? ? }); ? } ? @override ? Widget build(BuildContext context) { ? ? return SizedBox( ? ? ? child: TapboxC( ? ? ? ? active: _active, ? ? ? ? onChanged: _handleTapboxChanged, ? ? ? ), ? ? ); ? } } //----------------------------- TapboxC ------------------------------ class TapboxC extends StatefulWidget { ? const TapboxC({ ? ? Key? key, ? ? this.active = false, ? ? required this.onChanged, ? }) : super(key: key); ? final bool active; ? final ValueChanged<bool> onChanged; ? @override ? _TapboxCState createState() => _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 GestureDetector( ? ? ? onTapDown: _handleTapDown, // Handle the tap events in the order that ? ? ? onTapUp: _handleTapUp, // they occur: down, up, tap, cancel ? ? ? onTap: _handleTap, ? ? ? onTapCancel: _handleTapCancel, ? ? ? child: Container( ? ? ? ? child: Center( ? ? ? ? ? child: Text(widget.active ? 'Active' : 'Inactive', ? ? ? ? ? ? ? style: const TextStyle(fontSize: 32.0, color: Colors.white)), ? ? ? ? ), ? ? ? ? width: 200.0, ? ? ? ? height: 200.0, ? ? ? ? decoration: BoxDecoration( ? ? ? ? ? color: _highlight?Colors.lightGreen :widget.active ? Colors.lightGreen[700] : Colors.grey[600], ? ? ? ? ), ? ? ? ), ? ? ); ? } } //------------------------- MyApp ---------------------------------- class MyApp extends StatelessWidget { ? const MyApp({Key? key}) : super(key: key); ? @override ? Widget build(BuildContext context) { ? ? return MaterialApp( ? ? ? title: 'Flutter Demo', ? ? ? home: Scaffold( ? ? ? ? appBar: AppBar( ? ? ? ? ? title: const Text('Flutter Demo'), ? ? ? ? ), ? ? ? ? body: const Center( // ? ? ? ? ?child: TapboxA(), ? ? ? ? ? child: ParentWidget(), ? ? ? ? ), ? ? ? ), ? ? ); ? } }
當(dāng)然你也可以把高亮顯示的狀態(tài)交給父組件來管理,但是當(dāng)你開發(fā)完這個(gè)組件交給同事來用的時(shí)候,別人可能只會(huì)關(guān)注業(yè)務(wù)邏輯上的處理,不會(huì)關(guān)注的動(dòng)效處理。
其他交互組件
Flutter內(nèi)部預(yù)置了很多交互組件,甚至還有IOS風(fēng)格的組件,都可以拿來用。如果有必要的話,可以向上面的例子一樣自定義組件使用。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android編程簡(jiǎn)單獲取網(wǎng)絡(luò)上的圖片
這篇文章主要介紹了Android編程簡(jiǎn)單獲取網(wǎng)絡(luò)上的圖片,結(jié)合實(shí)例形式分析了Android獲取網(wǎng)絡(luò)圖片及加載顯示的相關(guān)操作步驟與注意事項(xiàng),需要的朋友可以參考下2016-10-10OpenHarmony實(shí)現(xiàn)類Android短信驗(yàn)證碼及倒計(jì)時(shí)流程詳解
這篇文章主要介紹了OpenHarmony實(shí)現(xiàn)類Android短信驗(yàn)證碼及倒計(jì)時(shí)流程,發(fā)送短信驗(yàn)證碼后,一般在界面上都會(huì)有一個(gè)倒計(jì)時(shí)的顯示.在安卓中,實(shí)現(xiàn)類似的倒計(jì)時(shí)有多種方式,當(dāng)然背后的基本原理都是設(shè)定一個(gè)初始值,然后每過一定的間隔時(shí)間執(zhí)行操作2022-11-11Android編程實(shí)現(xiàn)圓角邊框布局效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)圓角邊框布局效果的方法,結(jié)合實(shí)例形式分析了Android TableLayout布局的相關(guān)屬性操作與圓角邊框?qū)崿F(xiàn)技巧,需要的朋友可以參考下2017-06-06Android RecyclerView添加上拉加載更多功能
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView如何添加上拉加載更多功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Android 系統(tǒng)相機(jī)拍照后相片無(wú)法在相冊(cè)中顯示解決辦法
這篇文章主要介紹了Android 系統(tǒng)相機(jī)拍照后相片無(wú)法在相冊(cè)中顯示解決辦法的相關(guān)資料,需要的朋友可以參考下2016-12-12Android編程實(shí)現(xiàn)播放視頻的方法示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)播放視頻的方法,結(jié)合具體實(shí)例形式分析了Android使用VideoView類播放視頻的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-08-08Input系統(tǒng)之InputReader概要性實(shí)例分析
這篇文章主要介紹為大家了Input系統(tǒng)之InputReader概要性實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11android實(shí)現(xiàn)簡(jiǎn)單圓弧效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)單圓弧效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08淺談Android Studio 4.1 更新內(nèi)容
這篇文章主要介紹了淺談Android Studio 4.1 更新內(nèi)容,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10