Flutter基本組件Basics?Widget學(xué)習(xí)
1. 概述
上一篇說到,Basics Widget 并不是 Flutter 的一個專門的Widget類別,而是 Flutter 官方挑選一些開發(fā)常用的 Widget 構(gòu)成的,希望我們掌握到一些最基本的開發(fā)能力。
包括:
- 文本 Text
- 按鈕 Button
- 圖片 Image
- 單選框、復(fù)選框
- 輸入框、表單
- 指示器
- Container
- …
2. 常用組件
2.1 Text
Text 用于顯示簡單樣式文本,然后可以填充一些文本顯示樣式的屬性,如下例子:
Text("Hello World",
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textScaleFactor: 1.5);
textAlign
文本對齊方式maxLines、overflow
maxLines 指定文本顯示的最大行數(shù)。
當文本內(nèi)容超過最大行數(shù)時,overflow指定了階段方式, 例如ellipsis就是將多余的文本用 “…” 表示textScaleFactor
代表文本相對于當前字體大小的縮放因子,想你對于去設(shè)置文本的樣式 style 屬性的 fontSize, 它是調(diào)整字體大小的一個快捷方式, 該屬性的默認值可以通過MediaQueryData.textScaleFactor獲得, 如果沒有MediaQuery,那么會默認值為 1.0
2.1.1 TextStyle
TextStyle 用于指定文本樣式,例如顏色、字體、粗細、背景等,如下:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: Scaffold(
appBar: AppBar(
title: const Text("Basics Widget"),
),
body: Text(
"Hello World",
style: TextStyle(
color: Colors.blue,
fontSize: 19.0,
height: 2,
fontFamily: "Courier",
background: Paint()..color = Colors.yellow,
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.dashed),
)));
}
效果如圖:

一些屬性:
height
行高,它不是一個絕定的值,因為具體的行高為height*fontSize,同理行寬也是fontFamily
由于不同平臺默認支持的字體集不同,所以在手動指定字體時一定要先在不同平臺測試一下fontSize
改屬性和 Text 的textScaleFactor都用于控制字體大小,但是有兩個區(qū)別,
①:fontSize可以精確指定字體大小, 而 textScaleFactor 只能縮放比例
②:textScaleFactor主要是用于系統(tǒng)字體大小設(shè)置改變時,對Flutter 應(yīng)用字體進行全局調(diào)整,而 fontSzie通常用于單個文本,字體大小不會跟隨系統(tǒng)字體大小變化
2.1.2 TextSpan
如果我們需要對Text內(nèi)容不同部分按照不同的樣式顯示,就可以使用 TextSpan,代表文本的一個“片段”,看看 TextSpan的定義:
const TextSpan({
this.text,
this.children,
TextStyle? style,
this.recognizer,
MouseCursor? mouseCursor,
this.onEnter,
this.onExit,
this.semanticsLabel,
this.locale,
this.spellOut,
})
其中 style 和 text 代表樣式和文本內(nèi)容, children是 List<InlineSpan>? 類型,也就說 TextSpan 可以包含其他 Span
reconizer 用于表示該文本片段上用于手勢進行識別處理,下面我們看一個效果圖,然后用 TextSpan 來實現(xiàn):

body: const Text.rich(TextSpan(children: [
TextSpan(text: "Home: "),
TextSpan(
text: "https://flutterchina.club",
style: TextStyle(color: Colors.blue),
recognizer: _recognizer
),
]))));
這里的代碼,用 TextSpan實現(xiàn)了一個基礎(chǔ)文本和一個鏈接片段
Text.rich方法將TextSpan添加到 Text 中,之所以可以這樣做,是因為 Text 其實就是 RichText 的一個包裝,而 RichText 是可以顯示多種多樣的 widget_reconizer是點擊鏈接的處理器
2.1.3 DefaultTextStyle
在 Widget 樹中, 文本的樣式默認是可以被繼承的,因此如果 Widget樹的某一個節(jié)點處設(shè)置一個默認的文本樣式,那么該節(jié)點的子樹所有的文本都會默認使用這個樣式,而 DefaultTextStyle 正是用于設(shè)置默認文本樣式的,看下面例子:
DefaultTextStyle(
//1.設(shè)置文本默認樣式
style: TextStyle(
color:Colors.red,
fontSize: 20.0,
),
textAlign: TextAlign.start,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("hello world"),
Text("I am Jack"),
Text("I am Jack",
style: TextStyle(
inherit: false, //2.不繼承默認樣式
color: Colors.grey
),
),
],
),
);
這里的代碼首先設(shè)置了一個默認的樣式,字體大小為20,、顏色為紅色,然后將 DefaultTextStyle 設(shè)置給了子樹,這樣一來 Column 所有子孫 Text 默認都會繼承該樣式, 除非 Text 設(shè)置 inherit: false,如下所示:

