Flutter入门疑难杂症:获取网络图片,并自适应屏幕宽度(适合文章/帖子详情)
程序员文章站
2022-03-11 18:09:04
...
经常会遇到帖子详情/文章详情,需要动态显示网络图片,并且要求图片宽度自适应屏幕,高度进行等比例缩放,如下图:
实现思路:
1、下载图片;
2、计算宽高比;
3、显示;
话不多说,直接贴代码,跑不通的可以留言。
//放在Column内,构建多张图片
List<Widget> _buildImgList(List<String>imgUrlList) {
List<Widget> returnList = List();
for (int i = 0; i < imgUrlList.length; i++) {
returnList.add(InkWell(
child: Column(children: [
ItemFitWidthNetImage(imgUrlList[i])
]),
onTap: () {
//这里是点击查看大图的,可以替换成各自自己的
MediaUtils.showBigImg(context,imgUrlList, i);
},
));
}
return returnList;
}
///宽度自适应的图片
// ignore: non_constant_identifier_names
Widget ItemFitWidthNetImage(String url, double fitWidth) {
return AsperctRaioImage.network(url, builder: (context, snapshot, url) {
//计算缩放
double scale = snapshot.data.width.toDouble() / fitWidth;
double fitHeight = snapshot.data.height.toDouble() / scale;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: fitWidth,
height: fitHeight,
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(url), fit: BoxFit.cover),
),
)
],
);
});
}
AsperctRaioImage :
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
typedef AsyncImageWidgetBuilder<T> = Widget Function(
BuildContext context, AsyncSnapshot<T> snapshot, String url);
typedef AsyncImageFileWidgetBuilder<T> = Widget Function(
BuildContext context, AsyncSnapshot<T> snapshot, File file);
typedef AsyncImageMemoryWidgetBuilder<T> = Widget Function(
BuildContext context, AsyncSnapshot<T> snapshot, Uint8List bytes);
enum AsperctRaioImageType { NETWORK, FILE, ASSET, MEMORY }
///有宽高的Image
class AsperctRaioImage extends StatelessWidget {
String url;
File file;
Uint8List bytes;
final ImageProvider provider;
AsperctRaioImageType type;
AsyncImageWidgetBuilder<ui.Image> builder;
AsyncImageFileWidgetBuilder<ui.Image> filebBuilder;
AsyncImageMemoryWidgetBuilder<ui.Image> memoryBuilder;
AsperctRaioImage.network(url, {Key key, @required this.builder})
: provider = NetworkImage(url),
type = AsperctRaioImageType.NETWORK,
this.url = url;
AsperctRaioImage.file(
file, {
Key key,
@required this.filebBuilder,
}) : provider = FileImage(file),
type = AsperctRaioImageType.FILE,
this.file = file;
AsperctRaioImage.asset(name, {Key key, @required this.builder})
: provider = AssetImage(name),
type = AsperctRaioImageType.ASSET,
this.url = name;
AsperctRaioImage.memory(bytes, {Key key, @required this.memoryBuilder})
: provider = MemoryImage(bytes),
type = AsperctRaioImageType.MEMORY,
this.bytes = bytes;
@override
Widget build(BuildContext context) {
final ImageConfiguration config = createLocalImageConfiguration(context);
final Completer<ui.Image> completer = Completer<ui.Image>();
final ImageStream stream = provider.resolve(config);
ImageStreamListener listener;
listener = ImageStreamListener(
(ImageInfo image, bool sync) {
completer.complete(image.image);
stream.removeListener(listener);
},
onError: (dynamic exception, StackTrace stackTrace) {
completer.complete();
stream.removeListener(listener);
FlutterError.reportError(FlutterErrorDetails(
context: ErrorDescription('image failed to precache'),
library: 'image resource service',
exception: exception,
stack: stackTrace,
silent: true,
));
},
);
stream.addListener(listener);
return FutureBuilder(
future: completer.future,
builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
if (snapshot.hasData) {
if (type == AsperctRaioImageType.FILE) {
return filebBuilder(context, snapshot, file);
} else if (type == AsperctRaioImageType.MEMORY) {
return memoryBuilder(context, snapshot, bytes);
} else {
return builder(context, snapshot, url);
}
} else {
return Container();
}
});
}
}
参考:https://www.jianshu.com/p/ee62849752e8