Flutter之基礎Widget

Flutter
  • 原文博客地址: Flutter之基礎Widget
  • Flutter和Dart系列文章
  • 項目GitHub地址
  • Flutter作為一種全新的響應式,跨平臺,高性能, 完全免費、開源的移動開發框架
  • WidgetFlutter開發中的主要組成部分, 是Flutter的基礎, Flutter的核心設計思想便是: 一切皆Widget
  • Flutter中的widget的概念更廣泛,它不僅可以表示UI元素,也可以表示一些功能性的組件如:用于手勢檢測的 GestureDetector widget、用于應用主題數據傳遞的Theme等等
Flutter框架

Widget與Element

  • Widget實際上就是Element的配置數據, Widget的功能是描述一個UI元素的一個配置數據, 而真正的UI渲染是由Element構成
  • 由于Element是通過Widget生成,所以它們之間有對應關系,所以在大多數場景,我們可以寬泛地認為Widget就是指UI控件或UI渲染
  • 一個Widget對象可以對應多個Element對象。這很好理解,根據同一份配置(Widget),可以創建多個實例(Element

Widget類的聲明

@immutable
abstract class Widget extends DiagnosticableTree {
  /// Initializes [key] for subclasses.
  const Widget({ this.key });

  /// See also the discussions at [Key] and [GlobalKey].
  final Key key;

  /// multiple times.
  @protected
  Element createElement();

  /// A short, textual description of this widget.
  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
  • Widget類繼承自DiagnosticableTree,主要作用是提供調試信息。
  • Key: 這個key屬性類似于React/Vue中的key,主要的作用是決定是否在下一次build時復用舊的widget,決定的條件在canUpdate()方法中
  • createElement():正如前文所述一個Widget可以對應多個ElementFlutter Framework在構建UI時,會先調用此方法生成對應節點的Element對象。此方法是Flutter Framework隱式調用的,在我們開發過程中基本不會調用到。
  • debugFillProperties 復寫父類的方法,主要是設置DiagnosticableTree的一些特性。
  • canUpdate是一個靜態方法,它主要用于在Widget樹重新build時復用舊的widget
    • 具體來說就是:是否用新的Widget對象去更新舊UI上所對應的Element對象的配置;
    • 通過其源碼我們可以看到,只要newWidgetoldWidgetruntimeTypekey同時相等時就會用newWidget去更新Element對象的配置,否則就會創建新的Element

StatelessWidget和StatefulWidget的區別

  • StatelessWidget是狀態不可變的widget, 初始狀態設置以后就不可再變化, 如果需要變化需要重新創建; StatefulWidget可以保存自己的狀態
  • Flutter中通過引入State來保存狀態, 當State的狀態改變時,能重新構建本節點以及孩子的Widget樹來進行UI變化
  • 如果需要主動改變State的狀態,需要通過setState()方法進行觸發,單純改變數據是不會引發UI改變的
  • 下面介紹部分的Widget組件

Text

UI上面文字的展示基本上都要靠Text組件來完成

// 兩種構造函數
// 顯示普通的文本
 const Text(this.data, {
    Key key,
    this.style,
    this.textAlign,
    this.textDirection,
    this.locale,
    this.softWrap,
    this.overflow,
    this.textScaleFactor,
    this.maxLines,
    this.semanticsLabel,
  }) : assert(data != null),
       textSpan = null,
       super(key: key);

  /// 段落式文本,可以給文本中的每個textSpan設置其樣式
  const Text.rich(this.textSpan, {
    Key key,
    this.style,
    this.textAlign,
    this.textDirection,
    this.locale,
    this.softWrap,
    this.overflow,
    this.textScaleFactor,
    this.maxLines,
    this.semanticsLabel,
  }): assert(textSpan != null),
      data = null,
      super(key: key);

參數介紹

data

文本的內容

Text('titanjun')

style

文本的樣式

  const TextStyle({
    this.inherit = true,
    this.color,
    this.fontSize,
    this.fontWeight,
    this.fontStyle,
    this.letterSpacing,
    this.wordSpacing,
    this.textBaseline,
    this.height,
    this.locale,
    this.foreground,
    this.background,
    this.shadows,
    this.decoration,
    this.decorationColor,
    this.decorationStyle,
    this.debugLabel,
    String fontFamily,
    String package,
  }) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
       assert(inherit != null),
       assert(color == null || foreground == null, _kColorForegroundWarning);
       
// 相關屬性介紹
1. inherit: 為false時不顯示

2. color: 字體顏色

3. fontSize: 字體大小, 默認是14.0

4. fontWeight: 字體的粗體

5. fontStyle: 字體的樣式
    normal正常 italic 斜體

6. letterSpacing: 字符間距

7. wordSpacing: 單詞間距

8. textBaseline
    alphabetic:用于對齊字母字符底部的水平線
    ideographic:用于對齊表意字符的水平線
    
9. height: 用在Text控件上的時候,會乘以fontSize做為行高,

10. locale: 國際化

11. foreground: 用paint來渲染text,也可以用他來改變字體顏色等

12. background: 背景顏色

13. decoration: 
    下劃線 underline、 刪除線 lineThrough、上劃線 overline,默認是無 none
    
14. decorationStyle: decoration線的樣式
    solid: 直線, double: 兩條線, dotted: 短虛線, dashed: 長虛線, wavy: 波浪線

15. decorationColor: decoration線的顏色

16. debugLabel: 文本樣式的描述, 該屬性只在調試中維護

17. fontFamily和package(自定義字體的時候用的到,后面再詳解)

使用樣式示例

style: TextStyle(
    inherit: true,
    color: Colors.red,
    fontSize: 50,
    fontWeight: FontWeight.bold,
    fontStyle: FontStyle.italic,
    letterSpacing: 2,
    wordSpacing: 5,
    textBaseline: TextBaseline.alphabetic,
    height: 2,
    locale: Locale('CH'),
    decoration: TextDecoration.lineThrough,
    decorationColor: Colors.blue,
    decorationStyle: TextDecorationStyle.wavy,
),

textAlign

文本顯示方向

left: 居左顯示
center: 居中顯示
right: 居右顯示
justify: 文本的拉伸行,其末尾用軟換行符填充寬度
start: 對齊容器前緣的文本。
    對于從左到右的文本([TextDirection.ltr]),這是左邊緣。
    對于從右到左的文本([TextDirection.rtl]),這是右邊緣。
end: 對齊容器尾部邊緣的文本。
    對于從左到右的文本([TextDirection.ltr]),這是右邊緣。
    對于從右到左的文本([TextDirection.rtl]),這是左邊緣。

textDirection

和上述TextAlign.start和TextAlign.end一樣

softWrap

文本是否能換行,bool類型

overflow

用來指定超出文本的表示方式,是截斷文本啊還是用三個點顯示等

ellipsis: ...形式顯示
clip: 直接截斷
fade: 效果和clip一樣

maxLines

用來指定文本最多顯示多少行

textScaleFactor

文本字體的縮放倍數,如:1.5則在默認字體上變成1.5倍大小字體,0.5則是0.5倍

Text構造函數

child: Text(
      // 需要顯示的文字
      'titanjun.top' * 3,
      textAlign: TextAlign.left,
      textDirection: TextDirection.ltr,
      locale: Locale('CH'),
      maxLines: 1,
      overflow: TextOverflow.fade,
      style: TextStyle(
          inherit: true,
          color: Colors.red,
          fontSize: 50,
          fontWeight: FontWeight.bold,
          fontStyle: FontStyle.italic,
          letterSpacing: 2,
          wordSpacing: 5,
          textBaseline: TextBaseline.alphabetic,
          height: 2,
          locale: Locale('CH'),
          decoration: TextDecoration.lineThrough,
          decorationColor: Colors.blue,
          decorationStyle: TextDecorationStyle.wavy,
      ),
  ),

Text.rich構造函數

這個構造函數和iOS中用到的富文本類似

child: Text.rich(
    TextSpan(
      text: '博客地址: ',
      children: [
        TextSpan(
          text: 'https://',
          style: TextStyle(color: Colors.red)
        ),
        TextSpan(
          text: 'titanjun.top',
          style: TextStyle(color: Colors.blue),
        ),
        TextSpan(
          text: '歡迎訪問',
          style: TextStyle(color: Colors.orange)
        ),
      ]
    ),
),
Text.rich

其中TextSpan的構造函數如下

const TextSpan({
    this.style,
    this.text,
    // 接受List<TextSpan>類型的數組
    this.children,
    // 文本的手勢操作, 后面說這個
    this.recognizer,
});

Image

  • 一個用于展示圖片的組件。支持 JPEG、PNG、GIF、Animated GIF、WebP、Animated WebP、BMP 和 WBMP 等格式
  • Image共有五種構造函數
image

Image()

  const Image({
    Key key,
    // 一個圖片對象ImageProvider, 可設置NetworkImage(), FileImage(), MemoryImage()三種對象
    @required this.image,
    // 圖片的描述, String
    this.semanticLabel,
    this.excludeFromSemantics = false,
    // 圖片的寬度, double
    this.width,
    // 圖片的高度, double
    this.height,
    // 圖像的顏色, 用于和圖片混合的顏色, 結合colorBlendMode使用
    this.color,
    // 顏色和圖片混合的狀態, BlendMode
    this.colorBlendMode,
    // 圖像在布局中分配的空間, BoxFit
    this.fit,
    // 圖像邊界內對齊圖像, Alignment
    this.alignment = Alignment.center,
    // 未充分填充容器時,是否重復顯示圖片
    this.repeat = ImageRepeat.noRepeat,
    // 九片圖像的中心切點, Rect
    this.centerSlice,
    // 是否在圖像的方向上繪制圖像 TextDirection
    this.matchTextDirection = false,
    // 當圖像提供者發生變化時,是繼續顯示舊圖像(true)還是暫時不顯示(false)
    this.gaplessPlayback = false,
    // 設置圖片的過濾質量
    this.filterQuality = FilterQuality.low,
  }) 

部分屬性詳解

fit

圖像在布局中分配的空間, BoxFit枚舉值

  • fill: 填充滿容器空間, 圖片會被拉伸
  • contain: 以容器的大小等比例縮放圖片
  • cover: 填充整個容器, 圖片會被剪切
  • fitWidth: 以容器的寬度, 等比例縮放圖片
  • fitHeight: 以容器的高度, 等比例的縮放圖片
  • none: 以圖片的實際大小顯示
  • scaleDown: 居中顯示, 圖片不會拉伸, 以寬高中最小的尺寸為標準
alignment

圖像邊界內對齊圖像, Alignment類, 不是枚舉值

  /// 定義方式為垂直方向-水平方向
  static const Alignment topLeft = Alignment(-1.0, -1.0);
  static const Alignment topCenter = Alignment(0.0, -1.0);
  static const Alignment topRight = Alignment(1.0, -1.0);
  static const Alignment centerLeft = Alignment(-1.0, 0.0);
  static const Alignment center = Alignment(0.0, 0.0);
  static const Alignment centerRight = Alignment(1.0, 0.0);
  static const Alignment bottomLeft = Alignment(-1.0, 1.0);
  static const Alignment bottomCenter = Alignment(0.0, 1.0);
  static const Alignment bottomRight = Alignment(1.0, 1.0);
  
  /// 使用方式
  alignment: Alignment.topLeft,
  // 或者
  alignment: Alignment(0.0, 1.0)
Image(
  image: NetworkImage('https://titanjun.oss-cn-hangzhou.aliyuncs.com/flutter/flutter.jpeg?x-oss-process=style/titanjun'),
  fit: BoxFit.scaleDown,
  alignment: Alignment.topLeft,
),

Image.network

用于顯示網絡圖片

Image.network(
  'https://titanjun.oss-cn-hangzhou.aliyuncs.com/flutter/catimage.jpg',
  width: 100,
  height: 100,
  fit: BoxFit.scaleDown,
  alignment: Alignment.center,
)

網絡請求Image是最常見的操作, 這里重點說明兩個點

緩存

  • ImageCacheImageProvider默認使用的圖片緩存。ImageCache使用的是LRU的算法
  • 默認可以存儲1000張圖片。如果覺得緩存太大,可以通過設置ImageCachemaximumSize屬性來控制緩存圖片的數量。
  • 也可以通過設置maximumSizeBytes來控制緩存的大小(默認緩存大小10MB)

CDN優化

如果想要使用cdn優化,可以通過url增加后綴的方式實現。默認實現中沒有這個點,但是考慮到cdn優化的可觀收益,建議大家利用好這個優化

Image.asset

  • Flutter應用程序可以包含代碼和 assets(有時稱為資源)
  • asset是打包到程序安裝包中的,可在運行時訪問
  • 常見類型的asset包括靜態數據(例如JSON文件),配置文件,圖標和圖片(JPEG,WebP,GIF,動畫WebP / GIF,PNG,BMP和WBMP)
  • Flutter使用pubspec.yaml文件(位于項目根目錄),來識別應用程序所需的asset
image

需要注意的是

  • 圖片所在的文件夾imagespubspec.yaml需要在同一目錄下, 否則pubspec.yaml文件中, 設置資源路徑的時候要對應修改
  • images圖片文件夾中2.0x和3.0x圖片要分別創建兩個文件夾, 并把2倍和3倍圖分別放在不同的文件夾中, 切文件的名字不要在帶@2x和@3x字樣
image
Image.asset(
  'images/home.png',
  width: 100,
  height: 100,
  fit: BoxFit.scaleDown,
  alignment: Alignment.center,
)

Image.file

Image.file(File file, {
    Key key,
    double scale = 1.0,
    this.semanticLabel,
    this.excludeFromSemantics = false,
    this.width,
    this.height,
    this.color,
    this.colorBlendMode,
    this.fit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.centerSlice,
    this.matchTextDirection = false,
    this.gaplessPlayback = false,
    this.filterQuality = FilterQuality.low,
  })
  • 主要解析file參數,其他與Image()構造的參數一致!
  • file: 對文件系統上的文件的引用。
  • File 實例是一個對象,它包含可以在其上執行操作的路徑

Image.memory

Image.memory(Uint8List bytes, {
    Key key,
    double scale = 1.0,
    this.semanticLabel,
    this.excludeFromSemantics = false,
    this.width,
    this.height,
    this.color,
    this.colorBlendMode,
    this.fit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.centerSlice,
    this.matchTextDirection = false,
    this.gaplessPlayback = false,
    this.filterQuality = FilterQuality.low,
  })
  • 加載Uint8List資源圖片
  • 主要解析bytes參數,其他與Image()構造的參數一致!

Icon

  • Flutter中,Icon是類似于web開發中一樣使用iconfont(字體圖標),它是將圖標做成字體文件,然后通過指定不同的字符而顯示不同的圖片
  • 在字體文件中,每一個字符都對應一個位碼,而每一個位碼對應一個顯示字形,不同的字體就是指字形不同,即字符對應的字形是不同的
  • 而在iconfont中,只是將位碼對應的字形做成了圖標,所以不同的字符最終就會渲染成不同的圖標。
  • Fluttericonfont相較于圖片的優勢如下:
    • 體積小:可以減小安裝包大小。
    • 矢量的:iconfont都是矢量圖標,放大不會影響其清晰度。
    • 可以應用文本樣式:可以像文本一樣改變字體圖標的顏色、大小對齊等。
    • 可以通過TextSpan和文本混用。

使用Material Design字體圖標

Flutter默認包含了一套Material Design的字體圖標,在pubspec.yaml文件中的配置如下

flutter:
  uses-material-design: true

<div class="note warning"><p>如果設置成false, 則圖片效果如下, 圖片顏色為自己設置的顏色</p></div>

image

在Text中使用

下面看一個在Text中使用iconfont的示例

String iconStr = "";
// accessible: &#xE914; or 0xE914 or E914
iconStr += "\uE914";
// error: &#xE000; or 0xE000 or E000
iconStr += " \uE000";
// fingerprint: &#xE90D; or 0xE90D or E90D
iconStr += " \uE90D";


Text(iconStr,
  style: TextStyle(
    fontFamily: "MaterialIcons",
    fontSize: 80.0,
    color: Colors.green
  ),
)

上述代碼的運行效果如下

image

任何一個圖片我們都可以使用Text文本進行展示, 但是這需要我們提供每一個圖標的字符碼點, 可在material-design-icons中搜索查找, 而且并不能固定指定圖片的大小, 只能設置字體的大小, 這并對開發者不友好

Icon介紹

Flutter封裝了一個Icon來專門顯示字體圖標,上面的例子也可以用如下方式實現

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Icon(Icons.accessible, color: Colors.green, size: 80),
    Icon(Icons.error, color: Colors.green, size: 80),
    Icon(Icons.fingerprint, color: Colors.green, size: 80),
  ],
)

