Flutter的 Image Widget
原始碼:image.dart
圖片的顯示
class Image extends StatefulWidget
Image
繼承自 [StatefulWidget
],它是具有狀態的,通過
@override///image.dart 574L
_ImageState createState() => _ImageState();
可以找到 Image
對應的State
類是 _ImageState
, 那麼構建Widget的方法就在_ImageState
的build
方法中,如下:
@override
Widget build(BuildContext context) {
final RawImage image = RawImage(
image: _imageInfo?.image,
width: widget.width,
height: widget.height,
scale: _imageInfo?.scale ?? 1.0,
color: widget.color,
colorBlendMode: widget.colorBlendMode,
fit: widget.fit,
alignment: widget.alignment,
repeat: widget.repeat,
centerSlice: widget.centerSlice,
matchTextDirection: widget.matchTextDirection,
invertColors: _invertColors,
filterQuality: widget.filterQuality,
);
if (widget.excludeFromSemantics)
return image;
return Semantics(
container: widget.semanticLabel != null,
image: true,
label: widget.semanticLabel == null ? '' : widget.semanticLabel,
child: image,
);
}
由原始碼可以看到,在此方法中建立的是 RawImage
widget ,傳入 imageInfo.image
,並由 RawImage
來渲染圖片資料。
圖片的載入
Image
類有這麼幾個構造方法,方便開發者載入顯示本地,檔案,網路中的圖片資料。
/// * [new Image], for obtaining an image from an [ImageProvider].
/// * [new Image.asset], for obtaining an image from an [AssetBundle]
/// using a key.
/// * [new Image.network], for obtaining an image from a URL.
/// * [new Image.file], for obtaining an image from a [File].
/// * [new Image.memory], for obtaining an image from a [Uint8List].
Image
載入了圖片資料後儲存在 imageInfo.image
。ImageInfo
類很簡單,只有兩個屬性:
@immutable
class ImageInfo {
//圖片畫素點陣,
final ui.Image image;
//縮放比例,例當scale為2時,寬高都將變為原圖的2倍。
final double scale;
}
那imageInfo
又是在哪生成的呢,也就是在哪載入了圖片的資料呢?根據 ImageInfo
類的註釋, ImageInfo
一旦被獲得,就會被 ImageStream
用來表示為真實的圖片資料。
ImageStream
的部分原始碼如下:
class ImageStream extends Diagnosticable {
/// Create an initially unbound image stream.
///
/// Once an [ImageStreamCompleter] is available, call [setCompleter].
ImageStream();
/// The completer that has been assigned to this image stream.
///
/// Generally there is no need to deal with the completer directly.
ImageStreamCompleter get completer => _completer;
ImageStreamCompleter _completer;
可見 ImageStream
主要是由 ImageStreamCompleter
來提供支援,只是一個 ImageStreamCompleter
的包裝類,不過當ImageStreamCompleter
可用的時候,需呼叫ImageStream.setCompleter
方法,以將事件傳遞給ImageStream
中的監聽者。
那麼 ImageStreamCompleter
又是個啥?繼續往下看,原始碼:
/// Base class for those that manage the loading of [dart:ui.Image] objects for
/// [ImageStream]s.
///
/// [ImageStreamListener] objects are rarely constructed directly. Generally, an
/// [ImageProvider] subclass will return an [ImageStream] and automatically
/// configure it with the right [ImageStreamCompleter] when possible.
abstract class ImageStreamCompleter extends Diagnosticable {
final List<_ImageListenerPair> _listeners = <_ImageListenerPair>[];
ImageInfo _currentImage;
void addListener(ImageListener listener, { ImageErrorListener onError }) {
//省略
}
void removeListener(ImageListener listener) {
//省略
}
/// Calls all the registered listeners to notify them of a new image.
@protected
void setImage(ImageInfo image) {
_currentImage = image;
if (_listeners.isEmpty)
return;
final List<ImageListener> localListeners = _listeners.map<ImageListener>(
(_ImageListenerPair listenerPair) => listenerPair.listener
).toList();
for (ImageListener listener in localListeners) {
try {
listener(image, false);
} catch (exception, stack) {
reportError(
context: 'by an image listener',
exception: exception,
stack: stack,
);
}
}
}
}
ImageStreamCompleter
是一個抽象類。去掉新增/移除Listener的方法後,還剩一個 [setImage
] 方法,方法內部邏輯很簡單,將傳入的引數 ImageInfo
傳遞到各個 ImageListener
,然後重新整理GUI。
ImageStreamCompleter
有兩個實現類,分別為
OneFrameImageStreamCompleter
MultiFrameImageStreamCompleter
。
那剛才看下來的原始碼只是一個監聽的設計而已:
widget
監聽 ImageStream
, 而widget
設定給ImageStream
的 listener
被傳遞到 ImageStreamCompleter
。當圖片成功載入時,ImageStreamCompleter
的setImage
方法被呼叫,圖片通過回撥回傳到 widget
。
圖片的載入2
Image類構造方法需傳入一個 ImageProvider
,圖片應便是在這裡面被載入的:
abstract class ImageProvider<T> {
///根據 configuration 處理 ImagePrivoder,並返回一個 ImageStream物件
///子類應該實現 [obtainKey] 和 [load] 方法,並且這兩個方法在此流程中使用
ImageStream resolve(ImageConfiguration configuration) {
assert(configuration != null);
final ImageStream stream = ImageStream();
T obtainedKey;
obtainKey(configuration).then<void>((T key) {
obtainedKey = key;
///當拿到KEY時,查詢快取
stream.setCompleter(PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key)));
}).catchError(
//省略錯誤處理...
return null;
}
);
return stream;
}
/// 根據 ImageConfiguration和 ImageProvider 的屬性來生成一個KEY用來標識載入的圖片
/// KEY要求實現 '==' 和 hascode 方法,這個KEY主要是用於快取
@protected
Future<T> obtainKey(ImageConfiguration configuration);
///開始載入圖片
@protected
ImageStreamCompleter load(T key);
}
其中 resolve
方法根據ImageConfiguration
來獲取相應的ImageStream
。
到目前為止,圖片獲取的流程應該差不多可以這樣來表示...
圖片的快取
在ImageProvider
的原始碼中能過看到,圖片的載入是做過快取處理的。即在ImageProvider
的resolve
方法中,有這麼一句:
stream.setCompleter(PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key)));
1. KEY
image.putIfAbsent
傳入的 key 的型別即為ImageProvider<T>
中的T
,需是不可改變的(immutable)以及實現[==
] 和 [hashcode
]方法。並且由 ImageProvider.obtainKey
方法生成,例如NetworkImage
中是這麼實現的:
class NetworkImage extends ImageProvider<NetworkImage> {
@override
Future<NetworkImage> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<NetworkImage>(this);
}
@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType)
return false;
final NetworkImage typedOther = other;
return url == typedOther.url
&& scale == typedOther.scale;
}
@override
int get hashCode => hashValues(url, scale);
}
2.ImageCache
快取的邏輯主要在 putIfAbent
方法中
使用的 LRU,並且預設最多儲存 1000個快取,最大快取限制為100MiB
const int _kDefaultSize = 1000;
const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
目前的圖片大小是這麼計算的:
final int imageSize = info?.image == null ? 0 : info.image.height * info.image.width * 4;
3.快取
由上程式碼可以看出,flutter 自帶的快取只會在執行期間生效,也就是快取在記憶體中。
相關文章
- Flutter 學習 - Widget 之 Image和IconFlutter
- Flutter中的WidgetFlutter
- Flutter Widget中的StateFlutter
- Flutter Widget and BaldFlutter
- Flutter Widget大全Flutter
- Flutter(八)之Flutter的基礎WidgetFlutter
- Flutter(十)之Flutter的滾動WidgetFlutter
- Flutter widget的生命週期Flutter
- Flutter元件ImageFlutter元件
- 14、Flutter Widget - Dismissible;Flutter
- 15、Flutter Widget - webview;FlutterWebView
- 16、Flutter Widget - PageView;FlutterView
- 13、Flutter Widget - FadeInImage;Flutter
- 1、Flutter Widget - Align ;Flutter
- 2、Flutter Widget - Positioned;Flutter
- 3、Flutter Widget - ImageFilter;FlutterFilter
- 4、Flutter Widget - Transform;FlutterORM
- 5、Flutter Widget - AbsorbPointer;FlutterORB
- 6、Flutter Widget - LayoutBuilder;FlutterUI
- 7、Flutter Widget - FittedBox;Flutter
- 8、Flutter Widget - Tooltip;Flutter
- 9、Flutter Widget - CustomPaint;FlutterAI
- 10、Flutter Widget - Hero;Flutter
- 11、Flutter Widget - ClipRRect;Flutter
- 12、Flutter Widget - InheritedModel;Flutter
- 1、Flutter Tips - Widget Key;Flutter
- Flutter UI - button系 WidgetFlutterUI
- Flutter widget元件簡介Flutter元件
- Flutter 常用 Widget 介紹Flutter
- [譯]Flutter: Widget Size and PositionFlutter
- Flutter AnimatedContainer 自帶動畫的WidgetFlutterAI動畫
- Flutter常用Widget詳解(三)Flutter
- Flutter Widget自定義總結Flutter
- 1、Flutter Widget(IOS Style) - CupertinoApp;FlutteriOSAPP
- 2、Flutter Widget(IOS Style) - CupertinoActionSheet;FlutteriOS
- 3、Flutter Widget(IOS Style) - CupertinoAlertDialog;FlutteriOS
- Flutter快速上車之WidgetFlutter
- Flutter之Widget大小與位置Flutter