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