Flutter - 基礎Widget

歡迎關注微信公衆號:FSA全棧行動 👋html

1、文本 Widget

一、純文本(Text)

Text 控件常見屬性:api

  • textAlign: 文本對齊,默認是左對齊,能夠根據實際狀況修改成居中(TextAlign.center)或右對齊(TextAlign.right)
  • maxLines: 文字最多顯示多少行,一般與 overflow 搭配使用
  • overflow: 內容溢出顯示效果,能夠設置顯示省略號(TextOverflow.ellipsis)
  • textScaleFactor: 縮放因子,默認是 1。
  • style: 文本樣式,直接使用 TextStyle()
    • fontSize: 文字大小
    • color: 文字顏色
    • fontWeight: 文字粗細
/// Text的使用Demo
class TextWidgetDemo extends StatelessWidget {
  final textContent = "《定風波》 蘇軾 \n莫聽穿林打葉聲,何妨吟嘯且徐行。\n竹杖芒鞋輕勝馬,誰怕?一蓑煙雨任生平。\n";
  // final textContent = "《定風波》 蘇軾 莫聽穿林打葉聲,何妨吟嘯且徐行。竹杖芒鞋輕勝馬,誰怕?一蓑煙雨任生平。";

  @override
  Widget build(BuildContext context) {
    return Text(
      textContent,
      // 默認狀況下,Text是包裹文字的,文字內容太少時可能看不出效果
      textAlign: TextAlign.center,
      // 文字最多顯示2行
      maxLines: 3,
      // 文字超過2行時,顯示...
      overflow: TextOverflow.ellipsis,
      // 縮放因子,默認是1
      textScaleFactor: 1,
      style: TextStyle(
        fontSize: 30,
        color: Colors.red,
        fontWeight: FontWeight.bold, // 字體加粗
      ),
    );
  }
}
複製代碼

注意:Text 並非最終渲染的 Widget,最終渲染的是 RichText。Text 的父類是 StatelessWidget,最終渲染的 Widget 是 build()方法建立出來的 RenderObjectWidget,即 RichText緩存

二、富文本(Text.rich())

Text.rich() 有一個必須參數 InlineSpan textSpan,InlineSpan 是抽象類且無工廠構造函數,沒法直接建立,故須要使用其子類:微信

  • TextSpan : 用於構建純文本的 Span
  • WidgetSpan : 用於構建內嵌 Widget 的 Span (好比:Icon)
/// Text.rich()的使用Demo
class TextRichDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text.rich(
      TextSpan(
        // text: "Hello lqr",
        // style: TextStyle(color: Colors.red,fontSize: 20),
        children: [
          TextSpan(text: "Hello World", style: TextStyle(color: Colors.red)),
          TextSpan(
              text: "Hello Flutter", style: TextStyle(color: Colors.green)),
          WidgetSpan(child: Icon(Icons.favorite, color: Colors.red)),
          TextSpan(text: "Hello Dart", style: TextStyle(color: Colors.blue)),
        ],
      ),
      style: TextStyle(fontSize: 26),
    );
  }
}
複製代碼

2、按鈕 Widget

一、常見 Button

  • RaisedButton : 突出的 Button(從 v1.25.0 過期,推薦使用 ElevatedButton)
  • FlatButton : 扁平的 Button(從 v1.25.0 過期,推薦使用 TextButton)
  • OutlineButton : 邊框 Button(從 v1.25.0 過期,推薦使用 OutlinedButton)
  • FloatingActionButton : 浮動按鈕,簡稱 FAB,通常用在 Scaffold 中
    • floatingActionButtonLocation : 可指定 FAB 在界面中的位置,好比底部居中: FloatingActionButtonLocation.centerFloat

在使用這些常見 Widget 時,常常會看到構造方法中有兩類 "必傳"參數markdown

  • 必傳參數 : 指的是 Dart 語法中方法的必傳參數,這種參數不傳必定報錯(編譯不經過)。
  • required 參數 : 使用 @required(或 required 關鍵字)修飾的 可選參數,這種不傳編譯能夠經過,可是會報警告。
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("基礎Widget")),
      body: HomeContent(),
      // 4. FloatingActionButton
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => print("FloatingActionButton Click"),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

...

class ButtonDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. 突出的Button(從 v1.25.0 過期,推薦使用 ElevatedButton)
        RaisedButton(
          child: Text("RaisedButton"),
          textColor: Colors.red, // 文字顏色(也能夠在Text的style中設置)
          color: Colors.blue, // 按鈕背景色
          onPressed: () => print("RaisedButton Click"),
        ),

        // 2. 扁平的Button(從 v1.25.0 過期,推薦使用 TextButton)
        FlatButton(
          child: Text("FlatButton"),
          color: Colors.orange,
          onPressed: () => print("FlatButton Click"),
        ),

        // 3. 邊框Button(從 v1.25.0 過期,推薦使用 OutlinedButton)
        OutlineButton(
            child: Text("OutlineButton"),
            onPressed: () => print("OutlineButton Click")),

        // 4. FloatingActionButton,通常用在Scaffold中
        // FloatingActionButton(onPressed: onPressed)

        // 5. 自定義Button:圖標-文字-背景-圓角
        FlatButton(
          color: Colors.amberAccent,
          shape: RoundedRectangleBorder( // 圓角
            borderRadius: BorderRadius.circular(8),
          ),
          child: Row(
            mainAxisSize: MainAxisSize.min, // 默認是max,佔滿父Widget;min是包裹內容
            children: [
              Icon(Icons.favorite, color: Colors.red), // 圖標
              Text("喜歡做者"), // 文字
            ],
          ),
          onPressed: () => print("自定義Button"), // onPressed必傳,不然樣式可能會出問題
        )
      ],
    );
  }
}
複製代碼

二、定製 Button

  • 默認間隔 : 默認狀況下 Button 上下有必定有間隔,能夠指定 materialTapTargetSize 來修改
    • MaterialTapTargetSize.padded:(默認值) 當按鈕寬(或高)不足 48px 時,就把寬(或高)擴展到 48px
    • MaterialTapTargetSize.shrinkWrap:緊縮包裹,能夠去除上下的間隔
  • 最小寬度 : ButtonTheme(也是個 Widget,包裹 Button) 或 minWidth(Button 的一個屬性)
  • 內間距 : 修改 padding 屬性值
class ButtonExtensionDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        /// 1. 默認狀況下Button上下有必定有間隔
        ///  MaterialTapTargetSize.padded:當按鈕寬(或高)不足48px時,就把寬(或高)擴展到48px。
        ///  MaterialTapTargetSize.shrinkWrap:緊縮包裹,能夠去除上下的間隔。
        FlatButton(
          color: Colors.red,
          child: Text("Flat Button1"),
          textColor: Colors.white,
          onPressed: () {},
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
        ),
        FlatButton(
          color: Colors.red,
          child: Text("Flat Button2"),
          textColor: Colors.white,
          onPressed: () {},
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
        ),

        /// 2. 修改按鈕的最小寬度:ButtonTheme
        FlatButton(
          minWidth: 30,
          height: 30,
          color: Colors.red,
          child: Text(""),
          onPressed: () {},
        ),
        ButtonTheme(
          minWidth: 30,
          height: 30,
          child: FlatButton(
            color: Colors.red,
            child: Text(""),
            onPressed: () {},
          ),
        ),

        /// 3. 修改按鈕的內間距
        FlatButton(
          padding: EdgeInsets.all(0),
          // 只能去除左右內間距,上下內間距能夠指定一個固定height解決
          color: Colors.red,
          child: Text("Float Button3"),
          textColor: Colors.white,
          onPressed: () {},
        ),
      ],
    );
  }
}
複製代碼

3、圖片 Widget

Image 控件須要一個必傳參數 ImageProvider image,常見子類以下:網絡

  • NetworkImage : 用於加載網絡圖片
    • 簡單寫法 : Image.network('http://lqr.com/FSA_QR.png')
  • AssetImage : 用於加載 app 包內圖片
    • 簡單寫法 : Image.asset('assets/images/FSA_QR.png')

一、NetworkImage

  • 常見屬性:
    • fit : 圖片填充方式
      • BoxFit.fill : 拉伸
      • BoxFit.contain : 內容縮放至最長的一邊貼邊
      • BoxFit.cover : 內容縮放至最短的一邊貼邊
      • BoxFit.fitWidth : 寬度必定,高度自適應
      • BoxFit.fitHeight : 高度必定,寬度自適應
    • alignment :
      • Alignment.bottomCenter : 底部居中
      • Alignment.center : 居中
      • Alignment(x, y) : 左上角是(-1, -1),右下角是(1, 1)
    • color : color 不是背景色,而是用於圖像混入的顏色,配合 colorBlendMode 使用
    • repeat : 重複模式,好比縱向重複 ImageRepeat.repeatY
