欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter基本組件Basics?Widget學(xué)習(xí)

 更新時(shí)間:2021年12月18日 11:52:49   作者:RikkaTheWorld  
本文詳細(xì)講解了Flutter基本組件Basics?Widget,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

1. 概述

上一篇說(shuō)到,Basics Widget 并不是 Flutter 的一個(gè)專(zhuān)門(mén)的Widget類(lèi)別,而是 Flutter 官方挑選一些開(kāi)發(fā)常用的 Widget 構(gòu)成的,希望我們掌握到一些最基本的開(kāi)發(fā)能力。

包括:

  • 文本 Text
  • 按鈕 Button
  • 圖片 Image
  • 單選框、復(fù)選框
  • 輸入框、表單
  • 指示器
  • Container

2. 常用組件

2.1 Text

Text 用于顯示簡(jiǎn)單樣式文本,然后可以填充一些文本顯示樣式的屬性,如下例子:

Text("Hello World",
        textAlign: TextAlign.left,
        maxLines: 1,
        overflow: TextOverflow.ellipsis,
        textScaleFactor: 1.5);
  • textAlign
    文本對(duì)齊方式
  • maxLinesoverflow
    maxLines 指定文本顯示的最大行數(shù)。
    當(dāng)文本內(nèi)容超過(guò)最大行數(shù)時(shí), overflow 指定了階段方式, 例如 ellipsis 就是將多余的文本用 “…” 表示
  • textScaleFactor
    代表文本相對(duì)于當(dāng)前字體大小的縮放因子,想你對(duì)于去設(shè)置文本的樣式 style 屬性的 fontSize, 它是調(diào)整字體大小的一個(gè)快捷方式, 該屬性的默認(rèn)值可以通過(guò) MediaQueryData.textScaleFactor 獲得, 如果沒(méi)有 MediaQuery,那么會(huì)默認(rèn)值為 1.0

2.1.1 TextStyle

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
    行高,它不是一個(gè)絕定的值,因?yàn)榫唧w的行高為 height*fontSize ,同理行寬也是
  • fontFamily
    由于不同平臺(tái)默認(rèn)支持的字體集不同,所以在手動(dòng)指定字體時(shí)一定要先在不同平臺(tái)測(cè)試一下
  • fontSize
    改屬性和 Text 的 textScaleFactor 都用于控制字體大小,但是有兩個(gè)區(qū)別,
    ①:fontSize 可以精確指定字體大小, 而 textScaleFactor 只能縮放比例
    ②: textScaleFactor 主要是用于系統(tǒng)字體大小設(shè)置改變時(shí),對(duì)Flutter 應(yīng)用字體進(jìn)行全局調(diào)整,而 fontSzie通常用于單個(gè)文本,字體大小不會(huì)跟隨系統(tǒng)字體大小變化

2.1.2 TextSpan

如果我們需要對(duì)Text內(nèi)容不同部分按照不同的樣式顯示,就可以使用 TextSpan,代表文本的一個(gè)“片段”,看看 TextSpan的定義:

  const TextSpan({
    this.text,
    this.children,
    TextStyle? style,
    this.recognizer,
    MouseCursor? mouseCursor,
    this.onEnter,
    this.onExit,
    this.semanticsLabel,
    this.locale,
    this.spellOut,
  })

其中 styletext 代表樣式和文本內(nèi)容, children是 List<InlineSpan>? 類(lèi)型,也就說(shuō) TextSpan 可以包含其他 Span

reconizer 用于表示該文本片段上用于手勢(shì)進(jìn)行識(shí)別處理,下面我們看一個(gè)效果圖,然后用 TextSpan 來(lái)實(shí)現(xiàn):

body: const Text.rich(TextSpan(children: [
              TextSpan(text: "Home: "),
              TextSpan(
                text: "https://flutterchina.club",
                style: TextStyle(color: Colors.blue),
                recognizer: _recognizer
              ),
            ]))));

