Flutter實戰】文字元件及五大案例

老孟Flutter發表於2020-06-10

老孟導讀:大家好,這是【Flutter實戰】系列文章的第二篇,這一篇講解文字元件,文字元件包括文字展示元件(Text和RichText)和文字輸入元件(TextField),基礎用法和五個案例助你快速掌握。 第一篇連結:【Flutter實戰】移動技術發展史

Text

Text是顯示文字的元件,最常用的元件,沒有之一。基本用法如下:

Text('老孟')複製程式碼

注意:Text元件一定要包裹在Scaffold元件下,否則效果如下:

文字的樣式在style中設定,型別為TextStyleTextStyle中包含很多文字樣式屬性,下面介紹一些常用的。

設定文字大小和顏色:

Text('老孟',style: TextStyle(color: Colors.red,fontSize: 20),),複製程式碼

上面黑色的字型為沒有設定的效果,作為對比。

設定字型粗細:

Text('老孟',style: TextStyle(fontWeight: FontWeight.bold))複製程式碼

字型粗細共有9個級別,為w100w900FontWeight.boldw700

設定斜體:

Text('老孟',style: TextStyle(fontStyle: FontStyle.italic,))複製程式碼

設定自定義的字型:

  1. 首先下載字型庫(比如中華字型庫)
  2. 將字型檔案拷貝的專案中,一般目錄是:assets/fonts/,assets和fonts都需要手動建立,此目錄不是必須的,而是約定俗成,資源一般都放在assets目錄下。
  3. 配置pubspec.yaml
fonts:
  - family: maobi 
    fonts:
      - asset: assets/fonts/maobi.ttf複製程式碼

maobi:是自己對當前字型的命名,有意義即可。

asset:字型檔案的目錄。

使用:

Text('老孟', style: TextStyle(fontFamily: 'maobi',)),複製程式碼

設定對齊方式:

Container(
  height: 100,
  width: 200,
  color: Colors.blue.withOpacity(.4),
  child: Text('老孟', textAlign: TextAlign.center),
),複製程式碼

textAlign只是控制水平方向的對齊方式,值說明如下:

  • left:左對齊
  • right:右對齊
  • center:居中
  • justify:兩端對齊,此屬性中文存在bug(Flutter版本:1.17.3)也可以在官方issue中關注此問題
  • start:前端對齊,和TextDirection屬性有關,如果設定TextDirection.ltr,則左對齊,設定TextDirection.rtl則右對齊。
  • end:末端對齊,和TextDirection屬性有關,如果設定TextDirection.ltr,則右對齊,設定TextDirection.rtl則左對齊。

設定文字自動換行:

Container(
  height: 100,
  width: 200,
  color: Colors.blue.withOpacity(.4),
  child: Text('老孟,專注分享Flutter技術和應用實戰',softWrap: true,),
)複製程式碼

文字超出範圍時的處理:

Container(
  height: 100,
  width: 200,
  color: Colors.blue.withOpacity(.4),
  child: Text('老孟,專注分享Flutter技術和應用實戰',overflow: TextOverflow.ellipsis,),
)複製程式碼

溢位的處理方式:

  • clip:直接裁剪。
  • fade:越來越透明。
  • ellipsis:省略號結尾。
  • visible:依然顯示,此時將會溢位父元件。

設定全域性字型樣式:

MaterialApptheme中設定如下

MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
   ...
    textTheme: TextTheme(
        bodyText2: TextStyle(color: Colors.red,fontSize: 24),
    )
  ),
  home: Scaffold(
    body: TextDemo(),
  ),
)複製程式碼

Text元件預設為紅色,

Text('老孟'),

Text('老孟',style: TextStyle(color: Colors.blue,fontSize: 20),),複製程式碼

RichText

RichText的屬性和Text基本一樣,使用如下:

RichText(
  text: TextSpan(
      style: DefaultTextStyle.of(context).style,
      children: <InlineSpan>[
        TextSpan(text: '老孟', style: TextStyle(color: Colors.red)),
        TextSpan(text: ','),
        TextSpan(text: '專注分享Flutter技術和應用實戰'),
      ]),
)複製程式碼

