您好,登錄后才能下訂單哦!
這篇文章主要介紹Flutter基本組件Basics Widget怎么用,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
Basics Widget 并不是 Flutter 的一個專門的Widget類別,而是 Flutter 官方挑選一些開發(fā)常用的 Widget 構(gòu)成的,希望我們掌握到一些最基本的開發(fā)能力。
包括:
文本 Text
按鈕 Button
圖片 Image
單選框、復(fù)選框
輸入框、表單
指示器
Container
…
Text
用于顯示簡單樣式文本,然后可以填充一些文本顯示樣式的屬性,如下例子:
Text("Hello World", textAlign: TextAlign.left, maxLines: 1, overflow: TextOverflow.ellipsis, textScaleFactor: 1.5);
textAlign
文本對齊方式
maxLines
、 overflow
maxLines 指定文本顯示的最大行數(shù)。
當(dāng)文本內(nèi)容超過最大行數(shù)時, overflow
指定了階段方式, 例如 ellipsis
就是將多余的文本用 “…” 表示
textScaleFactor
代表文本相對于當(dāng)前字體大小的縮放因子,想你對于去設(shè)置文本的樣式 style 屬性的 fontSize, 它是調(diào)整字體大小的一個快捷方式, 該屬性的默認(rèn)值可以通過 MediaQueryData.textScaleFactor
獲得, 如果沒有 MediaQuery
,那么會默認(rèn)值為 1.0
TextStyle
用于指定文本樣式,例如顏色、字體、粗細(xì)、背景等,如下:
@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
由于不同平臺默認(rèn)支持的字體集不同,所以在手動指定字體時一定要先在不同平臺測試一下
fontSize
改屬性和 Text 的 textScaleFactor
都用于控制字體大小,但是有兩個區(qū)別,
①:fontSize
可以精確指定字體大小, 而 textScaleFactor 只能縮放比例
②: textScaleFactor
主要是用于系統(tǒng)字體大小設(shè)置改變時,對Flutter 應(yīng)用字體進(jìn)行全局調(diào)整,而 fontSzie通常用于單個文本,字體大小不會跟隨系統(tǒng)字體大小變化
如果我們需要對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
用于表示該文本片段上用于手勢進(jìn)行識別處理,下面我們看一個效果圖,然后用 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
是點(diǎn)擊鏈接的處理器
在 Widget 樹中, 文本的樣式默認(rèn)是可以被繼承的,因此如果 Widget樹的某一個節(jié)點(diǎn)處設(shè)置一個默認(rèn)的文本樣式,那么該節(jié)點(diǎn)的子樹所有的文本都會默認(rèn)使用這個樣式,而 DefaultTextStyle
正是用于設(shè)置默認(rèn)文本樣式的,看下面例子:
DefaultTextStyle( //1.設(shè)置文本默認(rèn)樣式 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.不繼承默認(rèn)樣式 color: Colors.grey ), ), ], ), );
這里的代碼首先設(shè)置了一個默認(rèn)的樣式,字體大小為20,、顏色為紅色,然后將 DefaultTextStyle
設(shè)置給了子樹,這樣一來 Column 所有子孫 Text 默認(rèn)都會繼承該樣式, 除非 Text 設(shè)置 inherit: false
,如下所示:
在 Flutter 中可以使用自定義的字體,或者其他第三方字體, 這里就不介紹配置了,具體可以看官方文檔:字體
Material 組件庫提供了多種多樣的按鈕,他們都是直接或間接對 RawMaterialButton
的包裝定制,所以大部分屬性都一樣。另外 Marterial 庫中的按鈕都有以下共同點(diǎn):
按下時都有水波紋
動畫統(tǒng)一用 onPressed
屬性來設(shè)置回調(diào),當(dāng)按鈕按下時會執(zhí)行該回調(diào),如果不提供回調(diào)則按鈕會處于禁用狀態(tài),不會響應(yīng)用戶點(diǎn)擊
即 帶陰影的按鈕, 默認(rèn)帶有陰影和灰色背景,按下后陰影會變大,如下所示:
代碼如下:
child: ElevatedButton( child: const Text("i am ElevatedButton"), onPressed: () {}, ), ),
文本按鈕,按下后會有背景色,如下圖所示:
默認(rèn)有一個邊框,不帶陰影且背景透明,按下后,邊框顏色會變亮、同時出現(xiàn)背景和陰影,如下圖所示:
可以點(diǎn)擊的 Icon, 不包含文字,點(diǎn)擊后會出現(xiàn)背景,如下所示:
代碼設(shè)置為:
IconButton( icon: Icon(Icons.eleven_mp), onPressed: () {}, ),
上面學(xué)到的 ElevatedButton
、 TextButton
、 OutlinedButton
都有一個 icon()
的構(gòu)造函數(shù),這樣就可以代入一個圖片進(jìn)去,例如設(shè)置:
ElevatedButton.icon( icon: const Icon(Icons.send), label: const Text("發(fā)送"), onPressed: () {}, ),
效果為(這里有編碼問題,可以無視):
可以通過 Image
組件來加載并顯示布局, Image
的數(shù)據(jù)源可以是
asset
文件
內(nèi)存
網(wǎng)絡(luò)
ImageProvider
是抽象類,主要定義了圖片的獲取接口 load()
,從不同的數(shù)據(jù)源獲取圖片需要實現(xiàn)不同的 ImageProvider
,如 AssetImage
是實現(xiàn)了從 Asset 中加載圖片, NetworkImage
則實現(xiàn)了從網(wǎng)絡(luò)中加載圖片。
Image
組件在構(gòu)建時有一個必選的 image
參數(shù),它對應(yīng)一個 ImageProvier
,下面分別演示一下如何從 asset 和 網(wǎng)絡(luò)中加載圖片。
在工程根目錄下創(chuàng)建一個 images 目錄,并將圖片拷貝到該目錄。
接下來在 pubspec.yaml
文件的 flutter部分 中,寫入(注意縮進(jìn)):
flutter: .. assets: - assets/images/bobo.jpg
最后在代碼中使用:
Image( image: AssetImage("images/bobo.jpg"), width: 100.0, )
就能展示圖片。
(不過我這里遇到一個問題,使用手機(jī)運(yùn)行Flutter應(yīng)用能正常展示圖片,但是使用 Chrome 模擬器會報錯,不知道是什么原因造成的
直接使用代碼:
Image( image: NetworkImage("https://www.wahaotu.com/uploads/allimg/201904/1554901831804910.jpg"), width: 100.0, )
可以正常展示圖片。
(不過這里出現(xiàn)了很上面一樣的問題,但是使用官方使用的url又能正常展示圖片
我們可以來看下 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è)置圖片寬高,當(dāng)不指定寬高時,會根據(jù)當(dāng)前父容器的限制盡可能的顯示其原始大小,如果只設(shè)置其中一個,那么另一個屬性默認(rèn)會按比例縮放
fit
該屬性用于用于在圖片的顯示空間和圖片本身大小不同時指定圖片的適應(yīng)模式。適應(yīng)模式是在 BoxFit
中定義的,它是一個枚舉類型,有這些值:
①fill
:拉伸填充滿顯示空間 ,圖片會便是
②cover
:會按圖片的長寬比放大后居中填滿顯示空間,圖片不會變形,超出顯示部分會被剪裁
③contain
:圖片默認(rèn)適應(yīng)規(guī)則,圖片會保證圖片本身長寬比不變的情況下縮放以適應(yīng)當(dāng)前的顯示空間
④fitWidth
:圖片寬度會縮放到顯示空間的寬度,高度會按比例縮放,居中顯示,圖片不會變形
⑤fitHeight
:和上面的反著來
⑥none
:圖片沒有適應(yīng)策略,會在顯示空間內(nèi)顯示圖片
color
和 colorBlendMode
:在圖片繪制時可以對每一個像素進(jìn)行顏色混合處理,color
指定混合色,而 colorBlendMode
指定混合模式下,因為用的比較少,這里就不做實例
repeat
:當(dāng)圖片本身大小小于顯示空間時,指定圖片的重復(fù)規(guī)則,這里也不做展示
Android中有 svg 矢量圖, 而 Flutter 中的也有,就是 Icon
,它有下面這些優(yōu)點(diǎn):
體積小
因為是矢量圖,所以拉伸不會影響清晰程度
可以通過 TextSpan 和 文本混用
可以引用到文本樣式
Flutter 默認(rèn)實現(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ā)者碼點(diǎn),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), ], )
我們也可以使用自定義的字體圖標(biāo),這里就不贅述了,可以看看官方示例:Icon自定義字體圖標(biāo)
Flutter 提供了 Material 風(fēng)格的 開關(guān)Switch
和 復(fù)選框Checkbox
,它們都繼承自 StatfulWidget
,但是它們不會保存選中的狀態(tài),選中狀態(tài)是由父組件來管理的。 當(dāng) Switch
或者 Checkbox
被點(diǎn)擊時,會觸發(fā) onChanged
回調(diào),我們可以在此回調(diào)中處理選中狀態(tài)改變邏輯,下面看官方例子:
class SwitchAndCheckBoxTestRoute extends StatefulWidget { @override _SwitchAndCheckBoxTestRouteState createState() => _SwitchAndCheckBoxTestRouteState(); } class _SwitchAndCheckBoxTestRouteState extends State<SwitchAndCheckBoxTestRoute> { bool _switchSelected=true; //維護(hù)單選開關(guān)狀態(tài) bool _checkboxSelected=true;//維護(hù)復(fù)選框狀態(tài) @override Widget build(BuildContext context) { return Column( children: <Widget>[ Switch( value: _switchSelected,//當(dāng)前狀態(tài) onChanged:(value){ //重新構(gòu)建頁面 setState(() { _switchSelected=value; }); }, ), Checkbox( value: _checkboxSelected, activeColor: Colors.red, //選中時的顏色 onChanged:(value){ setState(() { _checkboxSelected=value!; }); } , ) ], ); } }
代碼中需要維護(hù) Switch
和 Checkbox
的選中狀態(tài),所以 Widget 繼承自 StatefulWidget
。 在其 build
方法中分別狀態(tài)了 Switch 和 Checkbox, 并且用兩個 bool 值來維護(hù)分別的選中狀態(tài)。 當(dāng)按鈕被點(diǎn)擊時,會回調(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),所以放在一起管理更好
它們的屬性比較簡單,常用的有:
activeColor
:設(shè)置激活狀態(tài)的顏色
tristate
: 是否為三態(tài),僅 Checbox有,一般情況下只有 “true” 和 “false”,表示選中和非選中,如果設(shè)置了 tristate
后,還會增加一個 “null” 狀態(tài)
此外, Checkbox 不可設(shè)置寬高,其大小是自定義的,而 Switch 也僅能設(shè)置寬度而已。
Flutter Material組件提供了 輸入款TextField
和 表單Form
來看下 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
是否占有當(dāng)前鍵盤的輸入焦點(diǎn)
InputDecoration
用于控制 TextField 的外觀顯示,如提示文本、背景顏色、邊框等。
keyboardType
用于設(shè)置該輸入框默認(rèn)的鍵盤輸入類型, 有文本、電話、email等格式
textInputAction
鍵盤動作按鈕圖標(biāo),就是右下角的那個圖標(biāo)設(shè)置
style
文本的樣式(正在編輯中的)
textAlign
輸入框內(nèi)編輯文本在水平方向的對齊方式
autofocus
是否自動獲取焦點(diǎn)
obscureText
是否隱藏正在編輯的文本, 比如輸入密碼的場景,文本內(nèi)容會用 “?” 來代替
maxLines
最大行數(shù)
maxLenth
和 maxLengthEnforcement
maxLenth
代表輸入框文本的最大長度,設(shè)置后輸入框右下角會顯示輸入的文本計數(shù)maxLengthEnforcement
決定輸入文本長度超過 maxLength
時如何處理,如截斷
toolbarOptions
長按時出現(xiàn)的菜單,可以選擇 copy、cut、paste 、selectAll
onChange
輸入框內(nèi)容改變的回調(diào), 當(dāng)然 controller
也可以做到監(jiān)聽
onEditingComplete
、onSubmitted
作用一樣,都是在輸入完成時觸發(fā),比如點(diǎn)擊了鍵盤的 完成鍵、搜索鍵不同的是兩個回調(diào)簽名不同
inputFormatters
指定輸入格式,當(dāng)用戶輸入內(nèi)容改變時,會根據(jù)指定格式來校驗
enable
如果為false, 則輸入框會被禁用
cursorWidth
、 cursorRadius
、 cursorColor
分別表示自定義輸入框光標(biāo)寬度、圓角和顏色
一個簡單的設(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, ) ]),
我們可以通過 onChange 拿到內(nèi)容。 當(dāng)然也可以使用 controller 來獲取
步驟為:
controller
:final TextEditingController _tfController = TextEditingController();
TextField( controller: _tfController, ... )
最后就可以通過 : print(_tfController.text)
來獲得輸入框的內(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è)置默認(rèn)值、選擇文本等,這里就不多贅述。
可以使用 FocusNode
和 FocusScopeNode
來控制焦點(diǎn)。默認(rèn)情況下是由 FocusScope
來管理,可以在這個范圍內(nèi)通過 FocusScopeNode
在輸入框之間移動焦點(diǎn)、設(shè)置默認(rèn)焦點(diǎn)。
我們可以通過下面代碼來獲取當(dāng)前 Widget 樹中默認(rèn)的 FocusScopeNode:
focusScopeNode = FocusScope.of(context)
拿到句柄后,可以使用下面代碼來獲取焦點(diǎn):
focusScopeNode.requestFocus(focusNode);
其中 focucsNode 是為 TextField 創(chuàng)建的 FocusNode, 這個操作可以讓該 TextField 獲取焦點(diǎn)。 調(diào)用 focusNode.unfocus()
可以取消焦點(diǎn)。
通過 FocusNode
可以監(jiān)聽焦點(diǎn)改變的事件:
focusNode.addListener((){ print(focusNode.hasFocus); })
true為獲取焦點(diǎn),false為失去焦點(diǎn)
表單Form
對輸入框進(jìn)行分組和統(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)容,當(dāng)為true時,每一個 FormField 內(nèi)容發(fā)生變化時都會校驗合法性,并直接顯示錯誤信息,否則就需要通過調(diào)用 FormState.validate()
來手動校驗
v1.19 已經(jīng)廢棄了,改成使用 AutovalidateMode
autovalidateMode
自動校驗?zāi)J?,是上面的替換,它有三個枚舉值:
①disable
:當(dāng) FormField 內(nèi)容改變時不做校驗
②always
:即使用戶沒有用戶交互也要校驗合法性
③onUserInteraction
:只有在用戶交互時才會去校驗合法性
onWillPop
決定 Form
所在的路由是否可以直接返回。該回調(diào)返回一個 Future
對象,如果 Future 的最終結(jié)果是 false,則當(dāng)前路由不會返回,如果為 true,則會返回到上一個路由。
這個屬性通常是用于攔截返回按鈕的
onChanged
Form 的任意一個 FormField 內(nèi)容發(fā)生改變時就會調(diào)用該方法
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 ,可以直接當(dāng)成 Form 的 FormField 來使用, 相當(dāng)于用 Form 來管理 TextField
Form 表單的狀態(tài)類就是 FormState
, 可以通過 Form.of
或者 GlobalKey
獲得,通過獲得它來對 Form 的子孫 FormField 進(jìn)行統(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)容清空
我們做一個用戶登錄的程序,再點(diǎn)擊登錄前需要做到輸入檢查:
用戶名不能為空,如果為空則提示“用戶名不能為空”
密碼不能小于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怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。