Icons類中包含了所有Material Design圖標的IconData靜態變量定義, .....我大概算了一下, Icons中大概一共定義了984中圖標

// icon的構造函數
const Icon(this.icon, {
    Key key,
    // double, 設置圖片的大小, 同事設置寬高
    this.size,
    // Color, 設置圖片的顏色
    this.color,
    // String, 圖標的語義標簽
    this.semanticLabel,
    // TextDirection, 從左/右開始排列
    this.textDirection,
})

按鈕

  • Flutter提供了RaisedButtonFlatButtonOutlineButtonIconButton四種按鈕, 除了IconButton之外都是繼承自MaterialButton
  • 所有Material庫中的按鈕都有如下相同點:
    • 按下時都會有“水波動畫”。
    • 有一個onPressed屬性來設置點擊回調,當按鈕按下時會執行該回調,如果不提供該回調則按鈕會處于禁用狀態,禁用狀態不響應用戶點擊

MaterialButton

MaterialButton是除IconButton按鈕之外的其他按鈕的父類, 下面介紹一下各屬性的使用

const MaterialButton({
    Key key,
    // 點擊事件
    @required this.onPressed,
    // 高亮狀態變化回調,參數:是否高亮,按下時高亮,抬起不高亮
    this.onHighlightChanged,
    // 字體的主體
    this.textTheme,
    // 按鈕文字顏色
    this.textColor,
    // 禁用狀態下按鈕字體顏色
    this.disabledTextColor,
    // 按鈕背景顏色
    this.color,
    // 禁用狀態下背景顏色
    this.disabledColor,
    // 高亮狀態(按下時的背景顏色)
    this.highlightColor,
    // 按鈕的水波紋的顏色
    this.splashColor,
    // 字體亮度
    this.colorBrightness,
    // 按鈕底部陰影效果的偏移量, double
    this.elevation,
    // 高亮狀態下, 按鈕底部陰影效果的偏移量, double
    this.highlightElevation,
    // 禁用狀態下, 按鈕底部陰影效果的偏移量, double
    this.disabledElevation,
    // 內邊距
    this.padding,
    // 按鈕的形狀
    this.shape,
    this.clipBehavior = Clip.none,
    this.materialTapTargetSize,
    this.animationDuration,
    // 按鈕的最小寬度
    this.minWidth,
    // 按鈕的高度
    this.height,
    // 子widget
    this.child,
})

