在 Flutter 應用中使用整合平臺視圖託管您的原生 iOS 檢視
整合平臺視圖 (後稱為平臺視圖) 允許將原生檢視嵌入到 Flutter 應用中,所以您可以透過 Dart 將變換、裁剪和不透明度等效果應用到原生檢視。
例如,這使您可以透過使用平臺視圖直接在 Flutter 應用內部使用 Android 和 iOS SDK 中的 Google Maps。
iOS 只支援混合整合模式,這意味著原生的 UIView
會被加入檢視層級中。
要在 iOS 中建立平臺視圖,需要如下步驟:
在 Dart 端
在 Dart 端,建立一個 Widget
並新增如下的實現,具體如下:
在 Dart 檔案中,例如 native_view_example.dart
,請執行下列操作:
-
新增如下匯入程式碼:
import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart';
-
實現
build()
方法: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>{}; 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)
}
}
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
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
weak var registrar = self.registrar(forPlugin: "plugin-name")
let factory = FLNativeViewFactory(messenger: registrar!.messenger())
self.registrar(forPlugin: "<plugin-name>")!.register(
factory,
withId: "<platform-view-type>")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
要在外掛中進行註冊,修改外掛的主類
(例如 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>")
}
}
在工廠類和平臺視圖的檔案頭部新增以下內容。用 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];
}
@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
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
NSObject<FlutterPluginRegistrar>* registrar =
[self registrarForPlugin:@"plugin-name"];
FLNativeViewFactory* factory =
[[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
[[self registrarForPlugin:@"<plugin-name>"] registerViewFactory:factory
withId:@"<platform-view-type>"];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@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:
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.
default:
throw UnsupportedError('Unsupported platform view');
}
}
效能
在 Flutter 中使用平臺視圖時,效能會有所取捨。
例如,在典型的 Flutter 應用中,Flutter 的 UI 是專門在 raster 執行緒上合成的。由於平台的主執行緒很少被阻塞,因此 Flutter 應用程式可以快速執行。
使用混合整合模式渲染平臺視圖時, Flutter UI 由平台執行緒完成,與其他執行緒一起競爭,例如:處理系統或外掛訊息等任務。
在 Android 10 之前,混合整合模式將每個 Flutter 幀從視訊記憶體中複製到主記憶體中,然後再將其複製回 GPU 紋理中。在 Android 10 或更高版本中,視訊記憶體會被複制兩次。由於每幀都會進行一次複製,因此可能會影響整個 Flutter UI 的效能。
另一方面,虛擬顯示模式使平臺視圖的每個畫素流經附加的中間圖形緩衝區,這會浪費視訊記憶體和繪圖效能。
對於複雜的情況,可以使用一些技巧來緩解這些問題。
例如,當 Dart 中發生動畫時,您可以使用佔位符紋理。換句話說,如果在渲染平臺視圖時動畫很慢,請考慮對原生檢視進行截圖,並將其渲染為紋理。
更多資訊,請檢視下面連結: