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