新聞中心
創(chuàng)建一個(gè)有狀態(tài)的widget
重點(diǎn):

創(chuàng)新互聯(lián)成立與2013年,是專(zhuān)業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站建設(shè)、成都做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元托克托做網(wǎng)站,已為上家服務(wù),為托克托各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話(huà):18980820575
- 要?jiǎng)?chuàng)建一個(gè)自定義有狀態(tài)widget,需創(chuàng)建兩個(gè)類(lèi):StatefulWidget和State
- 狀態(tài)對(duì)象包含widget的狀態(tài)和build() 方法。
- 當(dāng)widget的狀態(tài)改變時(shí),狀態(tài)對(duì)象調(diào)用setState(),告訴框架重繪widget
在本節(jié)中,您將創(chuàng)建一個(gè)自定義有狀態(tài)的widget。 您將使用一個(gè)自定義有狀態(tài)widget來(lái)替換兩個(gè)無(wú)狀態(tài)widget - 紅色實(shí)心星形圖標(biāo)和其旁邊的數(shù)字計(jì)數(shù) - 該widget用兩個(gè)子widget管理一行:IconButton和Text。
實(shí)現(xiàn)一個(gè)自定義的有狀態(tài)widget需要?jiǎng)?chuàng)建兩個(gè)類(lèi):
- 定義一個(gè)widget類(lèi),繼承自StatefulWidget.
- 包含該widget狀態(tài)并定義該widget build()方法的類(lèi),它繼承自State.
本節(jié)展示如何為L(zhǎng)akes應(yīng)用程序構(gòu)建一個(gè)名為FavoriteWidget的StatefulWidget。第一步是選擇如何管理FavoriteWidget的狀態(tài)。
Step 1: 決定哪個(gè)對(duì)象管理widget的狀態(tài)
Widget的狀態(tài)可以通過(guò)多種方式進(jìn)行管理,但在我們的示例中,widget本身(FavoriteWidget)將管理自己的狀態(tài)。 在這個(gè)例子中,切換星形圖標(biāo)是一個(gè)獨(dú)立的操作,不會(huì)影響父窗口widget或其他用戶(hù)界面,因此該widget可以在內(nèi)部處理它自己的狀態(tài)。
Step 2: 創(chuàng)建StatefulWidget子類(lèi)
FavoriteWidget類(lèi)管理自己的狀態(tài),因此它重寫(xiě)createState()來(lái)創(chuàng)建狀態(tài)對(duì)象。 框架會(huì)在構(gòu)建widget時(shí)調(diào)用createState()。在這個(gè)例子中,createState()創(chuàng)建_FavoriteWidgetState的實(shí)例,您將在下一步中實(shí)現(xiàn)該實(shí)例。
class FavoriteWidget extends StatefulWidget {
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
注意: 以下劃線(xiàn)(_)開(kāi)頭的成員或類(lèi)是私有的。有關(guān)更多信息,請(qǐng)參閱Dart語(yǔ)言參考中的庫(kù)和可見(jiàn)性部分 。
Step 3: 創(chuàng)建State子類(lèi)
自定義State類(lèi)存儲(chǔ)可變信息 - 可以在widget的生命周期內(nèi)改變邏輯和內(nèi)部狀態(tài)。 當(dāng)應(yīng)用第一次啟動(dòng)時(shí),用戶(hù)界面顯示一個(gè)紅色實(shí)心的星星形圖標(biāo),表明該湖已經(jīng)被收藏,并有41個(gè)“喜歡”。狀態(tài)對(duì)象存儲(chǔ)這些信息在_isFavorited和_favoriteCount變量。
狀態(tài)對(duì)象也定義了build方法。此build方法創(chuàng)建一個(gè)包含紅色I(xiàn)conButton和Text的行。 該widget使用IconButton(而不是Icon), 因?yàn)樗哂幸粋€(gè)onPressed屬性,該屬性定義了處理點(diǎn)擊的回調(diào)方法。IconButton也有一個(gè)icon的屬性,持有Icon。
按下IconButton時(shí)會(huì)調(diào)用_toggleFavorite()方法,然后它會(huì)調(diào)用setState()。 調(diào)用setState()是至關(guān)重要的,因?yàn)檫@告訴框架,widget的狀態(tài)已經(jīng)改變,應(yīng)該重繪。 _toggleFavorite在: 1)實(shí)心的星形圖標(biāo)和數(shù)字“41” 和 2)虛心的星形圖標(biāo)和數(shù)字“40”之間切換UI。
class _FavoriteWidgetState extends State {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite() {
setState(() {
// If the lake is currently favorited, unfavorite it.
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
// Otherwise, favorite it.
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}
@override
Widget build(BuildContext context) {
return new Row(
mainAxisSize: MainAxisSize.min,
children: [
new Container(
padding: new EdgeInsets.all(0.0),
child: new IconButton(
icon: (_isFavorited
? new Icon(Icons.star)
: new Icon(Icons.star_border)),
color: Colors.red[500],
onPressed: _toggleFavorite,
),
),
new SizedBox(
width: 18.0,
child: new Container(
child: new Text('$_favoriteCount'),
),
),
],
);
}
}
提示: 當(dāng)文本在40和41之間變化時(shí),將文本放在SizedBox中并設(shè)置其寬度可防止出現(xiàn)明顯的“跳躍” ,因?yàn)檫@些值具有不同的寬度。
Step 4: 將有stateful widget插入widget樹(shù)中
將您自定義stateful widget在build方法中添加到widget樹(shù)中。首先,找到創(chuàng)建圖標(biāo)和文本的代碼,并刪除它:
// ...
new Icon(
Icons.star,
color: Colors.red[500],
),
new Text('41')
// ...
在相同的位置創(chuàng)建stateful widget:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget titleSection = new Container(
// ...
child: new Row(
children: [
new Expanded(
child: new Column(
// ...
),
new FavoriteWidget(),
],
),
);
return new MaterialApp(
// ...
);
}
}
管理狀態(tài)
重點(diǎn)是什么?
- 有多種方法可以管理狀態(tài).
- 選擇使用何種管理方法
- 如果不是很清楚時(shí), 那就在父widget中管理狀態(tài)吧.
誰(shuí)管理著stateful widget的狀態(tài)?widget本身?父widget?都會(huì)?另一個(gè)對(duì)象?答案是……這取決于實(shí)際情況。 有幾種有效的方法可以給你的widget添加互動(dòng)。作為小部件設(shè)計(jì)師。以下是管理狀態(tài)的最常見(jiàn)的方法:
- widget管理自己的state
- 父widget管理 widget狀態(tài)
- 混搭管理(父widget和widget自身都管理狀態(tài)))
如何決定使用哪種管理方法?以下原則可以幫助您決定:
- 如果狀態(tài)是用戶(hù)數(shù)據(jù),如復(fù)選框的選中狀態(tài)、滑塊的位置,則該狀態(tài)最好由父widget管理
- 如果所討論的狀態(tài)是有關(guān)界面外觀(guān)效果的,例如動(dòng)畫(huà),那么狀態(tài)最好由widget本身來(lái)管理.
如果有疑問(wèn),首選是在父widget中管理狀態(tài)
我們將通過(guò)創(chuàng)建三個(gè)簡(jiǎn)單示例來(lái)舉例說(shuō)明管理狀態(tài)的不同方式:TapboxA、TapboxB和TapboxC。 這些例子功能是相似的 - 每創(chuàng)建一個(gè)容器,當(dāng)點(diǎn)擊時(shí),在綠色或灰色框之間切換。 _active確定顏色:綠色為true,灰色為false。
widget管理自己的狀態(tài)
有時(shí),widget在內(nèi)部管理其狀態(tài)是最好的。例如, 當(dāng)ListView的內(nèi)容超過(guò)渲染框時(shí), ListView自動(dòng)滾動(dòng)。大多數(shù)使用ListView的開(kāi)發(fā)人員不想管理ListView的滾動(dòng)行為,因此ListView本身管理其滾動(dòng)偏移量。
_TapboxAState 類(lèi):
- 管理TapboxA的狀態(tài).
- 定義_active:確定盒子的當(dāng)前顏色的布爾值.
- 定義_handleTap()函數(shù),該函數(shù)在點(diǎn)擊該盒子時(shí)更新_active,并調(diào)用setState()更新UI.
- 實(shí)現(xiàn)widget的所有交互式行為.
// TapboxA 管理自身狀態(tài).
//------------------------- TapboxA ----------------------------------
class TapboxA extends StatefulWidget {
TapboxA({Key key}) : super(key: key);
@override
_TapboxAState createState() => new _TapboxAState();
}
class _TapboxAState extends State {
bool _active = false;
void _handleTap() {
setState(() {
_active = !_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],
),
),
);
}
}
//------------------------- MyApp ----------------------------------
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Flutter Demo'),
),
body: new Center(
child: new TapboxA(),
),
),
);
}
}
父widget管理widget的state
對(duì)于父widget來(lái)說(shuō),管理狀態(tài)并告訴其子widget何時(shí)更新通常是最有意義的。 例如,IconButton允許您將圖標(biāo)視為可點(diǎn)按的按鈕。 IconButton是一個(gè)無(wú)狀態(tài)的小部件,因?yàn)槲覀冋J(rèn)為父widget需要知道該按鈕是否被點(diǎn)擊來(lái)采取相應(yīng)的處理。
在以下示例中,TapboxB通過(guò)回調(diào)將其狀態(tài)導(dǎo)出到其父項(xiàng)。由于TapboxB不管理任何狀態(tài),因此它的父類(lèi)為StatelessWidget。
ParentWidgetState 類(lèi):
- 為T(mén)apboxB 管理_active狀態(tài).
- 實(shí)現(xiàn)_handleTapboxChanged(),當(dāng)盒子被點(diǎn)擊時(shí)調(diào)用的方法.
- 當(dāng)狀態(tài)改變時(shí),調(diào)用setState()更新UI.
TapboxB 類(lèi):
- 繼承StatelessWidget類(lèi),因?yàn)樗袪顟B(tài)都由其父widget處理.
- 當(dāng)檢測(cè)到點(diǎn)擊時(shí),它會(huì)通知父widget.
// ParentWidget 為 TapboxB 管理狀態(tài).
//------------------------ ParentWidget --------------------------------
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State {
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 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],
),
),
);
}
}
提示: 在創(chuàng)建API時(shí),請(qǐng)考慮使用@required為代碼所依賴(lài)的任何參數(shù)使用注解。
'package: flutter/foundation.dart';
混合管理
對(duì)于一些widget來(lái)說(shuō),混搭管理的方法最有意義的。在這種情況下,有狀態(tài)widget管理一些狀態(tài),并且父widget管理其他狀態(tài)。
在TapboxC示例中,點(diǎn)擊時(shí),盒子的周?chē)鷷?huì)出現(xiàn)一個(gè)深綠色的邊框。點(diǎn)擊時(shí),邊框消失,盒子的顏色改變。 TapboxC將其_active狀態(tài)導(dǎo)出到其父widget中,但在內(nèi)部管理其_highlight狀態(tài)。這個(gè)例子有兩個(gè)狀態(tài)對(duì)象_ParentWidgetState和_TapboxCState。
_ParentWidgetState 對(duì)象:
- 管理_active 狀態(tài).
- 實(shí)現(xiàn) _handleTapboxChanged(), 當(dāng)盒子被點(diǎn)擊時(shí)調(diào)用.
- 當(dāng)點(diǎn)擊盒子并且_active狀態(tài)改變時(shí)調(diào)用setState()更新UI
_TapboxCState 對(duì)象:
- 管理_highlight state.
- GestureDetector監(jiān)聽(tīng)所有tap事件。當(dāng)用戶(hù)點(diǎn)下時(shí),它添加高亮(深綠色邊框);當(dāng)用戶(hù)釋放時(shí),會(huì)移除高亮。
- 當(dāng)按下、抬起、或者取消點(diǎn)擊時(shí)更新_highlight狀態(tài),調(diào)用setState()更新UI。
- 當(dāng)點(diǎn)擊時(shí),將狀態(tài)的改變傳遞給父widget.
//---------------------------- ParentWidget ----------------------------
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
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 onChanged;
_TapboxCState createState() => new _TapboxCState();
}
class _TapboxCState extends State {
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);
}
Widget build(BuildContext context) {
// This example adds a green border on tap down.
// On tap up, the square changes to the opposite state.
return new GestureDetector(
onTapDown: _handleTapDown, // Handle the tap events in the order that
onTapUp: _handleTapUp, // they occur: down, up, tap, cancel
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,
),
),
);
}
}
另一種實(shí)現(xiàn)可能會(huì)將高亮狀態(tài)導(dǎo)出到父widget,同時(shí)保持_active狀態(tài)為內(nèi)部,但如果您要求某人使用該TapBox,他們可能會(huì)抱怨說(shuō)沒(méi)有多大意義。 開(kāi)發(fā)人員只會(huì)關(guān)心該框是否處于活動(dòng)狀態(tài)。開(kāi)發(fā)人員可能不在乎高亮顯示是如何管理的,并且傾向于讓TapBox處理這些細(xì)節(jié)。
其他交互式widgets
Flutter提供各種按鈕和類(lèi)似的交互式widget。這些widget中的大多數(shù)實(shí)現(xiàn)了Material Design 指南, 它們定義了一組具有質(zhì)感的UI組件。
如果你愿意,你可以使用GestureDetector來(lái)給任何自定義widget添加交互性。 您可以在管理狀態(tài)和Flutter Gallery中找到GestureDetector的示例。
注意: Futter還提供了一組名為Cupertino的iOS風(fēng)格的小部件 。
When you need interactivity, it’s easiest to use one of the prefabricated widgets. Here’s a partial list: 當(dāng)你需要交互性時(shí),最容易的是使用預(yù)制的widget。這是預(yù)置widget部分列表:
標(biāo)準(zhǔn) widgets:
- Form
- FormField
Material Components:
- Checkbox
- DropdownButton
- FlatButton
- FloatingActionButton
- IconButton
- Radio
- RaisedButton
- Slider
- Switch
- TextField
文章標(biāo)題:創(chuàng)新互聯(lián)Flutter教程:Flutter添加交互
文章起源:http://www.dlmjj.cn/article/djesdco.html


咨詢(xún)
建站咨詢(xún)
