透過平臺檢視在 Flutter 應用中託管原生 iOS 檢視
瞭解如何透過平臺檢視在 Flutter 應用中託管原生 iOS 檢視。
平臺檢視允許你在 Flutter 應用中嵌入原生檢視,這樣你就可以從 Dart 應用轉換、裁剪和調整原生檢視的不透明度。
例如,這允許您直接在 Flutter 應用中使用 Android 和 iOS SDK 提供的原生 Google 地圖。
iOS 僅使用混合組合(Hybrid composition),這意味著原生 UIView 會被附加到檢視層級中。
若要在 iOS 上建立平臺檢視,請按照以下說明操作:
在 Dart 側
#在 Dart 端,建立一個 Widget 並新增構建實現,如下面的步驟所示。
在 Dart 元件檔案中,進行類似於 native_view_example.dart 中所示的更改。
新增以下匯入:
dartimport 'package:flutter/foundation.dart'; import 'package:flutter/services.dart';實現
build()方法dartWidget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = '<platform-view-type>'; // Pass parameters to the platform side. final Map<String, dynamic> creationParams = <String, dynamic>{}; return UiKitView( viewType: viewType, layoutDirection: TextDirection.ltr, creationParams: creationParams, creationParamsCodec: const StandardMessageCodec(), ); }
欲瞭解更多資訊,請參閱 API 文件:UIKitView。
在平臺側
#在平臺端,請使用 Swift 或 Objective-C
實現工廠類和平臺檢視。FLNativeViewFactory 用於建立平臺檢視,而平臺檢視提供對 UIView 的引用。例如,參考 FLNativeView.swift
import Flutter
import UIKit
class FLNativeViewFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger
init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(
withFrame frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?
) -> FlutterPlatformView {
return FLNativeView(
frame: frame,
viewIdentifier: viewId,
arguments: args,
binaryMessenger: messenger)
}
/// Implementing this method is only necessary when the `arguments` in `createWithFrame` is not `nil`.
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
class FLNativeView: NSObject, FlutterPlatformView {
private var _view: UIView
init(
frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?,
binaryMessenger messenger: FlutterBinaryMessenger?
) {
_view = UIView()
super.init()
// iOS views can be created here
createNativeView(view: _view)
}
func view() -> UIView {
return _view
}
func createNativeView(view _view: UIView){
_view.backgroundColor = UIColor.blue
let nativeLabel = UILabel()
nativeLabel.text = "Native text from iOS"
nativeLabel.textColor = UIColor.white
nativeLabel.textAlignment = .center
nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
_view.addSubview(nativeLabel)
}
}
最後,註冊平臺檢視。這可以在應用或外掛中完成。
對於應用註冊,請修改應用的 AppDelegate.swift
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
guard let pluginRegistrar = engineBridge.pluginRegistry.registrar(forPlugin: "plugin-name") else { return }
let factory = FLNativeViewFactory(messenger: pluginRegistrar.messenger())
pluginRegistrar.register(
factory,
withId: "<platform-view-type>")
}
}
對於外掛註冊,請修改外掛的主檔案(例如 FLPlugin.swift)
import Flutter
import UIKit
class FLPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let factory = FLNativeViewFactory(messenger: registrar.messenger())
registrar.register(factory, withId: "<platform-view-type>")
}
}
在 Objective-C 中,為工廠類和平臺檢視新增標頭檔案。例如,如 FLNativeView.h 中所示
#import <Flutter/Flutter.h>
@interface FLNativeViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
@interface FLNativeView : NSObject <FlutterPlatformView>
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
- (UIView*)view;
@end
實現工廠類和平臺檢視。FLNativeViewFactory 用於建立平臺檢視,而平臺檢視提供對 UIView 的引用。例如,參考 FLNativeView.m
#import "FLNativeView.h"
@implementation FLNativeViewFactory {
NSObject<FlutterBinaryMessenger>* _messenger;
}
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
self = [super init];
if (self) {
_messenger = messenger;
}
return self;
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args {
return [[FLNativeView alloc] initWithFrame:frame
viewIdentifier:viewId
arguments:args
binaryMessenger:_messenger];
}
/// Implementing this method is only necessary when the `arguments` in `createWithFrame` is not `nil`.
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
return [FlutterStandardMessageCodec sharedInstance];
}
@end
@implementation FLNativeView {
UIView *_view;
}
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
if (self = [super init]) {
_view = [[UIView alloc] init];
}
return self;
}
- (UIView*)view {
return _view;
}
@end
最後,註冊平臺檢視。這可以在應用或外掛中完成。
對於應用註冊,請修改應用的 AppDelegate.m
#import "AppDelegate.h"
#import "FLNativeView.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (void)didInitializeImplicitFlutterEngine:(NSObject<FlutterImplicitEngineBridge>*)engineBridge {
[GeneratedPluginRegistrant registerWithRegistry:engineBridge.pluginRegistry];
NSObject<FlutterPluginRegistrar>* registrar =
[engineBridge.pluginRegistry registrarForPlugin:@"plugin-name"];
FLNativeViewFactory* factory =
[[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
[registrar registerViewFactory:factory withId:@"<platform-view-type>"];
}
@end
對於外掛註冊,請修改主外掛檔案(例如 FLPlugin.m)
#import <Flutter/Flutter.h>
#import "FLNativeView.h"
@interface FLPlugin : NSObject<FlutterPlugin>
@end
@implementation FLPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FLNativeViewFactory* factory =
[[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
[registrar registerViewFactory:factory withId:@"<platform-view-type>"];
}
@end
欲瞭解更多資訊,請參閱以下 API 文件:
整合起來
#在 Dart 中實現 build() 方法時,可以使用 defaultTargetPlatform 來檢測平臺,並決定使用哪個元件。
Widget build(BuildContext context) {
// This is used in the platform side to register the view.
const String viewType = '<platform-view-type>';
// Pass parameters to the platform side.
final Map<String, dynamic> creationParams = <String, dynamic>{};
switch (defaultTargetPlatform) {
case TargetPlatform.android:
// return widget on Android.
case TargetPlatform.iOS:
// return widget on iOS.
case TargetPlatform.macOS:
// return widget on macOS.
default:
throw UnsupportedError('Unsupported platform view');
}
}
效能
#Flutter 中的平臺檢視會帶來效能上的權衡。
針對複雜情況,可以使用一些技術來緩解效能問題。
例如,當 Dart 發生動畫時,可以使用佔位紋理。換句話說,如果平臺檢視渲染導致動畫卡頓,可以考慮擷取原生檢視的螢幕截圖並將其作為紋理進行渲染。
組合限制
#組合 iOS 平臺檢視時存在一些限制。
- 不支援
ShaderMask和ColorFiltered元件。 BackdropFilter元件受支援,但在使用方式上存在一些限制。有關詳細資訊,請檢視 iOS 平臺檢視 Backdrop Filter 模糊設計文件。