2.1.4 使用字體
在 Flutter 中可以使用自定義的字體,或者其他第三方字體, 這里就不介紹配置了,具體可以看官方文檔:字體
2.2 Button
Material 組件庫提供了多種多樣的按鈕,他們都是直接或間接對 RawMaterialButton 的包裝定制,所以大部分屬性都一樣。另外 Marterial 庫中的按鈕都有以下共同點:
- 按下時都有水波紋
- 動畫統(tǒng)一用
onPressed屬性來設(shè)置回調(diào),當按鈕按下時會執(zhí)行該回調(diào),如果不提供回調(diào)則按鈕會處于禁用狀態(tài),不會響應(yīng)用戶點擊
2.2.1 ElevatedButton
即 帶陰影的按鈕, 默認帶有陰影和灰色背景,按下后陰影會變大,如下所示:

代碼如下:
child: ElevatedButton(
child: const Text("i am ElevatedButton"),
onPressed: () {},
),
),
2.2.2 TextButton
文本按鈕,按下后會有背景色,如下圖所示:

2.2.3 OutlinedButton
默認有一個邊框,不帶陰影且背景透明,按下后,邊框顏色會變亮、同時出現(xiàn)背景和陰影,如下圖所示:

2.2.4 IconButton
可以點擊的 Icon, 不包含文字,點擊后會出現(xiàn)背景,如下所示:


代碼設(shè)置為:
IconButton(
icon: Icon(Icons.eleven_mp),
onPressed: () {},
),
2.2.5 帶圖標的按鈕
上面學(xué)到的 ElevatedButton、 TextButton、 OutlinedButton 都有一個 icon() 的構(gòu)造函數(shù),這樣就可以代入一個圖片進去,例如設(shè)置:
ElevatedButton.icon(
icon: const Icon(Icons.send),
label: const Text("發(fā)送"),
onPressed: () {},
),
效果為(這里有編碼問題,可以無視):