onPressed

按鈕觸發時觸發的函數,如果不設置此屬性Button為不可用狀態

onPressed: () => print('被點擊了'),

textTheme

按鈕字體的主題, 在onPressed不為空的時候才有效果

/// 三個取值
ButtonTextTheme.normal
ButtonTextTheme.accent
ButtonTextTheme.primary
image

colorBrightness

設置按鈕的字體亮度, 取值分別是Brightness.lightBrightness.darks

image

padding

內邊距,其接收值的類型是EdgeInsetsGeometry類型的,EdgeInsetsGeometry是一個抽象類, 只能使用其子類EdgeInsets來實現

padding: EdgeInsets.all(10)

shape

  • 設置按鈕的形狀,其接收值是ShapeBorder類型,ShapeBorder也是一個抽象類
  • ShapeBorder的子類中比較常用的幾個如下所示
    • BeveledRectangleBorder 帶斜角的長方形邊框
    • CircleBorder 圓形邊框
    • RoundedRectangleBorder 圓角矩形
    • StadiumBorder 兩端是半圓的邊框
// 帶斜角的長方形邊框
const BeveledRectangleBorder({
    // 邊框的樣式 
    this.side = BorderSide.none,
    // 圓角大小
    this.borderRadius = BorderRadius.zero,
})

