Flutter之Text和Image

RunTitan發表於2019-04-19

Flutter

  • 原文部落格地址: Flutter之Text和Image
  • 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://user-gold-cdn.xitu.io/2019/4/19/16a34ef6cd5c73e1?w=1196&h=698&f=jpeg&s=29359'),
  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()構造的引數一致!

參考文件

相關文章