2.3 圖片及Icon
2.3.1 圖片
可以通過 Image 組件來加載并顯示布局, Image 的數(shù)據(jù)源可以是
- asset
- 文件
- 內(nèi)存
- 網(wǎng)絡(luò)
2.3.1.1 ImageProvider
ImageProvider 是抽象類,主要定義了圖片的獲取接口 load(),從不同的數(shù)據(jù)源獲取圖片需要實現(xiàn)不同的 ImageProvider,如 AssetImage 是實現(xiàn)了從 Asset 中加載圖片, NetworkImage 則實現(xiàn)了從網(wǎng)絡(luò)中加載圖片。
2.3.1.2 Image Widget
Image 組件在構(gòu)建時有一個必選的 image 參數(shù),它對應(yīng)一個 ImageProvier,下面分別演示一下如何從 asset 和 網(wǎng)絡(luò)中加載圖片。
1.從 asset 中加載圖片
在工程根目錄下創(chuàng)建一個 images 目錄,并將圖片拷貝到該目錄。
接下來在 pubspec.yaml 文件的 flutter部分 中,寫入(注意縮進):
flutter:
..
assets:
- assets/images/bobo.jpg
最后在代碼中使用:
Image(
image: AssetImage("images/bobo.jpg"),
width: 100.0,
)
就能展示圖片。
(不過我這里遇到一個問題,使用手機運行Flutter應(yīng)用能正常展示圖片,但是使用 Chrome 模擬器會報錯,不知道是什么原因造成的

2.從網(wǎng)絡(luò)URL中加載圖片
直接使用代碼:
Image(
image: NetworkImage("https://www.wahaotu.com/uploads/allimg/201904/1554901831804910.jpg"),
width: 100.0,
)
可以正常展示圖片。
(不過這里出現(xiàn)了很上面一樣的問題,但是使用官方使用的url又能正常展示圖片
2.3.1.3 Image 參數(shù)
我們可以來看下 Image 的參數(shù),通過這些參數(shù)可以控制圖片外觀、大小、混合效果等。
const Image({
Key? key,
required this.image,
this.frameBuilder,
this.loadingBuilder,
this.errorBuilder,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width,
this.height,
this.color,
this.opacity,
this.colorBlendMode,
this.fit,
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.isAntiAlias = false,
this.filterQuality = FilterQuality.low,
})
width、height
設(shè)置圖片寬高,當不指定寬高時,會根據(jù)當前父容器的限制盡可能的顯示其原始大小,如果只設(shè)置其中一個,那么另一個屬性默認會按比例縮放fit
該屬性用于用于在圖片的顯示空間和圖片本身大小不同時指定圖片的適應(yīng)模式。適應(yīng)模式是在BoxFit中定義的,它是一個枚舉類型,有這些值:
①fill:拉伸填充滿顯示空間 ,圖片會便是
②cover:會按圖片的長寬比放大后居中填滿顯示空間,圖片不會變形,超出顯示部分會被剪裁
③contain:圖片默認適應(yīng)規(guī)則,圖片會保證圖片本身長寬比不變的情況下縮放以適應(yīng)當前的顯示空間
④fitWidth:圖片寬度會縮放到顯示空間的寬度,高度會按比例縮放,居中顯示,圖片不會變形
⑤fitHeight:和上面的反著來- ⑥
none:圖片沒有適應(yīng)策略,會在顯示空間內(nèi)顯示圖片

color和colorBlendMode:在圖片繪制時可以對每一個像素進行顏色混合處理,color指定混合色,而colorBlendMode指定混合模式下,因為用的比較少,這里就不做實例repeat:當圖片本身大小小于顯示空間時,指定圖片的重復(fù)規(guī)則,這里也不做展示
2.3.2 Icon
Android中有 svg 矢量圖, 而 Flutter 中的也有,就是 Icon,它有下面這些優(yōu)點:
- 體積小
- 因為是矢量圖,所以拉伸不會影響清晰程度
- 可以通過 TextSpan 和 文本混用
- 可以引用到文本樣式
Flutter 默認實現(xiàn)了一套Icon,在 pubspec.yaml 的配置文件可以看到:
flutter: uses-material-design: true
來看下官方的示例代碼:
String icons = "";
// accessible: 0xe03e
icons += "\uE03e";
// error: 0xe237
icons += " \uE237";
// fingerprint: 0xe287
icons += " \uE287";
Text(
icons,
style: TextStyle(
fontFamily: "MaterialIcons",
fontSize: 24.0,
color: Colors.green,
),
);
效果為:

為了不讓開發(fā)者碼點,F(xiàn)lutter 封裝了 IconData 和 Icon來專門顯示字體圖片,上面的例子也可以用下面方式實現(xiàn):
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.accessible,color: Colors.green),
Icon(Icons.error,color: Colors.green),
Icon(Icons.fingerprint,color: Colors.green),
],
)
我們也可以使用自定義的字體圖標,這里就不贅述了,可以看看官方示例:Icon自定義字體圖標
2.4 單選開關(guān)和復(fù)選框
Flutter 提供了 Material 風格的 開關(guān)Switch 和 復(fù)選框Checkbox,它們都繼承自 StatfulWidget,但是它們不會保存選中的狀態(tài),選中狀態(tài)是由父組件來管理的。 當 Switch 或者 Checkbox 被點擊時,會觸發(fā) onChanged 回調(diào),我們可以在此回調(diào)中處理選中狀態(tài)改變邏輯,下面看官方例子:
class SwitchAndCheckBoxTestRoute extends StatefulWidget {
@override
_SwitchAndCheckBoxTestRouteState createState() => _SwitchAndCheckBoxTestRouteState();
}
class _SwitchAndCheckBoxTestRouteState extends State<SwitchAndCheckBoxTestRoute> {
bool _switchSelected=true; //維護單選開關(guān)狀態(tài)
bool _checkboxSelected=true;//維護復(fù)選框狀態(tài)
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Switch(
value: _switchSelected,//當前狀態(tài)
onChanged:(value){
//重新構(gòu)建頁面
setState(() {
_switchSelected=value;
});
},
),
Checkbox(
value: _checkboxSelected,
activeColor: Colors.red, //選中時的顏色
onChanged:(value){
setState(() {
_checkboxSelected=value!;
});
} ,
)
],
);
}
}
代碼中需要維護 Switch 和 Checkbox 的選中狀態(tài),所以 Widget 繼承自 StatefulWidget。 在其 build 方法中分別狀態(tài)了 Switch 和 Checkbox, 并且用兩個 bool 值來維護分別的選中狀態(tài)。 當按鈕被點擊時,會回調(diào) onChanged 回調(diào)選中狀態(tài)出去,此時我們需要調(diào)用 setState() 方法來觸發(fā) Flutter 重繪。
為什么要這樣子設(shè)計,我的理解是:
- 將開關(guān)、復(fù)選框的狀態(tài)拋給父組件,可以更加靈活,比如在勾選時候做一些網(wǎng)絡(luò)請求,即異步的操作
- 一般來說,這些item是否選中,是和用戶數(shù)據(jù)關(guān)聯(lián)的,用戶數(shù)據(jù)也不可能是他們的私有狀態(tài),所以放在一起管理更好
2.4.1 屬性
它們的屬性比較簡單,常用的有:
activeColor:設(shè)置激活狀態(tài)的顏色tristate: 是否為三態(tài),僅 Checbox有,一般情況下只有 “true” 和 “false”,表示選中和非選中,如果設(shè)置了tristate后,還會增加一個 “null” 狀態(tài)
此外, Checkbox 不可設(shè)置寬高,其大小是自定義的,而 Switch 也僅能設(shè)置寬度而已。
2.5 輸入框以及表單
Flutter Material組件提供了 輸入款TextField 和 表單Form
2.5.1 輸入框 TextField
2.5.1.1 屬性
來看下 TextField 提供的屬性:
const TextField({
...
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType? keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.strutStyle,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.readOnly = false,
ToolbarOptions? toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscuringCharacter = '?',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
this.enableSuggestions = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.maxLengthEnforcement,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.onAppPrivateCommand,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorHeight,
this.cursorRadius,
this.cursorColor,
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.selectionControls,
this.onTap,
this.mouseCursor,
this.buildCounter,
this.scrollController,
this.scrollPhysics,
this.autofillHints,
this.restorationId,
this.enableIMEPersonalizedLearning = true,
})
屬性比較多,列幾個關(guān)鍵的講解:
controller
編輯框的控制器,通過它可以設(shè)置/獲取編輯框的內(nèi)容、選擇編輯內(nèi)容、監(jiān)聽編輯文本改變事件。大多數(shù)情況下我們都需要顯示提供一個controller來與文本框交互,如果設(shè)置的話, TextField 內(nèi)部會創(chuàng)建一個focusNode
用于控制TextField是否占有當前鍵盤的輸入焦點InputDecoration
用于控制 TextField 的外觀顯示,如提示文本、背景顏色、邊框等。keyboardType
用于設(shè)置該輸入框默認的鍵盤輸入類型, 有文本、電話、email等格式textInputAction
鍵盤動作按鈕圖標,就是右下角的那個圖標設(shè)置style
文本的樣式(正在編輯中的)textAlign
輸入框內(nèi)編輯文本在水平方向的對齊方式autofocus
是否自動獲取焦點obscureText
是否隱藏正在編輯的文本, 比如輸入密碼的場景,文本內(nèi)容會用 “?” 來代替maxLines
最大行數(shù)maxLenth和maxLengthEnforcement
maxLenth代表輸入框文本的最大長度,設(shè)置后輸入框右下角會顯示輸入的文本計數(shù)
maxLengthEnforcement決定輸入文本長度超過maxLength時如何處理,如截斷toolbarOptions
長按時出現(xiàn)的菜單,可以選擇 copy、cut、paste 、selectAll- onChange
輸入框內(nèi)容改變的回調(diào), 當然controller也可以做到監(jiān)聽 onEditingComplete、onSubmitted
作用一樣,都是在輸入完成時觸發(fā),比如點擊了鍵盤的 完成鍵、搜索鍵不同的是兩個回調(diào)簽名不同inputFormatters
指定輸入格式,當用戶輸入內(nèi)容改變時,會根據(jù)指定格式來校驗enable
如果為false, 則輸入框會被禁用cursorWidth、cursorRadius、cursorColor
分別表示自定義輸入框光標寬度、圓角和顏色
一個簡單的設(shè)置代碼如下:
Column(children: const <Widget>[
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: "用戶名",
hintText: "請輸入用戶名或密碼",
prefixIcon: Icon(Icons.person)
),
),
TextField(
decoration: InputDecoration(
labelText: "密碼",
hintText: "請輸入密碼",
prefixIcon: Icon(Icons.lock)
),
obscureText: true,
)
]),

2.5.1.2 通過 controller 獲取輸入內(nèi)容
我們可以通過 onChange 拿到內(nèi)容。 當然也可以使用 controller 來獲取
步驟為:
定義一個 controller:
final TextEditingController _tfController = TextEditingController();
然后在 TextFiled 中傳入這個 controller
TextField( controller: _tfController, ... )
最后就可以通過 : print(_tfController.text) 來獲得輸入框的內(nèi)容
2.5.1.3 通過 controller 監(jiān)聽文本內(nèi)容變化
可以通過 onChange 來監(jiān)聽文本, controller 可以通過設(shè)置監(jiān)聽器來監(jiān)聽文本,如下:
@override
void initState() {
super.initState();
_tfController.addListener(() {
print(_tfController.text);
});
}
controller 的功能更多,除了監(jiān)聽文本,還可以設(shè)置默認值、選擇文本等,這里就不多贅述。
2.5.1.4 控制焦點
可以使用 FocusNode 和 FocusScopeNode 來控制焦點。默認情況下是由 FocusScope 來管理,可以在這個范圍內(nèi)通過 FocusScopeNode 在輸入框之間移動焦點、設(shè)置默認焦點。
我們可以通過下面代碼來獲取當前 Widget 樹中默認的 FocusScopeNode:
focusScopeNode = FocusScope.of(context)
拿到句柄后,可以使用下面代碼來獲取焦點:
focusScopeNode.requestFocus(focusNode);
其中 focucsNode 是為 TextField 創(chuàng)建的 FocusNode, 這個操作可以讓該 TextField 獲取焦點。 調(diào)用 focusNode.unfocus() 可以取消焦點。
2.5.1.5 監(jiān)聽焦點狀態(tài)改變事件
通過 FocusNode 可以監(jiān)聽焦點改變的事件:
focusNode.addListener((){
print(focusNode.hasFocus);
})
true為獲取焦點,false為失去焦點
2.5.2 表單
表單Form 對輸入框進行分組和統(tǒng)一操作。 就像 Android 的原生組件 RadioGroup 之于 RadioButton 一樣, Form 可以管理內(nèi)容校驗、輸入框重置等。
Form 繼承自 StatefulWidget,其狀態(tài)管理在 FormState 里面,來看看 From 的定義:
class Form extends StatefulWidget {
const Form({
Key? key,
required this.child,
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
this.autovalidate = false,
this.onWillPop,
this.onChanged,
AutovalidateMode? autovalidateMode,
})
...
autovalidate
是否自動校驗輸入內(nèi)容,當為true時,每一個 FormField 內(nèi)容發(fā)生變化時都會校驗合法性,并直接顯示錯誤信息,否則就需要通過調(diào)用FormState.validate()來手動校驗
v1.19 已經(jīng)廢棄了,改成使用AutovalidateModeautovalidateMode
自動校驗?zāi)J?,是上面的替換,它有三個枚舉值:
①disable:當 FormField 內(nèi)容改變時不做校驗
②always:即使用戶沒有用戶交互也要校驗合法性
③onUserInteraction:只有在用戶交互時才會去校驗合法性onWillPop
決定Form所在的路由是否可以直接返回。該回調(diào)返回一個Future對象,如果 Future 的最終結(jié)果是 false,則當前路由不會返回,如果為 true,則會返回到上一個路由。
這個屬性通常是用于攔截返回按鈕的onChanged
Form 的任意一個 FormField 內(nèi)容發(fā)生改變時就會調(diào)用該方法
2.5.2.1 FormField
Form 的子孫元素是 FormField 類型,F(xiàn)ormField 是一個抽象類,定義了幾個屬性, FormState 內(nèi)部通過他們來完成操作, FormField 部分定義如下:
const FormField({
Key? key,
required this.builder,
this.onSaved,
this.validator,
this.initialValue,
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
this.autovalidate = false,
this.enabled = true,
AutovalidateMode? autovalidateMode,
this.restorationId,
})
onSaved
保存時的回調(diào)validator
驗證合法性的回調(diào)initValue
初始值
為了方便使用, Flutter 提供了一個 TextFormFild 組件,繼承自 FormField 類,還包裝了 TextFileld ,可以直接當成 Form 的 FormField 來使用, 相當于用 Form 來管理 TextField
2.5.2.2 FormState
Form 表單的狀態(tài)類就是 FormState, 可以通過 Form.of 或者 GlobalKey 獲得,通過獲得它來對 Form 的子孫 FormField 進行統(tǒng)一操作。
FormState 常用的三個方法:
FormState.validate():調(diào)用此方法后, 會調(diào)用Form子孫FormField.validate()回調(diào),如果有一個檢驗失敗,那么會返回 false,這樣所有校驗失敗的 Widget 都會給出錯誤提示FormState.save():調(diào)用此方法后,會調(diào)用 子孫的FormFild.save()回調(diào),用于保存表單內(nèi)容FormState.reset(): 會將子孫 FormField 的內(nèi)容清空
2.5.2.3 示例
我們做一個用戶登錄的程序,再點擊登錄前需要做到輸入檢查:
- 用戶名不能為空,如果為空則提示“用戶名不能為空”
- 密碼不能小于6位,如果小于6位則提示 “密碼不能少于6位”
代碼如下:
import 'package:flutter/material.dart';
class FormTestRoute extends StatefulWidget {
const FormTestRoute({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _FormTestRouteState();
}
class _FormTestRouteState extends State<FormTestRoute> {
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final GlobalKey _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Form demo'),
),
body: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
TextFormField(
autofocus: true,
controller: _usernameController,
decoration: const InputDecoration(
labelText: "username",
hintText: "username or email",
icon: Icon(Icons.person)),
validator: (username) {
return username!.trim().isNotEmpty
? null
: "username cannot empty";
},
),
TextFormField(
controller: _passwordController,
decoration: const InputDecoration(
labelText: "password",
hintText: "please input your password",
icon: Icon(Icons.lock)),
obscureText: true,
validator: (pwd) {
return pwd!.trim().length >= 6
? null
: "password digit cannot less than 6!";
},
),
// login button
Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
if ((_formKey.currentState as FormState).validate()) {
print("Loing success");
}
},
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Text("Login"),
),
))
],
),
)
],
)));
}
}
效果如下圖所示:

以上所述是小編給大家介紹的Flutter基本組件Basics Widget學(xué)習(xí),希望對大家有所幫助。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android自定義view實現(xiàn)電影票在線選座功能
這篇文章主要為大家詳細介紹了Android自定義view實現(xiàn)選座功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
Android實現(xiàn)點擊獲取驗證碼60秒后重新獲取功能
這篇文章主要為大家詳細介紹了Android點擊獲取驗證碼60秒后重新獲取驗證碼的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
android的消息處理機制(圖文+源碼分析)—Looper/Handler/Message
這篇文章寫的非常好,深入淺出;android的消息處理機制(圖+源碼分析)—Looper,Handler,Message是一位大三學(xué)生自己剖析的心得,感興趣的朋友可以了解下哦,希望對你有所幫助2013-01-01
Flutter開發(fā)之路由與導(dǎo)航的實現(xiàn)
這篇文章主要介紹了Flutter開發(fā)之路由與導(dǎo)航的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Android ListView與ScrollView沖突的解決方法總結(jié)
這篇文章主要介紹了Android ListView與ScrollView沖突的解決方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-04-04