// 圓形邊框
const CircleBorder({ 
    this.side = BorderSide.none 
})

// 圓角矩形
const RoundedRectangleBorder({
    this.side = BorderSide.none,
    this.borderRadius = BorderRadius.zero,
})

// 兩端是半圓的邊框
const StadiumBorder({ 
    this.side = BorderSide.none 
})

// 邊框樣式的設置
const BorderSide({
    // 邊框顏色, 默認黑色 
    this.color = const Color(0xFF000000),
    // 邊框寬度, 默認1.0
    this.width = 1.0,
    // 邊框樣式, solid: 實線邊框(默認值), none: 不顯示邊框
    this.style = BorderStyle.solid,
})

下面就來看一下shape的配置和使用, 設置默認狀態(即所有的邊框樣式和圓角都是默認值)的效果如下

image
children: <Widget>[
  // BeveledRectangleBorder
  RaisedButton(
    child: Text('BeveledRectangleBorder'),
    onPressed: () => print('RaisedButton'),
    shape: BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(10)),
      side: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid
      )
    ),
  ),
  RaisedButton(
    child: Icon(Icons.supervisor_account, color: Colors.green, size: 40),
    onPressed: () => print('RaisedButton'),
    padding: EdgeInsets.all(10),
    shape: CircleBorder(
      side: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid
      )
    ),
  ),
  RaisedButton(
    child: Text('RoundedRectangleBorder'),
    onPressed: () => print('RaisedButton'),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(10)),
      side: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid
      )
    ),
  ),
  RaisedButton(
    child: Text('StadiumBorder'),
    onPressed: () => print('RaisedButton'),
    shape: StadiumBorder(
      side: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid
      )
    ),
  ),
],