TextField

TextField是文字輸入元件,即輸入框,常用元件之一。基本用法:

TextField()複製程式碼

不需要任何引數,一個最簡單的文字輸入元件就出來了,效果如下:

decoration是TextField元件的裝飾(外觀)引數,型別是InputDecoration。

icon顯示在輸入框的前面,用法如下:

TextField(
  decoration: InputDecoration(
    icon: Icon(Icons.person),
  ),
)複製程式碼

當輸入框是空而且沒有焦點時,labelText顯示在輸入框上邊,當獲取焦點或者不為空時labelText往上移動一點,labelStyle參數列示文字樣式,具體參考TextStyle, 用法如下:

TextField(
  decoration: InputDecoration(
    labelText: '姓名:',
    labelStyle: TextStyle(color:Colors.red)
  ),
)複製程式碼

hasFloatingPlaceholder引數控制當輸入框獲取焦點或者不為空時是否還顯示labelText,預設為true,顯示。

helperText顯示在輸入框的左下部,用於提示使用者,helperStyle參數列示文字樣式,具體參考TextStyle用法如下:

TextField(
  decoration: InputDecoration(
    helperText: '使用者名稱長度為6-10個字母',
    helperStyle: TextStyle(color: Colors.blue),
    helperMaxLines: 1
  ),
)複製程式碼

hintText是當輸入框為空時的提示,不為空時不在顯示,用法如下:

TextField(
  decoration: InputDecoration(
    hintText: '請輸入使用者名稱',
    hintStyle: TextStyle(color: Colors.grey),
    hintMaxLines: 1
  ),
)複製程式碼

errorText顯示在輸入框的左下部,預設字型為紅色,用法如下:

TextField(
  decoration: InputDecoration(
    errorText: '使用者名稱輸入錯誤',
    errorStyle: TextStyle(fontSize: 12),
    errorMaxLines: 1,
    errorBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.red)),
  ),
)複製程式碼

prefix系列的元件是輸入框前面的部分,用法如下:

TextField(
  decoration: InputDecoration(
    prefixIcon: Icon(Icons.person)
  ),
)複製程式碼

注意prefix和icon的區別,icon是在輸入框邊框的外部,而prefix在裡面。

suffix和prefix相反,suffix在輸入框的尾部,用法如下:

TextField(
  decoration: InputDecoration(
      suffixIcon: Icon(Icons.person)
  ),
)複製程式碼

counter元件統計輸入框文字的個數,counter僅僅是展示效果,不具備自動統計字數的功能, 自動統計字數程式碼如下:

var _textFieldValue = '';
TextField(
  onChanged: (value){
    setState(() {
      _textFieldValue = value;
    });
  },
  decoration: InputDecoration(
    counterText: '${_textFieldValue.length}/32'
  ),
)複製程式碼

filled為true時,輸入框將會被fillColor填充,仿QQ登入輸入框程式碼如下:

Container(
  height: 60,
  width: 250,
  child: TextField(
    decoration: InputDecoration(
      fillColor: Color(0x30cccccc),
      filled: true,
      enabledBorder: OutlineInputBorder(
          borderSide: BorderSide(color: Color(0x00FF0000)),
          borderRadius: BorderRadius.all(Radius.circular(100))),
      hintText: 'QQ號/手機號/郵箱',
      focusedBorder: OutlineInputBorder(
          borderSide: BorderSide(color: Color(0x00000000)),
          borderRadius: BorderRadius.all(Radius.circular(100))),
    ),
  ),
)複製程式碼

controller是輸入框文字編輯的控制器,可以獲取TextField的內容、設定TextField的內容,下面將輸入的英文變為大寫:

TextEditingController _controller;

@override
void initState() {
  super.initState();
  _controller = TextEditingController()
    ..addListener(() {
      //獲取輸入框的內容,變為大寫
      _controller.text = _controller.text.toUpperCase();

    });
}

@override
Widget build(BuildContext context) {
  return TextField(
    controller: _controller,
  );
}