class ImageDemo01 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisSpacing: 8,
      mainAxisSpacing: 8,
      crossAxisCount: 3,
      children: [
        wrapItem(
          Image(image: NetworkImage(imageUrl)),
          "NetworkImage",
        ),
        wrapItem(
          Image.network(imageUrl),
          "Image.network()",
        ),
        Container(),
        wrapItem(
          Image.network(imageUrl, fit: BoxFit.fill), // 拉伸
          "BoxFit.fill",
        ),
        wrapItem(
          Image.network(imageUrl, fit: BoxFit.contain), // 內容縮放至最長的一邊貼邊
          "BoxFit.contain",
        ),
        wrapItem(
          Image.network(imageUrl, fit: BoxFit.cover), // 內容縮放至最短的一邊貼邊
          "BoxFit.cover",
        ),
        wrapItem(
          Image.network(imageUrl, fit: BoxFit.fitWidth), // 寬度必定,高度自適應
          "BoxFit.fitWidth",
        ),
        wrapItem(
          Image.network(imageUrl, fit: BoxFit.fitHeight), //高度必定,寬度自適應
          "BoxFit.fitHeight",
        ),
        Container(),
        wrapItem(
          Image.network(imageUrl, alignment: Alignment.bottomCenter),
          "Alignment.topLeft",
        ),
        wrapItem(
          Image.network(imageUrl, alignment: Alignment.center),
          "Alignment.center",
        ),
        wrapItem(
          // 左上角是(-1, -1),右下角是(1, 1)
          Image.network(imageUrl, alignment: Alignment(0, -1)),
          "Alignment(0, -1)",
        ),
        wrapItem(
          // color不是背景色,而是用於圖像混入的顏色,配合 colorBlendMode 使用
          Image.network(imageUrl,
              color: Colors.green, colorBlendMode: BlendMode.colorDodge),
          "BlendMode.colorDodge",
        ),
        wrapItem(
          Image.network(imageUrl, repeat: ImageRepeat.repeatY),
          "ImageRepeat.repeatY",
        ),
      ],
    );
  }

  Widget wrapItem(Widget widget, String tip) {
    Text genTip(String tip) {
      return Text(
        tip,
        style: TextStyle(
          fontSize: 14,
          color: Colors.white,
          backgroundColor: Colors.black,
        ),
      );
    }

    return Stack(
      fit: StackFit.expand,
      children: [
        Container(color: Colors.red[100], child: widget),
        Positioned(left: 4, bottom: 4, child: genTip(tip)),
      ],
    );
  }
}
複製代碼

二、AssetImage

使用 AssetImage 加載包內圖片步驟以下:app

  1. 在 Flutter 項目中建立一個文件夾目錄(好比 assets/image),存儲圖片
  2. pubspec.yaml 進行配置
assets:
  # - assets/images/FSA_QR.png # 配置單張圖片
  - assets/images/ # 配置多張圖片
複製代碼
  1. 使用圖片
class ImageDemo02 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    // 簡單寫法
    // Image.asset('assets/images/FSA_QR.png');

    return Image(
      image: AssetImage('assets/images/FSA_QR.png'),
    );
  }
}
複製代碼

三、佔位圖(placeHolder)

在網絡圖片未加載出來以前顯示的圖片稱爲佔位圖,可使用 FadeInImage 實現佔位圖功能:less

class ImageExtensionDemo extends StatelessWidget {
  final imageUrl =
      "https://up.enterdesk.com/edpic_source/ab/a0/40/aba040ce2daa32fa9cb0cc624b385c0a.jpg";

  @override
  Widget build(BuildContext context) {
    return FadeInImage(
      fadeInDuration: Duration(milliseconds: 1),
      fadeOutDuration: Duration(milliseconds: 1),
      placeholder: AssetImage("assets/images/FSA_QR.png"),
      image: NetworkImage(imageUrl),
    );
  }
}
複製代碼

Flutter 會自動進行圖片緩存(默認最多緩存 1000 張,緩存空間最多 100m)
api.flutter.dev/flutter/wid…
api.flutter.dev/flutter/pai…ide

4、字體圖標 Widget

Icon 字體圖標和圖片圖標對比:函數

  • 字體圖標是矢量圖(放大的時候不會失真)
  • 字體圖標能夠設置顏色
  • 圖標不少時,字體圖標占據空間更小

Icon 控件接收一個必傳參數 IconData icon,Icons 中配備了大量經常使用 icon (如 Icons.pets),可使用 Icons.xxxIconData(編碼,字體) 這 2 種方式來獲得 IconData 對象。另外,IconData 的本質就是字體,所以也可使用 Text 來顯示字體圖標:

class IconDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // return Icon(Icons.pets, size: 300, color: Colors.orange);
    // return Icon(IconData(0xe90e, fontFamily: 'MaterialIcons'),size: 300,color: Colors.orange);

    /// 1. 使用Text顯示字體圖標時,須要將字體編碼 -> unicode編碼
    /// 2. 設置對應的字體fontFamily
    // return Text("0xe90e", style: TextStyle(fontSize: 100, color: Colors.orange));
    return Text(
      "\ue90e",
      style: TextStyle(
        fontSize: 100,
        color: Colors.orange,
        fontFamily: 'MaterialIcons',
      ),
    );
  }
}
複製代碼

5、表單 Widget

一、TextField 配置

  • decoration : 用於自定義輸入框樣式,InputDecoration():
    • labelText : 輸入框上的 label 文字
    • icon : 輸入框左側的 icon
    • hintText : 輸入框中的提示文字
    • border : 邊框,一般使用 OutlineInputBorder()
    • filled : 是否使用填充色,默認爲 false
    • fillColor : 填充色(能夠理解爲輸入框的背景色)
  • obscureText : 是否模糊文字,默認爲 false,密文模式設置設置爲 true
  • onChanged : 監聽文字內容變化
  • onSubmitted : 監聽提交事件
class TextFieldDemo1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(),
        TextField(
          decoration: InputDecoration(
            labelText: 'username(labelText)',
            icon: Icon(Icons.people),
            hintText: '請輸入用戶名(hintText)',
          ),
        ),
        TextField(
          decoration: InputDecoration(
            hintText: '請輸入用戶名(hintText)',
          ),
        ),
        SizedBox(height: 10),
        TextField(
          decoration: InputDecoration(
            labelText: 'OutlineInputBorder',
            icon: Icon(Icons.people),
            border: OutlineInputBorder(),
          ),
        ),
        TextField(
          decoration: InputDecoration(
            labelText: 'fillColor',
            icon: Icon(Icons.people),
            border: OutlineInputBorder(),
            filled: true,
            fillColor: Colors.red[100],
          ),
        ),
        TextField(
          decoration: InputDecoration(hintText: '監聽事件'),
          onChanged: (value) => print("onChange:$value"), // 監聽文字內容變化
          onSubmitted: (value) => print("onSubmitted:$value"), // 監聽提交事件
        ),
        TextField(
          obscureText: true, // 模糊文本
          decoration: InputDecoration(
            labelText: 'password',
            icon: Icon(Icons.lock),
            border: OutlineInputBorder(),
          ),
        )
      ],
    );
  }
}
複製代碼

二、TextField 內容獲取

Flutter 是聲明式 UI,也沒有提供 ref 之類的方式去獲取到 TextField 控件,所以沒法經過 TextField 對象來獲取輸入框中的內容,不過,能夠爲 TextField 指定 controller,經過 controller 來獲取對應輸入框中的內容:

題外話:Vue 和 React 能夠爲控件指定 ref 值,用於在 js 或 jsx 中來獲取到控件。

class TextFieldDemo2 extends StatelessWidget {
  final usernameTextEditController = TextEditingController();
  final passwordTextEditController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Column(
        children: [
          TextField(
            controller: usernameTextEditController,
            decoration: InputDecoration(
              labelText: 'username',
              icon: Icon(Icons.people),
              hintText: '請輸入用戶名',
              border: OutlineInputBorder(),
            ),
          ),
          SizedBox(height: 8),
          TextField(
            controller: passwordTextEditController,
            obscureText: true,
            decoration: InputDecoration(
              labelText: 'password',
              hintText: '請輸入密碼',
              icon: Icon(Icons.lock),
              border: OutlineInputBorder(),
            ),
          ),
          SizedBox(height: 8),
          Container(
            // width: 300,
            width: double.infinity,
            height: 40,
            child: FlatButton(
              color: Colors.blue,
              textColor: Colors.white,
              child: Text("登陸"),
              onPressed: () {
                // 1. 獲取用戶名和密碼
                final username = usernameTextEditController.text;
                final password = passwordTextEditController.text;
                print("帳號:$username , 密碼:$password");
              },
            ),
          ),
        ],
      ),
    );
  }
}
複製代碼

若是文章對您有所幫助, 請不吝點擊關注一下個人微信公衆號:FSA全棧行動, 這將是對我最大的激勵. 公衆號不只有Android技術, 還有iOS, Python等文章, 可能有你想要了解的技能知識點哦~

相關文章
相關標籤/搜索