上述代碼是分別設置圓角和邊框后的代碼, 效果如下

image

RaisedButton

  • RaisedButton即"漂浮"按鈕,它默認帶有陰影和灰色背景。按下后陰影會變大
  • RaisedButton繼承自MaterialButton, 相關屬性和父類一樣
RaisedButton(
    child: Text('RaisedButton'),
    onPressed: () => print('RaisedButton'),
)

FlatButton

  • FlatButton即扁平按鈕,默認背景透明并不帶陰影。按下后,會有背景色
  • RaisedButton繼承自MaterialButton, 相關屬性和父類一樣
FlatButton(
    child: Text('FlatButton'),
    onPressed: () => print('FlatButton'),
)

OutlineButton

  • OutlineButton默認有一個邊框,不帶陰影且背景透明。按下后,邊框顏色會變亮、同時出現背景和陰影(較弱)
  • RaisedButton繼承自MaterialButton, 相關屬性和父類一樣
OutlineButton(
    child: Text('OutlineButton'),
    onPressed: () => print('OutlineButton'),
)

IconButton

IconButton是一個可點擊的Icon,不包括文字,默認沒有背景,點擊后會出現背景

// 繼承自StatelessWidget
class IconButton extends StatelessWidget {
  const IconButton({
    Key key,
    // 按鈕的大小
    this.iconSize = 24.0,
    // 內邊距
    this.padding = const EdgeInsets.all(8.0),
    // 按鈕中圖片的對齊方式
    this.alignment = Alignment.center,
    // 圖片按鈕的圖片Icon
    @required this.icon,
    // 背景色
    this.color,
    // 高亮狀態下的背景色
    this.highlightColor,
    // 按鈕按下時, 水波紋的顏色
    this.splashColor,
    // 禁用狀態下, 按鈕的背景色
    this.disabledColor,
    // 點擊事件
    @required this.onPressed,
    // String, 描述按鈕按下時的描述文本, 需要長按才能出現(黑框顯示文本)
    this.tooltip
  })
}