@override
dispose() {
  super.dispose();
  _controller.dispose();
}複製程式碼

有時輸入框後面帶有“清除”功能,需要controller來實現。如果需要2個TextField的內容進行同步,只需要給2個TextField設定同一個controller即可實現。

keyboardType引數控制軟鍵盤的型別,說明如下:

  • text:通用鍵盤。
  • multiline:當TextField為多行時(maxLines設定大於1),右下角的為“換行” 按鍵。
  • number:數字鍵盤。
  • phone:手機鍵盤,比數字鍵盤多"*"和 "#"。
  • datetime:在ios上和text一樣,在android上出現數字鍵盤、":"和 "-"。
  • emailAddress:郵箱鍵盤,有"@" 和 "."按鍵。
  • url:url鍵盤,有"/" 和 "."按鍵。
  • visiblePassword:既有字幕又有數字的鍵盤。

textInputAction引數控制軟鍵盤右下角的按鍵,說明如下:

  • none:android上顯示返回鍵,ios不支援。
  • unspecified:讓作業系統自己決定哪個合適,一般情況下,android顯示“完成”或者“返回”。
  • done:android顯示代表“完成”的按鈕,ios顯示“Done”(中文:完成)。
  • go:android顯示錶達使用者去向目的地的圖示,比如向右的箭頭,ios顯示“Go”(中文:前往)。
  • search:android顯示錶達搜尋的按鈕,ios顯示"Search"(中文:搜尋)。
  • send:android顯示錶達傳送意思的按鈕,比如“紙飛機”按鈕,ios顯示"Send"(中文:傳送)。
  • next:android顯示錶達“前進”的按鈕,比如“向右的箭頭”,ios顯示"Next"(中文:下一項)。
  • previous:android顯示錶達“後退”的按鈕,比如“向左的箭頭”,ios不支援。
  • continueAction:android 不支援,ios僅在ios9.0+顯示"Continue"(中文:繼續)。
  • join:Android和ios顯示"Join"(中文:加入)。
  • route:android 不支援,ios顯示"Route"(中文:路線)。
  • emergencyCall:android 不支援,ios顯示"Emergency Call"(中文:緊急電話)。
  • newline:android顯示錶達“換行”的按鈕,ios顯示”換行“。

大家可能發現了,Android上顯示的按鈕大部分是不確定的,比如next有的顯示向右的箭頭,有的顯示前進,這是因為各大廠商對Android ROM定製引發的。

textCapitalization引數是配置鍵盤是大寫還是小寫,僅支援鍵盤模式為text,其他模式下忽略此配置,說明如下:

  • words:每一個單詞的首字母大寫。
  • sentences:每一句話的首字母大寫。
  • characters:每個字母都大寫
  • none:都小寫

這裡僅僅是控制軟鍵盤是大寫模式還是小寫模式,你也可以切換大小寫,系統並不會改變輸入框內的內容。

textAlignVertical表示垂直方向的對齊方式,textDirection表示文字方向,用法如下:

TextField(
  textAlignVertical: TextAlignVertical.center,
  textDirection: TextDirection.rtl,
)複製程式碼

toolbarOptions表示長按時彈出的選單,有copycutpasteselectAll,用法如下:

TextField(
  toolbarOptions: ToolbarOptions(
    copy: true,
    cut: true,
    paste: true,
    selectAll: true
  ),
)複製程式碼

cursor表示游標,用法如下:

TextField(
  showCursor: true,
  cursorWidth: 3,
  cursorRadius: Radius.circular(10),
  cursorColor: Colors.red,
)複製程式碼

效果如下:

將輸入框設定為密碼框,只需obscureText屬性設定true即可,用法如下:

TextField(
  obscureText: true,
)複製程式碼

通過inputFormatters可以限制使用者輸入的內容,比如只想讓使用者輸入字元,設定如下:

TextField(
  inputFormatters: [
    WhitelistingTextInputFormatter(RegExp("[a-zA-Z]")),
  ],
)複製程式碼

這時使用者是無法輸入數字的。