這里的代碼,用 TextSpan實(shí)現(xiàn)了一個(gè)基礎(chǔ)文本和一個(gè)鏈接片段

  • Text.rich 方法將 TextSpan 添加到 Text 中,之所以可以這樣做,是因?yàn)?Text 其實(shí)就是 RichText 的一個(gè)包裝,而 RichText 是可以顯示多種多樣的 widget
  • _reconizer 是點(diǎn)擊鏈接的處理器

2.1.3 DefaultTextStyle

在 Widget 樹(shù)中, 文本的樣式默認(rèn)是可以被繼承的,因此如果 Widget樹(shù)的某一個(gè)節(jié)點(diǎn)處設(shè)置一個(gè)默認(rèn)的文本樣式,那么該節(jié)點(diǎn)的子樹(shù)所有的文本都會(huì)默認(rèn)使用這個(gè)樣式,而 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è)置了一個(gè)默認(rèn)的樣式,字體大小為20,、顏色為紅色,然后將 DefaultTextStyle 設(shè)置給了子樹(shù),這樣一來(lái) Column 所有子孫 Text 默認(rèn)都會(huì)繼承該樣式, 除非 Text 設(shè)置 inherit: false,如下所示:

2.1.4 使用字體

在 Flutter 中可以使用自定義的字體,或者其他第三方字體, 這里就不介紹配置了,具體可以看官方文檔:字體

2.2 Button

Material 組件庫(kù)提供了多種多樣的按鈕,他們都是直接或間接對(duì) RawMaterialButton 的包裝定制,所以大部分屬性都一樣。另外 Marterial 庫(kù)中的按鈕都有以下共同點(diǎn):

  • 按下時(shí)都有水波紋
  • 動(dòng)畫(huà)統(tǒng)一用 onPressed 屬性來(lái)設(shè)置回調(diào),當(dāng)按鈕按下時(shí)會(huì)執(zhí)行該回調(diào),如果不提供回調(diào)則按鈕會(huì)處于禁用狀態(tài),不會(huì)響應(yīng)用戶點(diǎn)擊

2.2.1 ElevatedButton

即 帶陰影的按鈕, 默認(rèn)帶有陰影和灰色背景,按下后陰影會(huì)變大,如下所示:

代碼如下:

        child: ElevatedButton(
          child: const Text("i am ElevatedButton"),
          onPressed: () {},
        ),
      ),

2.2.2 TextButton

文本按鈕,按下后會(huì)有背景色,如下圖所示:

2.2.3 OutlinedButton

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

2.2.4 IconButton

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

代碼設(shè)置為:

IconButton(
 icon: Icon(Icons.eleven_mp),
 onPressed: () {},
),

2.2.5 帶圖標(biāo)的按鈕

上面學(xué)到的 ElevatedButton、 TextButtonOutlinedButton 都有一個(gè) icon() 的構(gòu)造函數(shù),這樣就可以代入一個(gè)圖片進(jìn)去,例如設(shè)置:

ElevatedButton.icon(
          icon: const Icon(Icons.send),
          label: const Text("發(fā)送"),
          onPressed: () {},
        ),

效果為(這里有編碼問(wèn)題,可以無(wú)視):

2.3 圖片及Icon

2.3.1 圖片

可以通過(guò) Image 組件來(lái)加載并顯示布局, Image 的數(shù)據(jù)源可以是

  • asset
  • 文件
  • 內(nèi)存
  • 網(wǎng)絡(luò)
2.3.1.1 ImageProvider

ImageProvider 是抽象類(lèi),主要定義了圖片的獲取接口 load(),從不同的數(shù)據(jù)源獲取圖片需要實(shí)現(xiàn)不同的 ImageProvider,如 AssetImage 是實(shí)現(xiàn)了從 Asset 中加載圖片, NetworkImage 則實(shí)現(xiàn)了從網(wǎng)絡(luò)中加載圖片。

2.3.1.2 Image Widget

Image 組件在構(gòu)建時(shí)有一個(gè)必選的 image 參數(shù),它對(duì)應(yīng)一個(gè) ImageProvier,下面分別演示一下如何從 asset 和 網(wǎng)絡(luò)中加載圖片。