使用示例

IconButton(
    icon: Icon(Icons.mail_outline, color:Colors.orange, size: 40),
    color: Colors.yellow,
    iconSize: 100,
    alignment: Alignment.topLeft,
    onPressed: () => print('IconButton'),
    tooltip: 'titanjun.top',
)

圖文按鈕

每一個繼承自MaterialButton的按鈕Widget都有一個工廠構造函數, 返回一個圖片在左, 文字在右的按鈕

factory RaisedButton.icon({
    // 這里包含MaterialButton的所有屬性
    ....
    // 圖片Widget
    @required Widget icon,
    // 文字Widget
    @required Widget label,
  })
  
factory FlatButton.icon({
    ....
    @required Widget icon,
    @required Widget label,
  })
  
factory OutlineButton.icon({
    ....
    @required Widget icon,
    @required Widget label,
  })
  
// 使用示例
RaisedButton.icon(
  label: Text('data'),
  icon: Icon(Icons.mail),
  onPressed: () => {},
),

單選開關和復選框

  • Material widgets庫中提供了Material風格的單選開關Switch和復選框Checkbox,它們都是繼承自StatelessWidget
  • 它們本身不會保存當前選擇狀態,所以一般都是在父widget中管理選中狀態
  • 當用戶點擊SwitchCheckbox時,它們會觸發onChanged回調,我們可以在此回調中處理選中狀態改變邏輯