onChanged是當內容發生變化時回撥,onSubmitted是點選回車或者點選軟鍵盤上的完成回撥,onTap點選輸入框時回撥,用法如下:

TextField(
  onChanged: (value){
    print('onChanged:$value');
  },
  onEditingComplete: (){
    print('onEditingComplete');
  },

  onTap: (){
    print('onTap');
  },
)複製程式碼

輸入框右下角經常需要字數統計,除了使用上面介紹的方法外,還可以使用buildCounter,建議使用此方法,用法如下:

TextField(
  maxLength: 100,
  buildCounter: (
    BuildContext context, {
    int currentLength,
    int maxLength,
    bool isFocused,
  }) {
    return Text(
      '$currentLength/$maxLength',
    );
  },
)複製程式碼

動態獲取焦點

FocusScope.of(context).requestFocus(_focusNode);複製程式碼

_focusNode為TextField的focusNode:

_focusNode = FocusNode();

TextField(
    focusNode: _focusNode,
    ...
)複製程式碼

動態失去焦點

_focusNode.unfocus();複製程式碼

過渡顏色的文字

Builder(
  builder: (BuildContext context) {
    RenderBox box = context.findRenderObject();
    final Shader linearGradient = LinearGradient(
      colors: <Color>[Colors.purple, Colors.blue],
    ).createShader(
        Rect.fromLTWH(0.0, 0.0, box?.size?.width, box?.size?.height));

    return Text(
      '老孟,專注分享Flutter技術和應用實戰',
      style: new TextStyle(
          fontSize: 18.0,
          fontWeight: FontWeight.bold,
          foreground: Paint()..shader = linearGradient),
    );
  },
)複製程式碼

Builder元件是為了計算當前Text元件大小,生成LinearGradient。

帶前後置標籤的文字

RichText(
  text: TextSpan(
      style: DefaultTextStyle.of(context).style,
      children: <InlineSpan>[
        WidgetSpan(
            child: Container(
              margin: EdgeInsets.only(right: 10),
              padding: EdgeInsets.symmetric(horizontal: 10),
              decoration: BoxDecoration(
                  shape: BoxShape.rectangle,
                  borderRadius: BorderRadius.all(Radius.circular(20)),
                  color: Colors.blue),
              child: Text(
                '判斷題',
                style: TextStyle(color: Colors.white),
              ),
            )),
        TextSpan(text: '泡沫滅火器可用於帶電滅火'),

      ]),
)複製程式碼

“服務協議”

通常在登入頁面的底部會出現登入即代表同意並閱讀 《服務協議》,其中《服務協議》為藍色且可點選:

Text.rich(
  TextSpan(
      text: '登入即代表同意並閱讀',
      style: TextStyle(fontSize: 11, color: Color(0xFF999999)),
      children: [
        TextSpan(
          text: '《服務協議》',
          style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
          recognizer: TapGestureRecognizer()
            ..onTap = () {
              print('onTap');
            },
        ),
      ]),
)複製程式碼

登入密碼輸入框

TextField(
  decoration: InputDecoration(
    fillColor: Color(0x30cccccc),
    filled: true,
    enabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Color(0x00FF0000)),
        borderRadius: BorderRadius.all(Radius.circular(100))),
    hintText: '輸入密碼',
    focusedBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Color(0x00000000)),
        borderRadius: BorderRadius.all(Radius.circular(100))),

  ),
  textAlign: TextAlign.center,
  obscureText: true,
  onChanged: (value) {

  },
)複製程式碼

評論回覆

Text.rich(
  TextSpan(
      text: '回覆',
      style: TextStyle(fontSize: 11, color: Color(0xFF999999)),
      children: [
        TextSpan(
          text: '@老孟:',
          style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
          recognizer: TapGestureRecognizer()
            ..onTap = () {
              print('onTap');
            },
        ),
        TextSpan(
          text: '你好,想知道Flutter發展前景如何?',
        ),
      ]),
)複製程式碼

交流

老孟Flutter部落格地址(330個控制元件用法):laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

相關文章