Flutter调用原生图片资源
Posted Ever69
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter调用原生图片资源相关的知识,希望对你有一定的参考价值。
在Flutter与原生的混合开发中,经常遇到Flutter与原生都需要使用同一份图片的情况,并且由于原生是主导,图片资源都在原生这侧。
那么,Flutter可不可以直接使用原生的图片资源呢?
——答案是不可以的,Flutter并不能直接访问原生侧的图片资源,官方没有提供这样的API供我们使用,并且官方文档中页说明了不支持。
请注意,在 Flutter 1.0 beta 2 之前,Flutter 中定义的资源无法从本机端访问,反之亦然,Flutter 无法使用本机中的资源,因为它们位于不同的文件夹中。
从 Flutter beta 2 开始,Flutter资源存储在本机资源文件夹中,并使用 android 的本机端访问AssetManager:
val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png")
截止到 Flutter beta 2,Flutter 仍然无法访问原生资源,也无法访问原生资产。
简单讲就是,在Flutter 1.0 beta 2 之前,Flutter和原生都不能互相访问对方的资源,从 Flutter beta 2 之后,原生可以访问Flutter中的资源,但是Flutter还是不能访问原生中的资源。
那么,在Flutter侧再放一份图片资源呢?虽然可以这么做,但这样显然是不合理的,除了要维护两套资源文件外,安装包的大小也会增加,尤其是那种有很多图片资源的App。
所以,为了避免两份同样图片资源的存在,我们只能想办法让Flutter使用原生侧的图片资源,那么,到底怎么做呢?
虽然Flutter不能直接使用原生的图片资源,但是我们可以曲线救国嘛,直接不可以,那就间接咯~
Flutter中图片的加载方式
曲线救国前,先了解一下,在Flutter中,负责图片展示的小部Image有四种图片加载方式
- Image.assest,用于从本地资源集合获取图像。
- Image.network ,用于从 URL 获取图像。
- Image.memory,用于从字节数组获取图像。
- Image.file,用于从文件获取图像。
通过流的形式加载原生的图片资源
既然Flutter中的Image可以通过字节数组的形式加载图片,那么,我们是不是可以将原生中的图片转成字节数组,返回给Flutter进行图片加载呢?我觉得没毛病。
使用MethodChannel定义一个通信方法,向原生获取图片的字节数组。
Flutter侧代码
//字节数组
Uint8List _imageBytes = Uint8List.fromList([]);
//用于展示的小部件
RaisedButton(
child: Text("通过流的形式调用原生图片"),
onPressed: ()
_getImageAsBytes("ic_launcher");
,
),
Image.memory(_imageBytes)
//获取图片字节数组的方法
Future<void> _getImageAsBytes(String imageName) async
Uint8List bytes =
await platform.invokeMethod("imageAsBytes", 'name': '$imageName');
setState(()
_imageBytes = bytes;
);
原生侧代码
Android
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "samples.flutter.dev/battery")
.setMethodCallHandler call, result ->
when (call.method)
"imageAsBytes" ->
if (call.hasArgument("name"))
val path = call.argument<String>("name")?.let getImageAsBytes(it)
if (path == null)
result.error("-1", "调用原生图片失败", null)
else
result.success(path)
private fun getImageAsBytes(imageName: String): ByteArray?
var imageId = resources.getIdentifier(imageName, "mipmap", packageName)
if (imageId == 0)
imageId = resources.getIdentifier(imageName, "drawable", packageName)
if (imageId == 0)
return null
val imageBitmap = BitmapFactory.decodeResource(resources, imageId)
val bos = ByteArrayOutputStream()
imageBitmap.compress(Bitmap.CompressFormat.PNG,100,bos)
return bos.toByteArray()
ios
略。。
通过文件的形式加载原生的图片资源
Flutter中的Image小部件可以通过文件的形式加载图片,我们大可以将原生中的图片以文件的形式保存在本地,再将文件的路径告知Flutter去加载,这样就可以间接的使用原生中的图片资源了。
ok,上代码。还是使用MethodChannel进行通信,对Flutter与原生通信不熟悉的朋友可以看这篇博客-Flutte与原生通信
Flutter侧代码
//全局变量,图片文件地址
String _imageFilePath = "";
//小部件
RaisedButton(
child: Text("调用展示原生图片资源"),
onPressed: ()
_getImageAsFile("ic_launcher");
,
),
Image.file(File(_imageFilePath))
//获取图片文件路径的方法
Future<void> _getImageAsFile(String imageName) async
String path = await platform.invokeMethod("image", 'name': '$imageName');
setState(()
_imageFilePath = path;
);
原生侧代码
Android
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "samples.flutter.dev/battery")
.setMethodCallHandler call, result ->
when (call.method)
"imageAsFile" ->
if (call.hasArgument("name"))
val path = call.argument<String>("name")?.let getImageAsFile(it)
if (path.isNullOrEmpty())
result.error("-1", "调用原生图片失败", null)
else
result.success(path)
private fun getImageAsFile(imageName: String): String
var imageFilePath = "$externalCacheDir$File.separator$imageName"
val imageFile = File(imageFilePath)
if (!imageFile.exists())
var imageId = resources.getIdentifier(imageName, "mipmap", packageName)
if (imageId == 0)
imageId = resources.getIdentifier(imageName, "drawable", packageName)
if (imageId == 0)
return ""
val imageBitmap = BitmapFactory.decodeResource(resources, imageId)
val fos = FileOutputStream(imageFile)
val success = imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
if (!success)
imageFile.delete()
return ""
return imageFilePath
Ios
略(滑稽.jpg)
效果如何?
代码写完,读取个原生图片看看效果如何,以Android为例,读取mipmap文件夹下的ic_launcher图片(因为我这是一个Flutter工程,所以ic_launcher是Flutter的logo)。
运行App。
dangdan!Flutter读取原生图片,搞定~
以上是关于Flutter调用原生图片资源的主要内容,如果未能解决你的问题,请参考以下文章
Flutter自定义Widget—可加载原生图片资源的Image
Flutter自定义Widget—可加载原生图片资源的Image