1.從 asset 中加載圖片

在工程根目錄下創(chuàng)建一個(gè) images 目錄,并將圖片拷貝到該目錄。

接下來(lái)在 pubspec.yaml 文件的 flutter部分 中,寫(xiě)入(注意縮進(jìn)):

flutter:
  ..
  assets:
    - assets/images/bobo.jpg

最后在代碼中使用:

Image(
  image: AssetImage("images/bobo.jpg"),
  width: 100.0,
)

就能展示圖片。

(不過(guò)我這里遇到一個(gè)問(wèn)題,使用手機(jī)運(yùn)行Flutter應(yīng)用能正常展示圖片,但是使用 Chrome 模擬器會(huì)報(bào)錯(cuò),不知道是什么原因造成的

2.從網(wǎng)絡(luò)URL中加載圖片

直接使用代碼:

Image(
  image: NetworkImage("https://www.wahaotu.com/uploads/allimg/201904/1554901831804910.jpg"),
  width: 100.0,
)

可以正常展示圖片。

(不過(guò)這里出現(xiàn)了很上面一樣的問(wèn)題,但是使用官方使用的url又能正常展示圖片

2.3.1.3 Image 參數(shù)

我們可以來(lái)看下 Image 的參數(shù),通過(guò)這些參數(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,
  })
  • widthheight
    設(shè)置圖片寬高,當(dāng)不指定寬高時(shí),會(huì)根據(jù)當(dāng)前父容器的限制盡可能的顯示其原始大小,如果只設(shè)置其中一個(gè),那么另一個(gè)屬性默認(rèn)會(huì)按比例縮放
  • fit
    該屬性用于用于在圖片的顯示空間和圖片本身大小不同時(shí)指定圖片的適應(yīng)模式。適應(yīng)模式是在 BoxFit 中定義的,它是一個(gè)枚舉類(lèi)型,有這些值:
    fill:拉伸填充滿顯示空間 ,圖片會(huì)便是
    cover:會(huì)按圖片的長(zhǎng)寬比放大后居中填滿顯示空間,圖片不會(huì)變形,超出顯示部分會(huì)被剪裁
    contain:圖片默認(rèn)適應(yīng)規(guī)則,圖片會(huì)保證圖片本身長(zhǎng)寬比不變的情況下縮放以適應(yīng)當(dāng)前的顯示空間
    fitWidth:圖片寬度會(huì)縮放到顯示空間的寬度,高度會(huì)按比例縮放,居中顯示,圖片不會(huì)變形
    fitHeight:和上面的反著來(lái)
  • none:圖片沒(méi)有適應(yīng)策略,會(huì)在顯示空間內(nèi)顯示圖片

  • colorcolorBlendMode:在圖片繪制時(shí)可以對(duì)每一個(gè)像素進(jìn)行顏色混合處理,color指定混合色,而 colorBlendMode 指定混合模式下,因?yàn)橛玫谋容^少,這里就不做實(shí)例
  • repeat:當(dāng)圖片本身大小小于顯示空間時(shí),指定圖片的重復(fù)規(guī)則,這里也不做展示

2.3.2 Icon

Android中有 svg 矢量圖, 而 Flutter 中的也有,就是 Icon,它有下面這些優(yōu)點(diǎn):

  • 體積小
  • 因?yàn)槭鞘噶繄D,所以拉伸不會(huì)影響清晰程度
  • 可以通過(guò) TextSpan 和 文本混用
  • 可以引用到文本樣式

Flutter 默認(rèn)實(shí)現(xiàn)了一套Icon,在 pubspec.yaml 的配置文件可以看到:

flutter:
  uses-material-design: true

來(lái)看下官方的示例代碼:

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,
  ),
);

效果為:

為了不讓開(kāi)發(fā)者碼點(diǎn),F(xiàn)lutter 封裝了 IconDataIcon來(lái)專(zhuān)門(mén)顯示字體圖片,上面的例子也可以用下面方式實(shí)現(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)

