創建一(yī)個有狀态的widget
重點:
要(yào)創建一(yī)個自(zì)定義有狀态widget,需創建兩個類:StatefulWidget和(hé)State
狀态對象包含widget的狀态和(hé)build() 方法。
當widget的狀态改變時(shí),狀态對象調用setState(),告訴框架重繪widget
在本節中,您将創建一(yī)個自(zì)定義有狀态的widget。 您将使用一(yī)個自(zì)定義有狀态widget來替換兩個無狀态widget - 紅(hóng)色實心星形圖标和(hé)其旁邊的數(shù)字計數(shù) - 該widget用兩個子widget管理一(yī)行(xíng):IconButton和(hé)Text。
實現一(yī)個自(zì)定義的有狀态widget需要(yào)創建兩個類:
定義一(yī)個widget類,繼承自(zì)StatefulWidget.
包含該widget狀态并定義該widget build()方法的類,它繼承自(zì)State.
本節展示如(rú)何為(wèi)Lakes應用程序構建一(yī)個名為(wèi)FavoriteWidget的StatefulWidget。第一(yī)步是選擇如(rú)何管理FavoriteWidget的狀态。
Step 1: 決定哪個對象管理widget的狀态
Widget的狀态可(kě)以通(tōng)過多種方式進行(xíng)管理,但(dàn)在我們的示例中,widget本身(FavoriteWidget)将管理自(zì)己的狀态。 在這(zhè)個例子中,切換星形圖标是一(yī)個獨立的操作(zuò),不會影響父窗口widget或其他(tā)用戶界面,因此該widget可(kě)以在內(nèi)部處理它自(zì)己的狀态。
Step 2: 創建StatefulWidget子類
FavoriteWidget類管理自(zì)己的狀态,因此它重寫createState()來創建狀态對象。 框架會在構建widget時(shí)調用createState()。在這(zhè)個例子中,createState()創建_FavoriteWidgetState的實例,您将在下(xià)一(yī)步中實現該實例。
class FavoriteWidget extends StatefulWidget {
@override
_FavoriteWidgetState createState() => new _FavoriteWidgetState();
}
注意: 以下(xià)劃線(_)開(kāi)頭的成員(yuán)或類是私有的。有關更多信息,請(qǐng)參閱Dart語言參考中的庫和(hé)可(kě)見(jiàn)性部分 。
Step 3: 創建State子類
自(zì)定義State類存儲可(kě)變信息 - 可(kě)以在widget的生命周期內(nèi)改變邏輯和(hé)內(nèi)部狀态。 當應用第一(yī)次啓動時(shí),用戶界面顯示一(yī)個紅(hóng)色實心的星星形圖标,表明(míng)該湖已經被收藏,并有41個“喜歡”。狀态對象存儲這(zhè)些信息在_isFavorited和(hé)_favoriteCount變量。
狀态對象也定義了(le)build方法。此build方法創建一(yī)個包含紅(hóng)色IconButton和(hé)Text的行(xíng)。 該widget使用IconButton(而不是Icon), 因為(wèi)它具有一(yī)個onPressed屬性,該屬性定義了(le)處理點擊的回調方法。IconButton也有一(yī)個icon的屬性,持有Icon。
按下(xià)IconButton時(shí)會調用_toggleFavorite()方法,然後它會調用setState()。 調用setState()是至關重要(yào)的,因為(wèi)這(zhè)告訴框架,widget的狀态已經改變,應該重繪。 _toggleFavorite在: 1)實心的星形圖标和(hé)數(shù)字“41” 和(hé) 2)虛心的星形圖标和(hé)數(shù)字“40”之間(jiān)切換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'),
),
),
],
);
}
}
提示: 當文本在40和(hé)41之間(jiān)變化時(shí),将文本放在SizedBox中并設置其寬度可(kě)防止出現明(míng)顯的“跳(tiào)躍” ,因為(wèi)這(zhè)些值具有不同的寬度。
Step 4: 将有stateful widget插入widget樹(shù)中
将您自(zì)定義stateful widget在build方法中添加到widget樹(shù)中。首先,找到創建圖标和(hé)文本的代碼,并删除它:
// ...
new Icon(
Icons.star,
color: Colors.red[500],
),
new Text('41')
// ...
在相同的位置創建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(
// ...
);
}
}
管理狀态
重點是什麽?
有多種方法可(kě)以管理狀态.
選擇使用何種管理方法
如(rú)果不是很(hěn)清楚時(shí), 那(nà)就在父widget中管理狀态吧.
誰管理着stateful widget的狀态?widget本身?父widget?都(dōu)會?另一(yī)個對象?答(dá)案是……這(zhè)取決于實際情況。 有幾種有效的方法可(kě)以給你的widget添加互動。作(zuò)為(wèi)小部件設計師(shī)。以下(xià)是管理狀态的最常見(jiàn)的方法:
widget管理自(zì)己的state
父widget管理 widget狀态
混搭管理(父widget和(hé)widget自(zì)身都(dōu)管理狀态))
如(rú)何決定使用哪種管理方法?以下(xià)原則可(kě)以幫助您決定:
如(rú)果狀态是用戶數(shù)據,如(rú)複選框的選中狀态、滑塊的位置,則該狀态最好由父widget管理
如(rú)果所讨論的狀态是有關界面外(wài)觀效果的,例如(rú)動畫(huà),那(nà)麽狀态最好由widget本身來管理.
如(rú)果有疑問(wèn),首選是在父widget中管理狀态
我們将通(tōng)過創建三個簡單示例來舉例說明(míng)管理狀态的不同方式:TapboxA、TapboxB和(hé)TapboxC。 這(zhè)些例子功能(néng)是相似的 - 每創建一(yī)個容器,當點擊時(shí),在綠(lǜ)色或灰色框之間(jiān)切換。 _active确定顔色:綠(lǜ)色為(wèi)true,灰色為(wèi)false。
a large green box with the text, 'Active' a large grey box with the text, 'Inactive'
widget管理自(zì)己的狀态
有時(shí),widget在內(nèi)部管理其狀态是最好的。例如(rú), 當ListView的內(nèi)容超過渲染框時(shí), ListView自(zì)動滾動。大多數(shù)使用ListView的開(kāi)發人(rén)員(yuán)不想管理ListView的滾動行(xíng)為(wèi),因此ListView本身管理其滾動偏移量。
_TapboxAState 類:
管理TapboxA的狀态.
定義_active:确定盒子的當前顔色的布爾值.
定義_handleTap()函數(shù),該函數(shù)在點擊該盒子時(shí)更新_active,并調用setState()更新UI.
實現widget的所有交互式行(xíng)為(wèi).
// TapboxA 管理自(zì)身狀态.
//------------------------- 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
對于父widget來說,管理狀态并告訴其子widget何時(shí)更新通(tōng)常是最有意義的。 例如(rú),IconButton允許您将圖标視(shì)為(wèi)可(kě)點按的按鈕。 IconButton是一(yī)個無狀态的小部件,因為(wèi)我們認為(wèi)父widget需要(yào)知道(dào)該按鈕是否被點擊來采取相應的處理。
在以下(xià)示例中,TapboxB通(tōng)過回調将其狀态導出到其父項。由于TapboxB不管理任何狀态,因此它的父類為(wèi)StatelessWidget。
ParentWidgetState 類:
為(wèi)TapboxB 管理_active狀态.
實現_handleTapboxChanged(),當盒子被點擊時(shí)調用的方法.
當狀态改變時(shí),調用setState()更新UI.
TapboxB 類:
繼承StatelessWidget類,因為(wèi)所有狀态都(dōu)由其父widget處理.
當檢測到點擊時(shí),它會通(tōng)知父widget.
// ParentWidget 為(wèi) TapboxB 管理狀态.
//------------------------ 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
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],
),
),
);
}
}
提示: 在創建API時(shí),請(qǐng)考慮使用@required為(wèi)代碼所依賴的任何參數(shù)使用注解。
'package: flutter/foundation.dart';
混合管理
對于一(yī)些widget來說,混搭管理的方法最有意義的。在這(zhè)種情況下(xià),有狀态widget管理一(yī)些狀态,并且父widget管理其他(tā)狀态。
在TapboxC示例中,點擊時(shí),盒子的周圍會出現一(yī)個深綠(lǜ)色的邊框。點擊時(shí),邊框消失,盒子的顔色改變。 TapboxC将其_active狀态導出到其父widget中,但(dàn)在內(nèi)部管理其_highlight狀态。這(zhè)個例子有兩個狀态對象_ParentWidgetState和(hé)_TapboxCState。
_ParentWidgetState 對象:
管理_active 狀态.
實現 _handleTapboxChanged(), 當盒子被點擊時(shí)調用.
當點擊盒子并且_active狀态改變時(shí)調用setState()更新UI
_TapboxCState 對象:
管理_highlight state.
GestureDetector監聽所有tap事件。當用戶點下(xià)時(shí),它添加高亮(深綠(lǜ)色邊框);當用戶釋放時(shí),會移除高亮。
當按下(xià)、擡起、或者取消點擊時(shí)更新_highlight狀态,調用setState()更新UI。
當點擊時(shí),将狀态的改變傳遞給父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
_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,
),
),
);
}
}
另一(yī)種實現可(kě)能(néng)會将高亮狀态導出到父widget,同時(shí)保持_active狀态為(wèi)內(nèi)部,但(dàn)如(rú)果您要(yào)求某人(rén)使用該TapBox,他(tā)們可(kě)能(néng)會抱怨說沒有多大意義。 開(kāi)發人(rén)員(yuán)隻會關心該框是否處于活動狀态。開(kāi)發人(rén)員(yuán)可(kě)能(néng)不在乎高亮顯示是如(rú)何管理的,并且傾向于讓TapBox處理這(zhè)些細節。
其他(tā)交互式widgets
Flutter提供各種按鈕和(hé)類似的交互式widget。這(zhè)些widget中的大多數(shù)實現了(le)Material Design 指南, 它們定義了(le)一(yī)組具有質感的UI組件。
如(rú)果你願意,你可(kě)以使用GestureDetector來給任何自(zì)定義widget添加交互性。 您可(kě)以在管理狀态和(hé)Flutter Gallery中找到GestureDetector的示例。
注意: Futter還提供了(le)一(yī)組名為(wèi)Cupertino的iOS風(fēng)格的小部件 。
When you need interactivity, it’s easiest to use one of the prefabricated widgets. Here’s a partial list: 當你需要(yào)交互性時(shí),最容易的是使用預制的widget。這(zhè)是預置widget部分列表:
标準 widgets:
Form
FormField
Material Components:
Checkbox
DropdownButton
FlatButton
FloatingActionButton
IconButton
Radio
RaisedButton
Slider
Switch
TextField
網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發