什么是 platform view?
由于 Flutter 诞生于 Android 、iOS 非常成熟的时代背景,为了能让一些现有的 native 控件直接引用到 Flutter app 中,Flutter 团队提供了 AndroidView 、UIKitView 两个 widget 来满足需求,比如说 Flutter 中的 Webview、MapView,暂时无需使用 Flutter 重新开发一套。
其实 platform view 就是 AndroidView 和 UIKitView 的总称,允许将 native view 嵌入到了 flutter widget 体系中,完成 Datr 代码对 native view 的控制。
简单使用
此处仅是简单使用,有很多不合理的代码,目的仅是让初学者能完成展示,后面会有具体的 framework 代码分析,及官方维护的 platform view 的分析。
先看一下效果吧
存在与 native 交互的代码,建议用一个 plugin 来实现内部逻辑。
Plugin: exposing an Android or iOS API for developers
Flutter 侧
创建 Flutter plugin (建议使用 Android Studio),如果使用命令行,可以执行如下命令:
flutter create --org net.loosash --template = plugin share_platform_plugin
接下来在我们的插件工程里创建一个 widget 用来包裹 platform view。便于使用
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
/// 这里使用了 statelessWidget
class PlatformTextWidget extends StatelessWidget {
PlatformTextWidget({
this.text});
final String text;
@override
Widget build(BuildContext context) {
// 根据运行平台判断执行代码
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView(
// 在 native 中的唯一标识符,需要与 native 侧的值相同
viewType: "platform_text_view",
// 在创建 AndroidView 的同时,可以传递参数
creationParams: <String, dynamic>{
"text": text},
// 用来编码 creationParams 的形式,可选 [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]
// 如果存在 creationParams,则该值不能为null
creationParamsCodec: const StandardMessageCodec(),
);
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return UiKitView(
viewType: "platform_text_view",
creationParams: <String, dynamic>{
"text": text},
creationParamsCodec: const StandardMessageCodec(),
);
} else {
return Text("不支持的平台");
}
}
}
iOS 侧
在编辑Xcode中的iOS平台代码之前,首先确保代码至少已构建过一次。在创建的 plugin/example 目录下执行 build,如下:
cd share_platform_plugin/example
flutter build ios --no-codesign
或者执行 pod install
然后使用 Xcode 打开 share_platform_plugin/example/ios/Runner.xcworkspace,plugin 相关的代码目录很深,在 Pods/Development Pods/share_platform_plugin 内部,具体找到 SharePlatformPlugin.h 与 SharePlatformPlugin.m 目录即位我们操作的目录。
接下来我们先创建需要展示的 View ,这里仅以一个 UILabel 为例。
IOSTextView.h
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface IOSTextView : NSObject<FlutterPlatformView>
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
NS_ASSUME_NONNULL_END
IOSTextView.m
#import <Foundation/Foundation.h>
#import "IOSTextView.h"
@implementation IOSTextView{
int64_t _viewId;
FlutterMethodChannel* _channel;
UILabel * _uiLabel;
}
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args binaryMessenger:(NSObject<FlutterBinaryMessenger> *)messenger{
NSString *text = @"iOS端UILabel";
if ([args isKindOfClass:[NSDictionary class]]) {
NSDictionary *params = (NSDictionary *)args;
if([[params allKeys] containsObject:@"text"]){
if ([[params valueForKey:@"text"] isKindOfClass:[NSString class]]) {
text= [params valueForKey:@"text"];
}
}
}
_uiLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_uiLabel.textAlignment = NSTextAlignmentCenter;
_uiLabel.text = text;
_uiLabel.font = [UIFont systemFontOfSize:30];
return self;
}
-(UIView *)view{
return _uiLabel;
}
@end
然后创建 FlutterPlatformViewFactory
SharePlatformViewFactory.h
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface SharePlatformViewFactory : NSObject<FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messager;
-(NSObject<FlutterMessageCodec> *)createArgsCodec;
-(NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args;
@end
NS_ASSUME_NONNULL_END
SharePlatformViewFactory.m
#import "SharePlatformViewFactory.h"
#import "IOSTextView.h"
@implementation SharePlatformViewFactory{
NSObject<FlutterBinaryMessenger>*_messenger;
}
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger> *)messager{
self = [super init];
if (self) {
_messenger = messager;
}
return self;
}
-(NSObject<FlutterMessageCodec> *)createArgsCodec{
return [FlutterStandardMessageCodec sharedInstance];
}
-(NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args{
IOSTextView *iosTextView = [[IOSTextView alloc] initWithFrame:fra