Flutter与Swift平台通道:如何用Swift的View替代UIView显示?
问题描述
我通过Flutter Platform Channel和Swift实现原生视图显示,但遇到一个核心问题:Flutter要求视图必须是UIView类型,而我的Swift代码返回的是SwiftUI的View类型。目前我用UIHostingController做转换,虽然能运行,但视图周围出现大黑框,而且这种实现方式感觉不够规范,想咨询有没有其他替代方案。
当前实现代码
FluffViewFactory
// factory that returns FluffView public class FluffViewFactory : NSObject, FlutterPlatformViewFactory { public func create( withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any? ) -> FlutterPlatformView { return FluffView(frame, viewId: viewId, args: args) } }
FluffView
// the view public class FluffView: NSObject, FlutterPlatformView { let frame: CGRect let viewId: Int64 init(_ frame: CGRect, viewId: Int64, args: Any?) { self.frame = frame self.viewId = viewId } let context: DeviceActivityReport.Context = .totalActivity let filter = DeviceActivityFilter( segment:.daily( during: DateInterval( start: Date().addingTimeInterval(-24 * 3600), end: Date() ) ) ) // converts View into UIView for Flutter public func view() -> UIView { var child = UIHostingController(rootView: ContentView()) var parent = UIViewController() child.view.translatesAutoresizingMaskIntoConstraints = false child.view.frame = parent.view.bounds NSLayoutConstraint.activate([ child.view.topAnchor.constraint(equalTo: parent.view.topAnchor), child.view.leadingAnchor.constraint(equalTo: parent.view.leadingAnchor), child.view.bottomAnchor.constraint(equalTo: parent.view.bottomAnchor), child.view.trailingAnchor.constraint(equalTo: parent.view.trailingAnchor) ]) // First, add the view of the child to the view of the parent parent.view.addSubview(child.view) // TODO: set background color here // parent.view.backgroundColor = BackgroundStyle() // Then, add the child to the parent parent.addChild(child) return parent.view } }
AppDelegate
@UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController @State var context: DeviceActivityReport.Context = .totalActivity @State var filter = DeviceActivityFilter(segment: .daily(during: thisWeek)) // calls and registers the fluffview that will handle the conversion let viewFactory = FluffViewFactory() registrar(forPlugin: "Kitty")?.register(viewFactory, withId: "FluffView") GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }
解决方案
1. 简化UIHostingController使用,移除冗余父ViewController
不需要额外创建父ViewController,直接返回UIHostingController的view即可,同时设置背景色透明解决大黑框问题:
public func view() -> UIView { let hostingController = UIHostingController(rootView: ContentView()) // 设置背景透明,消除大黑框 hostingController.view.backgroundColor = .clear // 应用Flutter传递的frame hostingController.view.frame = self.frame // 禁用自动调整mask,避免布局冲突 hostingController.view.translatesAutoresizingMaskIntoConstraints = false return hostingController.view }
2. 修正AppDelegate中的错误
@State是SwiftUI专属属性,不能在UIKit的AppDelegate中使用,需要移除这部分代码:
@UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController // 移除错误的@State变量 let viewFactory = FluffViewFactory() registrar(forPlugin: "Kitty")?.register(viewFactory, withId: "FluffView") GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }
3. 更规范的布局适配
如果需要更灵活的布局,可以让UIHostingController的view自动适配Flutter的布局约束,无需手动设置frame:
public func view() -> UIView { let hostingController = UIHostingController(rootView: ContentView()) hostingController.view.backgroundColor = .clear hostingController.view.translatesAutoresizingMaskIntoConstraints = false // 让view填充Flutter提供的frame范围 hostingController.view.widthAnchor.constraint(equalToConstant: frame.width).isActive = true hostingController.view.heightAnchor.constraint(equalToConstant: frame.height).isActive = true return hostingController.view }
核心总结
- 大黑框的根源是UIHostingController或父ViewController的默认背景色为黑色,设置为透明即可解决
- 无需额外创建父ViewController,直接返回UIHostingController的view更简洁规范
- 禁止在UIKit类中使用SwiftUI的
@State属性,属于错误用法
内容的提问来源于stack exchange,提问作者Tejas Sharma
相关产品推荐
相关产品推荐