2.4 單選開(kāi)關(guān)和復(fù)選框

Flutter 提供了 Material 風(fēng)格的 開(kāi)關(guān)Switch復(fù)選框Checkbox,它們都繼承自 StatfulWidget,但是它們不會(huì)保存選中的狀態(tài),選中狀態(tài)是由父組件來(lái)管理的。 當(dāng) Switch 或者 Checkbox 被點(diǎn)擊時(shí),會(huì)觸發(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ù)單選開(kāi)關(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)建頁(yè)面  
            setState(() {
              _switchSelected=value;
            });
          },
        ),
        Checkbox(
          value: _checkboxSelected,
          activeColor: Colors.red, //選中時(shí)的顏色
          onChanged:(value){
            setState(() {
              _checkboxSelected=value!;
            });
          } ,
        )
      ],
    );
  }
}

代碼中需要維護(hù) SwitchCheckbox 的選中狀態(tài),所以 Widget 繼承自 StatefulWidget。 在其 build 方法中分別狀態(tài)了 Switch 和 Checkbox, 并且用兩個(gè) bool 值來(lái)維護(hù)分別的選中狀態(tài)。 當(dāng)按鈕被點(diǎn)擊時(shí),會(huì)回調(diào) onChanged 回調(diào)選中狀態(tài)出去,此時(shí)我們需要調(diào)用 setState() 方法來(lái)觸發(fā) Flutter 重繪。

為什么要這樣子設(shè)計(jì),我的理解是:

  • 將開(kāi)關(guān)、復(fù)選框的狀態(tài)拋給父組件,可以更加靈活,比如在勾選時(shí)候做一些網(wǎng)絡(luò)請(qǐng)求,即異步的操作
  • 一般來(lái)說(shuō),這些item是否選中,是和用戶數(shù)據(jù)關(guān)聯(lián)的,用戶數(shù)據(jù)也不可能是他們的私有狀態(tài),所以放在一起管理更好

2.4.1 屬性

它們的屬性比較簡(jiǎn)單,常用的有:

  • activeColor:設(shè)置激活狀態(tài)的顏色
  • tristate: 是否為三態(tài),僅 Checbox有,一般情況下只有 “true” 和 “false”,表示選中和非選中,如果設(shè)置了 tristate 后,還會(huì)增加一個(gè) “null” 狀態(tài)

此外, Checkbox 不可設(shè)置寬高,其大小是自定義的,而 Switch 也僅能設(shè)置寬度而已。

2.5 輸入框以及表單

Flutter Material組件提供了 輸入款TextField表單Form

2.5.1 輸入框 TextField

2.5.1.1 屬性

來(lái)看下 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,
  })

