Skip to main content

使用平台视图在Flutter应用程序中托管原生iOS视图

平台视图允许您在Flutter应用程序中嵌入原生视图,以便您可以从Dart应用变换、剪裁和不透明度到原生视图。

例如,这允许您直接在Flutter应用程序中使用Android和iOS SDK中的原生Google地图。

iOS仅使用混合合成,这意味着原生UIView附加到视图层次结构。

要在iOS上创建平台视图,请使用以下说明:

Dart端

#

在Dart端,创建一个Widget并添加构建实现,如下所示。

在Dart widget文件中,进行类似于native_view_example.dart中所示的更改:

  1. 添加以下导入:

    dart
    import 'package:flutter/foundation.dart';
    import 'package:flutter/services.dart';
  2. 实现build()方法:

    dart
    Widget build(BuildContext context) {
      // 这在平台端用于注册视图。
      const String viewType = '<platform-view-type>';
      // 将参数传递到平台端。
      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

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视图可以在这里创建
        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

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)

        guard let pluginRegistrar = self.registrar(forPlugin: "plugin-name") else { return false }

        let factory = FLNativeViewFactory(messenger: pluginRegistrar.messenger())
        pluginRegistrar.register(
            factory,
            withId: "<platform-view-type>")
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

对于插件注册,修改插件的主文件(例如,FLPlugin.swift):

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所示:

objc
#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

objc
#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

objc
#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):

objc
#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:

dart
Widget build(BuildContext context) {
  // 这在平台端用于注册视图。
  const String viewType = '<platform-view-type>';
  // 将参数传递到平台端。
  final Map<String, dynamic> creationParams = <String, dynamic>{};

  switch (defaultTargetPlatform) {
    case TargetPlatform.android:
    // 在Android上返回widget。
    case TargetPlatform.iOS:
    // 在iOS上返回widget。
    case TargetPlatform.macOS:
    // 在macOS上返回widget。
    default:
      throw UnsupportedError('不支持的平台视图');
  }
}

性能

#

Flutter中的平台视图会带来性能权衡。

对于复杂的情况,可以使用一些技术来减轻性能问题。

例如,您可以在Dart中发生动画时使用占位符纹理。换句话说,如果在渲染平台视图时动画缓慢,则考虑截取原生视图的屏幕截图并将其渲染为纹理。

合成限制

#

组合iOS平台视图时存在一些限制。