Flutter
框架既提供了与原生交互的接口,也支持原生项目嵌入 Flutter
。虽然支持,但是 Flutter
其实不建议在原生项目中嵌入 Flutter
,因为 Flutter
需要渲染引擎的支持,会比较重量级,不像嵌入 Web
页这么轻便。下面以 Flutter
调起原生相册为例,我们介绍一下 Flutter
调起原生的方式。
自己实现 Flutter 调起原生相册
-
Flutter
代码
MethodChannel _methodChannel = MethodChannel('mine_page/method');
File_avatarFile;
void initState() {
super.initState();
_methodChannel.setMethodCallHandler((call) {
if (call.method == 'imagePath') {
setState(() {
//获取图片本地路径并进行截取
String imagePath = call.arguments.toString().substring(7);
_avatarFile = File(imagePath);
});
}
return Future((){});
});
GestureDetector(
onTap: () {
_methodChannel.invokeMapMethod('picture');
},
child: Container(
width: 70,
height: 70,
// 设置圆角属性
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: (_avatarFile == null)
AssetImage('images/ChenXi.JPG') as ImageProvider : FileImage(_avatarFile ?File('')),
)
),
),
),
-
iOS
代码实现
@interface AppDelegate () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
/// methodChannel
@property (nonatomic, strong, nullable) FlutterMethodChannel *methodChannel;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
FlutterViewController *vc = (FlutterViewController *)self.window.rootViewController;
self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"mine_page/method" binaryMessenger:vc];
UIImagePickerController *pickerVc = [[UIImagePickerController alloc] init];
pickerVc.delegate = self;
[self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([call.method isEqualToString:@"picture"]) {
[vc presentViewController:pickerVc animated:YES completion:nil];
}
}];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
[picker dismissViewControllerAnimated:YES completion:^{
NSString *imagePath = [NSString stringWithFormat:@"%@",info[@"UIImagePickerControllerImageURL"]];
[self.methodChannel invokeMethod:@"imagePath" arguments:imagePath];
}];
}
当我们想用 Flutter
调起原生相册,并且更换头像的话我们需要经过以下几个步骤:
-
Flutter
与原生交互的时候借助一个类MethodChannel
,所以Flutter
代码中首先我们定义了一个变量_methodChannel
,并传入字符串mine_page/method
,就是一个标识 - 为头像添加点击实现,并调用
_methodChannel
的invokeMapMethod
方法,传入picture
,picture
就是作为打开相册的标识,可以我们自己随意定义。 - 同样在
oc
代码中我们也要定义一个FlutterMethodChannel
类型的属性methodChannel
,调用methodChannelWithName
方法创建methodChannel
对象,传入的第一个参数要与Flutter
中的字符保持一致,第二个参数我们传的是window
的根控制器。 - 实现
setMethodCallHandler
方法,当Flutter
中头像点击事件执行的时候就会调用setMethodCallHandler
中的回调,这里我们判断call.method
是否为picture
。 - 在
block
中调起UIImagePickerController
,并把pickerVc
的代理设置为self
。 - 实现选中图片的代理方法,并在代理方法中执行
[self.methodChannel invokeMethod:@"imagePath" arguments:imagePath]
,这里imagePath
为图片的本地路径。这里原生也是调用invokeMethod
方法与Flutter
进行通讯。 - 在
Flutter
代码中实现setMethodCallHandler
方法,当第 6 步执行完后就会执行闭包,在这里可以获取到图片的路径,把路径传给File
类,创建变量_avatarFile
。最后调用setState
方法,刷新页面。 - 头像部件中
image
属性进行判断,当_avatarFile
有值的时候就显示本地相册选中图片,否则就使用默认图片。
使用三方组件实现调起相册功能
Flutter
官方为我们提供了一个三方组件 image_picker 来实现调起相册的功能,这里我们用 image_picker
来实现一下。
// 头像
GestureDetector(
onTap: () {
_pickImage();
},
void _pickImage() async {
try {
XFilefile = await ImagePicker().pickImage(source: ImageSource.gallery);
setState(() {
_avatarFile = File(file?.path ?'');
});
}catch (e) {
print(e.toString());
setState(() {
_avatarFile = null;
});
}
}
使用三方组件的话我们只需要实现 _pickImage
方法中的这些代码就可以实现相册选择的功能,而且原生工程不需要改代码,但是需要注意的是 iOS
原生项目需要配置 info.plist
中的相册权限。使用三方库的好处就是运行项目的时候会先执行 pod install
,把原生相关的代码给下载到工程,三方库中不光有 dart
代码,而且也有原生相关的代码。