屬性比較多,列幾個(gè)關(guān)鍵的講解:

  • controller
    編輯框的控制器,通過(guò)它可以設(shè)置/獲取編輯框的內(nèi)容、選擇編輯內(nèi)容、監(jiān)聽(tīng)編輯文本改變事件。大多數(shù)情況下我們都需要顯示提供一個(gè) controller 來(lái)與文本框交互,如果設(shè)置的話, TextField 內(nèi)部會(huì)創(chuàng)建一個(gè)
  • focusNode
    用于控制 TextField 是否占有當(dāng)前鍵盤(pán)的輸入焦點(diǎn)
  • InputDecoration
    用于控制 TextField 的外觀顯示,如提示文本、背景顏色、邊框等。
  • keyboardType
    用于設(shè)置該輸入框默認(rèn)的鍵盤(pán)輸入類(lèi)型, 有文本、電話、email等格式
  • textInputAction
    鍵盤(pán)動(dòng)作按鈕圖標(biāo),就是右下角的那個(gè)圖標(biāo)設(shè)置
  • style
    文本的樣式(正在編輯中的)
  • textAlign
    輸入框內(nèi)編輯文本在水平方向的對(duì)齊方式
  • autofocus
    是否自動(dòng)獲取焦點(diǎn)
  • obscureText
    是否隱藏正在編輯的文本, 比如輸入密碼的場(chǎng)景,文本內(nèi)容會(huì)用 “?” 來(lái)代替
  • maxLines
    最大行數(shù)
  • maxLenthmaxLengthEnforcement
    maxLenth 代表輸入框文本的最大長(zhǎng)度,設(shè)置后輸入框右下角會(huì)顯示輸入的文本計(jì)數(shù)
    maxLengthEnforcement 決定輸入文本長(zhǎng)度超過(guò) maxLength 時(shí)如何處理,如截?cái)?/li>
  • toolbarOptions
    長(zhǎng)按時(shí)出現(xiàn)的菜單,可以選擇 copy、cut、paste 、selectAll
  • onChange
    輸入框內(nèi)容改變的回調(diào), 當(dāng)然 controller 也可以做到監(jiān)聽(tīng)
  • onEditingComplete 、onSubmitted
    作用一樣,都是在輸入完成時(shí)觸發(fā),比如點(diǎn)擊了鍵盤(pán)的 完成鍵、搜索鍵不同的是兩個(gè)回調(diào)簽名不同
  • inputFormatters
    指定輸入格式,當(dāng)用戶輸入內(nèi)容改變時(shí),會(huì)根據(jù)指定格式來(lái)校驗(yàn)
  • enable
    如果為false, 則輸入框會(huì)被禁用
  • cursorWidth、 cursorRadius、 cursorColor
    分別表示自定義輸入框光標(biāo)寬度、圓角和顏色

一個(gè)簡(jiǎn)單的設(shè)置代碼如下:

Column(children: const <Widget>[
        TextField(
          autofocus: true,
          decoration: InputDecoration(
            labelText: "用戶名",
            hintText: "請(qǐng)輸入用戶名或密碼",
            prefixIcon: Icon(Icons.person)
          ),
        ),
        TextField(
          decoration: InputDecoration(
            labelText: "密碼",
            hintText: "請(qǐng)輸入密碼",
            prefixIcon: Icon(Icons.lock)
          ),
          obscureText: true,
        )
      ]),

2.5.1.2 通過(guò) controller 獲取輸入內(nèi)容

我們可以通過(guò) onChange 拿到內(nèi)容。 當(dāng)然也可以使用 controller 來(lái)獲取

步驟為:

定義一個(gè) controller
final TextEditingController _tfController = TextEditingController();
然后在 TextFiled 中傳入這個(gè) controller
TextField(
  controller: _tfController,
  ...
)

最后就可以通過(guò) : print(_tfController.text) 來(lái)獲得輸入框的內(nèi)容

2.5.1.3 通過(guò) controller 監(jiān)聽(tīng)文本內(nèi)容變化

可以通過(guò) onChange 來(lái)監(jiān)聽(tīng)文本, controller 可以通過(guò)設(shè)置監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)文本,如下:

  @override
  void initState() {
    super.initState();
    _tfController.addListener(() { 
      print(_tfController.text);
    });
  }

controller 的功能更多,除了監(jiān)聽(tīng)文本,還可以設(shè)置默認(rèn)值、選擇文本等,這里就不多贅述。

2.5.1.4 控制焦點(diǎn)

可以使用 FocusNodeFocusScopeNode 來(lái)控制焦點(diǎn)。默認(rèn)情況下是由 FocusScope 來(lái)管理,可以在這個(gè)范圍內(nèi)通過(guò) FocusScopeNode 在輸入框之間移動(dòng)焦點(diǎn)、設(shè)置默認(rèn)焦點(diǎn)。

我們可以通過(guò)下面代碼來(lái)獲取當(dāng)前 Widget 樹(shù)中默認(rèn)的 FocusScopeNode:

focusScopeNode = FocusScope.of(context)

拿到句柄后,可以使用下面代碼來(lái)獲取焦點(diǎn):

focusScopeNode.requestFocus(focusNode);

其中 focucsNode 是為 TextField 創(chuàng)建的 FocusNode, 這個(gè)操作可以讓該 TextField 獲取焦點(diǎn)。 調(diào)用 focusNode.unfocus() 可以取消焦點(diǎn)。

