方法一
按照给定尺寸进行图片的解码,而不是解码整个图片的尺寸,用来减少内存的占用。
官方文档:
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之后版本才可用
设定最大的缓存宽度和高度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(),
),
方法三
从相册选取图片,展示时使用指定尺寸宽高进行处理。
使用三方库:
# 仿微信资源选择器
wechat_assets_picker: ^4.2.0
# 仿微信拍照
wechat_camera_picker: ^1.2.1
使用自定义provider
来指定所需图片的宽高:
/// The item builder for images and video type of asset.
/// 图片和视频资源的部件构建
/// 缩略图视图
static Widget thumbImageItemBuilder(
BuildContext context,
AssetEntity asset, // 图片资源数据
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
数据。
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);
}
进入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,
);
}
进入_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,
);
}
进入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,
});
}
调用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];
}
进入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"];
}
}
原生实现获取置顶宽高缩略图方法实现:
使用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];
}];
}