// Switch屬性
const Switch({
    Key key,
    // Switch的狀態值, true開啟, false關閉
    @required this.value,
    // Switch改變狀態所執行的操作
    @required this.onChanged,
    // 開啟狀態下選項條的顏色
    this.activeColor,
    // 開啟狀態下圓球的顏色
    this.activeTrackColor,
    // 關閉狀態下選項條的顏色
    this.inactiveThumbColor,
    // 關閉狀態下圓球的顏色
    this.inactiveTrackColor,
    // 設置開啟狀態下圓球的圖片
    this.activeThumbImage,
    // 設置關閉狀態下圓球的圖片
    this.inactiveThumbImage,
    // 設置Switch的尺寸樣式, padded: 建議大小48, shrinkWrap: 可能的最小尺寸
    this.materialTapTargetSize,
})

// Checkbox屬性
const Checkbox({
    Key key,
    // Switch的狀態值, true選中, false未選中
    @required this.value,
    // 如果為 true,那么復選框的值可以是 true,false 或 null
    // 如果為false(默認值), 那么只有true和false兩種狀態
    this.tristate = false,
    // 改變狀態時執行的函數
    @required this.onChanged,
    // 選中時的顏色
    this.activeColor,
    // 設置Checkbox的尺寸樣式, padded: 建議大小48, shrinkWrap: 可能的最小尺寸
    this.materialTapTargetSize,
})

使用代碼

children: <Widget>[
  Switch(
    value: false,
    onChanged: (value) {},
    activeColor: Colors.red,
    activeTrackColor: Colors.yellow,
    inactiveThumbColor: Colors.blue,
    inactiveTrackColor: Colors.cyan,
    materialTapTargetSize: MaterialTapTargetSize.shrinkWrap
  ),
  Checkbox(
    value: true,
    onChanged: (value) { },
    activeColor: Colors.orange,
    tristate: true,
  )
],
image


歡迎您掃一掃下面的微信公眾號,訂閱我的博客!

微信公眾號
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容