- 原文部落格地址: Flutter之Text和Image
- Flutter和Dart系列文章
- 專案GitHub地址
Flutter
作為一種全新的響應式,跨平臺,高效能, 完全免費、開源的移動開發框架Widget
是Flutter
開發中的主要組成部分, 是Flutter
的基礎,Flutter
的核心設計思想便是: 一切皆Widget
Flutter
中的widget
的概念更廣泛,它不僅可以表示UI
元素,也可以表示一些功能性的元件如:用於手勢檢測的GestureDetector
widget
、用於應用主題資料傳遞的Theme
等等
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可以對應多個Element
;Flutter Framework
在構建UI時,會先呼叫此方法生成對應節點的Element
物件。此方法是Flutter Framework
隱式呼叫的,在我們開發過程中基本不會呼叫到。debugFillProperties
複寫父類的方法,主要是設定DiagnosticableTree
的一些特性。canUpdate
是一個靜態方法,它主要用於在Widget
樹重新build
時複用舊的widget
- 具體來說就是:是否用新的
Widget
物件去更新舊UI上所對應的Element
物件的配置; - 通過其原始碼我們可以看到,只要
newWidget
與oldWidget
的runtimeType
和key
同時相等時就會用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)
),
]
),
),
複製程式碼
其中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()
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
是最常見的操作, 這裡重點說明兩個點
快取
ImageCache
是ImageProvider
預設使用的圖片快取。ImageCache
使用的是LRU
的演算法- 預設可以儲存1000張圖片。如果覺得快取太大,可以通過設定
ImageCache
的maximumSize
屬性來控制快取圖片的數量。 - 也可以通過設定
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
需要注意的是
- 圖片所在的資料夾
images
和pubspec.yaml
需要在同一目錄下, 否則pubspec.yaml
檔案中, 設定資源路徑的時候要對應修改 images
圖片資料夾中2.0x和3.0x
圖片要分別建立兩個資料夾, 並把2倍和3倍圖分別放在不同的資料夾中, 切檔案的名字不要在帶@2x和@3x
字樣
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()
構造的引數一致!