2.5.1.5 監(jiān)聽(tīng)焦點(diǎn)狀態(tài)改變事件

通過(guò) FocusNode 可以監(jiān)聽(tīng)焦點(diǎn)改變的事件:

focusNode.addListener((){
   print(focusNode.hasFocus);
})

true為獲取焦點(diǎn),false為失去焦點(diǎn)

2.5.2 表單

表單Form 對(duì)輸入框進(jìn)行分組和統(tǒng)一操作。 就像 Android 的原生組件 RadioGroup 之于 RadioButton 一樣, Form 可以管理內(nèi)容校驗(yàn)、輸入框重置等。

Form 繼承自 StatefulWidget,其狀態(tài)管理在 FormState 里面,來(lái)看看 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
    是否自動(dòng)校驗(yàn)輸入內(nèi)容,當(dāng)為true時(shí),每一個(gè) FormField 內(nèi)容發(fā)生變化時(shí)都會(huì)校驗(yàn)合法性,并直接顯示錯(cuò)誤信息,否則就需要通過(guò)調(diào)用 FormState.validate() 來(lái)手動(dòng)校驗(yàn)
    v1.19 已經(jīng)廢棄了,改成使用 AutovalidateMode
  • autovalidateMode
    自動(dòng)校驗(yàn)?zāi)J?,是上面的替換,它有三個(gè)枚舉值:
    disable:當(dāng) FormField 內(nèi)容改變時(shí)不做校驗(yàn)
    always:即使用戶沒(méi)有用戶交互也要校驗(yàn)合法性
    onUserInteraction:只有在用戶交互時(shí)才會(huì)去校驗(yàn)合法性
  • onWillPop
    決定 Form 所在的路由是否可以直接返回。該回調(diào)返回一個(gè) Future 對(duì)象,如果 Future 的最終結(jié)果是 false,則當(dāng)前路由不會(huì)返回,如果為 true,則會(huì)返回到上一個(gè)路由。
    這個(gè)屬性通常是用于攔截返回按鈕的
  • onChanged
    Form 的任意一個(gè) FormField 內(nèi)容發(fā)生改變時(shí)就會(huì)調(diào)用該方法
2.5.2.1 FormField

Form 的子孫元素是 FormField 類(lèi)型,F(xiàn)ormField 是一個(gè)抽象類(lèi),定義了幾個(gè)屬性, FormState 內(nèi)部通過(guò)他們來(lá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
    保存時(shí)的回調(diào)
  • validator
    驗(yàn)證合法性的回調(diào)
  • initValue
    初始值

為了方便使用, Flutter 提供了一個(gè) TextFormFild 組件,繼承自 FormField 類(lèi),還包裝了 TextFileld ,可以直接當(dāng)成 Form 的 FormField 來(lái)使用, 相當(dāng)于用 Form 來(lái)管理 TextField

2.5.2.2 FormState

Form 表單的狀態(tài)類(lèi)就是 FormState, 可以通過(guò) Form.of 或者 GlobalKey 獲得,通過(guò)獲得它來(lái)對(duì) Form 的子孫 FormField 進(jìn)行統(tǒng)一操作。

FormState 常用的三個(gè)方法:

  • FormState.validate():調(diào)用此方法后, 會(huì)調(diào)用 Form 子孫 FormField.validate() 回調(diào),如果有一個(gè)檢驗(yàn)失敗,那么會(huì)返回 false,這樣所有校驗(yàn)失敗的 Widget 都會(huì)給出錯(cuò)誤提示
  • FormState.save():調(diào)用此方法后,會(huì)調(diào)用 子孫的 FormFild.save() 回調(diào),用于保存表單內(nèi)容
  • FormState.reset(): 會(huì)將子孫 FormField 的內(nèi)容清空
2.5.2.3 示例

我們做一個(gè)用戶登錄的程序,再點(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學(xué)習(xí),希望對(duì)大家有所幫助。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評(píng)論