Flutter调用原生图片资源
Posted Ever69
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter调用原生图片资源相关的知识,希望对你有一定的参考价值。
在Flutter与原生的混合开发中,经常遇到Flutter与原生都需要使用同一份图片的情况,并且由于原生是主导,图片资源都在原生这侧。
那么,Flutter可不可以直接使用原生的图片资源呢?——答案是不可以的,Flutter并不能直接访问原生侧的图片资源,官方没有提供这样的API供我们使用。
那么,在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