方法一
按照給定尺寸進(jìn)行圖片的解碼,而不是解碼整個(gè)圖片的尺寸,用來減少內(nèi)存的占用。
官方文檔:
https://api.flutter.dev/flutter/painting/ResizeImage-class.html
官方說明:
Instructs Flutter to decode the image at the specified dimensions instead of at its native size.
This allows finer control of the size of the image in ImageCache and is generally used to reduce the memory footprint of ImageCache.
The decoded image may still be displayed at sizes other than the cached size provided here.
使用:
Image(
image: ResizeImage(
NetworkImage('https://img-dev.xinxigu.com.cn/s1/2021/1/18/6e19c84b1b4aeb416bdee40615aa9854.jpg'),
width: AdaptUtils.pxW(150).toInt(),
height: AdaptUtils.pxW(150).toInt(),
),
),
方法二
三方庫:cached_network_image 限2.5.0之后版本才可用
設(shè)定最大的緩存寬度和高度this.maxWidthDiskCache、this.maxHeightDiskCache

CachedNetworkImage({
Key key,
@required this.imageUrl,
this.httpHeaders,
this.imageBuilder,
this.placeholder,
this.progressIndicatorBuilder,
this.errorWidget,
this.fadeOutDuration = const Duration(milliseconds: 1000),
this.fadeOutCurve = Curves.easeOut,
this.fadeInDuration = const Duration(milliseconds: 500),
this.fadeInCurve = Curves.easeIn,
this.width,
this.height,
this.fit,
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.matchTextDirection = false,
this.cacheManager,
this.useOldImageOnUrlChange = false,
this.color,
this.filterQuality = FilterQuality.low,
this.colorBlendMode,
this.placeholderFadeInDuration,
this.memCacheWidth,
this.memCacheHeight,
this.cacheKey,
this.maxWidthDiskCache,
this.maxHeightDiskCache,
使用:
CachedNetworkImage(
imageUrl: AppUtils.processImageUrl(url: coverUrl) ?? AppURL.defaultImageRectangle,
width: AdaptUtils.pxW(150),
height: AdaptUtils.pxW(150),
fit: BoxFit.cover,
placeholder: AppURL.placeholderRectangle(
width: AdaptUtils.pxW(150),
height: AdaptUtils.pxW(150),
),
maxWidthDiskCache: AdaptUtils.pxW(150 * 2).toInt(),
maxHeightDiskCache: AdaptUtils.pxW(150 * 2).toInt(),
),
方法三
從相冊(cè)選取圖片,展示時(shí)使用指定尺寸寬高進(jìn)行處理。
使用三方庫:
# 仿微信資源選擇器
wechat_assets_picker: ^4.2.0
# 仿微信拍照
wechat_camera_picker: ^1.2.1
使用自定義provider來指定所需圖片的寬高:
/// The item builder for images and video type of asset.
/// 圖片和視頻資源的部件構(gòu)建
/// 縮略圖視圖
static Widget thumbImageItemBuilder(
BuildContext context,
AssetEntity asset, // 圖片資源數(shù)據(jù)
double thumbSizeWidth, // 縮略圖寬,同為圖片展示寬
double thumbSizeHeight, // 縮略圖高,同為圖片展示高
BoxFit fit, // 圖片展示方式
) {
final AssetEntityImageProvider imageProvider = AssetEntityImageProvider(
asset,
isOriginal: false,
thumbSize: [int.parse('${thumbSizeWidth.toStringAsFixed(0)}'), int.parse('${thumbSizeWidth.toStringAsFixed(0)}')],
);
return RepaintBoundary(
child: Image(
width: thumbSizeWidth,
height: thumbSizeHeight,
image: imageProvider,
fit: fit,
),
);
}
AssetEntityImageProvider傳入寬高和圖片原圖AssetEntity數(shù)據(jù)。
provider中key.entity.thumbDataWithSize方法:
Future<ui.Codec> _loadAsync(
AssetEntityImageProvider key,
DecoderCallback decode,
) async {
assert(key == this);
Uint8List data;
if (isOriginal ?? false) {
if (imageFileType == ImageFileType.heic) {
data = await (await key.entity.file).readAsBytes();
} else {
data = await key.entity.originBytes;
}
} else {
data = await key.entity.thumbDataWithSize(thumbSize[0], thumbSize[1]);
}
return decode(data);
}
進(jìn)入entity中thumbDataWithSize方法:
/// get thumb with size
Future<Uint8List> thumbDataWithSize(
int width,
int height, {
ThumbFormat format = ThumbFormat.jpeg,
int quality = 100,
}) {
assert(width > 0 && height > 0, "The width and height must better 0.");
assert(format != null, "The format must not be null.");
assert(quality > 0 && quality <= 100, "The quality must between 0 and 100");
/// Return null if asset is audio or other type, because they don't have such a thing.
if (type == AssetType.audio || type == AssetType.other) {
return null;
}
return PhotoManager._getThumbDataWithId(
id,
width: width,
height: height,
format: format,
quality: quality,
);
}
進(jìn)入_getThumbDataWithId方法中,
static _getThumbDataWithId(
String id, {
int width = 150,
int height = 150,
ThumbFormat format = ThumbFormat.jpeg,
int quality = 100,
}) {
return _plugin.getThumb(
id: id,
width: width,
height: height,
format: format,
quality: quality,
);
}
進(jìn)入getThumb:
Future<Uint8List> getThumb({
@required String id,
int width = 100,
int height = 100,
ThumbFormat format,
int quality,
}) {
return _channel.invokeMethod("getThumb", {
"width": width,
"height": height,
"id": id,
"format": format.index,
"quality": quality,
});
}
調(diào)用iOS原生的獲取圖片方法,
if ([call.method isEqualToString:@"getThumb"]) {
NSString *id = call.arguments[@"id"];
NSUInteger width = [call.arguments[@"width"] unsignedIntegerValue];
NSUInteger height = [call.arguments[@"height"] unsignedIntegerValue];
NSUInteger format = [call.arguments[@"format"] unsignedIntegerValue];
NSUInteger quality = [call.arguments[@"quality"] unsignedIntegerValue];
[manager getThumbWithId:id width:width height:height format:format quality:quality resultHandler:handler];
}
進(jìn)入getThumbWithId方法,
- (void)getThumbWithId:(NSString *)id width:(NSUInteger)width height:(NSUInteger)height format:(NSUInteger)format quality:(NSUInteger)quality resultHandler:(ResultHandler *)handler {
PMAssetEntity *entity = [self getAssetEntity:id];
if (entity && entity.phAsset) {
PHAsset *asset = entity.phAsset;
[self fetchThumb:asset width:width height:height format:format quality:quality resultHandler:handler];
} else {
[handler replyError:@"asset is not found"];
}
}
原生實(shí)現(xiàn)獲取置頂寬高縮略圖方法實(shí)現(xiàn):
使用iOS原生類PHImageManager的
targetSize:CGSizeMake(width, height)
contentMode:PHImageContentModeAspectFill
options:options
resultHandler:^(UIImage *result, NSDictionary *info)
來獲取縮略圖。
- (void)fetchThumb:(PHAsset *)asset width:(NSUInteger)width height:(NSUInteger)height format:(NSUInteger)format quality:(NSUInteger)quality resultHandler:(ResultHandler *)handler {
PHImageManager *manager = PHImageManager.defaultManager;
PHImageRequestOptions *options = [PHImageRequestOptions new];
[options setNetworkAccessAllowed:YES];
[options setProgressHandler:^(double progress, NSError *error, BOOL *stop,
NSDictionary *info) {
if (progress == 1.0) {
[self fetchThumb:asset width:width height:height format:format quality:quality resultHandler:handler];
}
}];
[manager requestImageForAsset:asset
targetSize:CGSizeMake(width, height)
contentMode:PHImageContentModeAspectFill
options:options
resultHandler:^(UIImage *result, NSDictionary *info) {
BOOL downloadFinished = [PMManager isDownloadFinish:info];
if (!downloadFinished) {
return;
}
if ([handler isReplied]) {
return;
}
NSData *imageData;
if (format == 1) {
imageData = UIImagePNGRepresentation(result);
} else {
double qualityValue = (double) quality / 100.0;
imageData = UIImageJPEGRepresentation(result, qualityValue);
}
FlutterStandardTypedData *data = [FlutterStandardTypedData typedDataWithBytes:imageData];
[handler reply:data];
}];
}