一、类型认识:
- assets资源(例如图片)转成ByteData ==》 例如:rootBundle.load(asset);可以由AssetBundle对象返回
- ByteData转成uint8List ==》 ByteDataObj.buffer.asUint8List()
- uint8list对象 转成 codec对象 ==》 instantiateimageCodec()
- codec对象 返回 FrameInfo ==》 Codec.getNextFrame()
- FrameInfo 对象 返回 ui.Image ==》 FrameInfo.image
二、AssetBundle 获取资源的类
继承AssetBundle 的类
- rootBundle.load("本地资源路径")
- NetworkAssetBundle(Uri.parse("网络资源路径")).load("网络资源路径");
- DefaultAssetBundle.of(context).load("本地资源路径");//只能在build中实用,因为需要传入context
返回的Future处理
//返回Codec句柄
ui.Codec codec = await ui.instantiateImageCodec(ByteData.buffer.asUint8List());
//获取一帧图片FrameInfo
ui.FrameInfo fi = await codec.getNextFrame();
//获取ui.Image
ui.Image image = fi.image;
显示ui.Image对象
-
使用canvas类显示(不推荐)
import 'dart:async'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class LALPageNews extends StatefulWidget { @override _LALPageNewsState createState() => _LALPageNewsState(); } class _LALPageNewsState extends State<LALPageNews> { Uint8List imageMemory;//先定义一个uint8list对象 @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: <Widget>[ //点击按钮,点击后显示 RaisedButton( onPressed:() async{ ui.PictureRecorder pictureRecorder = new ui.PictureRecorder(); // 图片记录仪 Canvas canvas = new Canvas(pictureRecorder); //canvas接受一个图片记录仪 //第一个ui.image对象 给canvas.drawimage使用 ui.Image images = await getAssetImage('assets/images/time.jpg'); // 使用方法获取ui.Image格式的图片 Paint _linePaint = new Paint() ..color = Colors.blue ..style = PaintingStyle.fill ..isAntiAlias = true//抗锯齿 ..strokeCap = StrokeCap.round//线条末端的处理方式 ..strokeWidth =20.0; // 绘制图片 canvas.drawImage(images, Offset(0, 0), _linePaint); // 直接画图 //第二个 ui.Image对象 由pictureRecorder结束记录后返回 toImage裁剪图片 ui.Image picture = await pictureRecorder.endRecording().toImage(MediaQuery.of(500, 1334);//设置生成图片的宽和高 //ByteData对象 转成 Uint8List对象 给 Image.memory() 使用来显示 ByteData pngImageBytes = await picture.toByteData(format: ui.ImageByteFormat.png); //Uint8List imgBytes = Uint8List.view(pngImageBytes.buffer); //这一行和下面这一行都是生成Uint8List格式的图片 Uint8List pngBytes = pngImageBytes.buffer.asUint8List(); setState(() { imageMemory = pngBytes; }); }, child: Text("生成图片"), ), imageMemory != null ? Image.memory(imageMemory) : Text('loading...'), ], ), ); } } //返回ui.Image Future<ui.Image> getAssetImage(String asset,{width,height}) async { ByteData data = await rootBundle.load(asset); ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height); ui.FrameInfo fi = await codec.getNextFrame(); return fi.image; }
备注:使用canvas对象,要传入一个pictureRecorder对象,pictureRecorder.endRecording()是绘画具体canvas图片的最后一步。
-
使用CustomPaint与CustomPainter widget显示(推荐)
import 'dart:async'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; //方法1:获取网络图片 返回ui.Image Future<ui.Image> getNetImage(String url,{width,height}) async { ByteData data = await NetworkAssetBundle(Uri.parse(url)).load(url); ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height); ui.FrameInfo fi = await codec.getNextFrame(); return fi.image; } //方法2.1:获取本地图片 返回ui.Image 需要传入BuildContext context Future<ui.Image> getAssetImage2(String asset,BuildContext context,{width,height}) async { ByteData data = await DefaultAssetBundle.of(context).load(asset); ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height); ui.FrameInfo fi = await codec.getNextFrame(); return fi.image; } //方法2.2:获取本地图片 返回ui.Image 不需要传入BuildContext context Future<ui.Image> getAssetImage(String asset,{width,height}) async { ByteData data = await rootBundle.load(asset); ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height); ui.FrameInfo fi = await codec.getNextFrame(); return fi.image; } //方法3:通过stream类型来获取ui.Image 待更新 //自定义CustomPainter(CustomPainter内不能使用异步,所有ui.Image通过实例化传入) //该widget做为CustomPaint的painter(在画布后面显示)或者foregroundPainter(在画布前面显示)参数。 class SelfForePainter extends CustomPainter{ ui.Image _imageFrame; SelfForePainter(this._imageFrame):super(); @override void paint(Canvas canvas, Size size){ Paint selfPaint = Paint() ..color = Colors.blue ..style = PaintingStyle.fill ..isAntiAlias = true ..strokeCap = StrokeCap.butt ..strokeWidth = 30.0; canvas.drawImage(_imageFrame, Offset(0,0), selfPaint); } @override bool shouldRepaint(CustomPainter oldDelegate) { return true; } } //在widget中显示 class LALPageNews extends StatefulWidget { @override _LALPageNewsState createState() => _LALPageNewsState(); } class _LALPageNewsState extends State<LALPageNews> { ui.Image _assetImageFrame;//本地图片 ui.Image _netImageFrame;//网络图片 @override void initState() { super.initState(); _getAssetImage(); _getNetImage(); } //获取本地图片 _getAssetImage() async{ ui.Image imageFrame = await getAssetImage('assets/images/time.jpg',width: 200,height: 200); setState(() { _assetImageFrame = imageFrame; }); } //获取网络图片 _getNetImage() async{ ui.Image imageFrame = await getNetImage('https://img.zcool.cn/community/0145f155452efa0000019ae95ef0e4.jpg@1280w_1l_2o_100sh.jpg',width: 200); setState(() { _netImageFrame = imageFrame; }); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: <Widget>[ CustomPaint( foregroundPainter:SelfForePainter(_assetImageFrame),//画在child前面 child: Container( width: double.infinity.toInt(), height: 300, color: Color.fromRGBO(155, 155, 155, 1), ), ), CustomPaint( size: Size.fromWidth(double.infinity), foregroundPainter:SelfForePainter(_netImageFrame),//画在child前面 child: Container( width: double.infinity, height: 300, color: Color.fromRGBO(155, 155, 155, 0.1), ), ), ], ), ); } }
备注:Custompaint作为widget来显示继承自CustomPainter的自定义类的Canvas,这种方法无需实例化Canvas和PictureRecorder,所以先对于上一种方案,更简单一些。
-
总结:静态资源路径或网络图片路径 可以转成ByteData类型;
-
ByteDataObj.buffer.asUint8List() 转成 uint8List类型,这种类型 可以由 Image.memroy(uint8ListObj)直接转成图片显示(一般图片转成ByteData不会直接用Image.memroy显示,因为转成ByteData,就是为了更多的操作来修改图片,不然直接使用以下方法更直接。
Image.asset(name)//显示本地图片 Image.network(src)//显示网络图片
-
ByteData ByteDataObj; //句柄(我的理解是,绘画一系列图片的对象,比如gif就是一系列图片的集合) ui.Codec codec = await ui.instantiateImageCodec(ByteDataObj.buffer.asUint8List(),targetWidth: width,targetHeight: height); //一帧数据 ui.FrameInfo fi = await codec.getNextFrame(); //帧数据变成ui.Image ui.Image image = fi.image;//ByteDataObj 对象可以转成 ui.image给CanvasObj.drawImage()作为参数 //Canvas()需要PictureRecorder()来记录绘画动作,Canvas对象有可以绘画各种形状的方法;CanvasObj.drawImage()方法需要传入ui.Image【ui.Image与material中的Image不是一种widget】 //CanvasObj其他draw方法就可以在图片上绘制其他形图案或者修改图片