用于 Flutter 的 iOS UITextView
目前 Flutter 没有 TextView,所以我们必须有一个从 iOS 和 Android 到 Flutter 项目的注入原生 TextView。
平台视图和平台通道
- 这是 Flutter 的一个 API,用于从原生视图创建小部件!
- 以及Dart和iOS / Android与每个订单的通信方式
执行
在 Flutter 项目中
在 Flutter 端创建一个 Widget 调用 TextView
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
typedef void TextViewCreatedCallback(TextViewController controller);
class TextView extends StatefulWidget {
const TextView({
Key key,
this.onTextViewCreated,
}) : super(key: key);
final TextViewCreatedCallback onTextViewCreated;
@override
State<StatefulWidget> createState() => _TextViewState();
}
class _TextViewState extends State<TextView> {
@override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
// The native TextView from AndroidView
}
if (defaultTargetPlatform == TargetPlatform.iOS) {
// viewType `FlutterUITextView` should be matched when register in iOS side
return UiKitView(
viewType: 'FlutterUITextView',
onPlatformViewCreated: _onPlatformViewCreated,
);
}
return Text('$defaultTargetPlatform is not yet supported by the text_view plugin');
}
void _onPlatformViewCreated(int id) {
if (widget.onTextViewCreated == null) {
return;
}
widget.onTextViewCreated(new TextViewController._(id));
}
}
class TextViewController {
// Open a channel with name is `com.my_app.channel.textview_$id`
// Make sure the iOS/Android observe on same the name of this channel
TextViewController._(int id) : _channel = new MethodChannel('com.my_app.channel.textview_$id');
final MethodChannel _channel;
// Tell the iOS/Android to set the html text to the UITextView (iOS), TextView (Kotlin)
Future<void> setHtmlText({String text}) async {
assert(text != null);
Map<String, dynamic> arguments = {
'text': text,
};
return _channel.invokeMethod('setHtmlText', arguments);
}
}
我们也可以有更多的方法setHtmlText
来从本地端为 TextView 设置更多的数据
来自 Flutter 的调用者
TextView(onTextViewCreated: (TextViewController controller) {
controller.setHtmlText(text: "<html><body>Hello World</body></html>");
})
在 iOS 项目中
设置预览
打开Info.plist,添加 keyio.flutter.embedded_views_preview
和 value 是true
为了让 Flutter 在 UIView 上预览。
<key>io.flutter.embedded_views_preview</key>
<true/>
创建与 FlutterPlatformView 兼容的 TextView
public class FlutterUITextView: NSObject, FlutterPlatformView {
let frame: CGRect
let viewId: Int64
let arguments: Any?
let textView: UITextView
var channel: FlutterMethodChannel?
public init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?,
messenger: FlutterBinaryMessenger) {
self.frame = frame
self.viewId = viewId
self.arguments = args
self.textView = UITextView()
self.channel = nil
super.init()
// This channel name has to be matched with the the name that we defined in `TextViewController` above
self.channel = FlutterMethodChannel(name: "com.my_app.channel.textview_\(viewId)", binaryMessenger: messenger)
channel?.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
switch call.method {
case "setHtmlText":
let args = call.arguments as? [String: Any]
self?.set(htmlText: (args?["text"] as? String) ?? "")
default:
break
}
})
}
public func view() -> UIView {
return textView
}
private func set(htmlText: String) {
DispatchQueue.main.async {
//Rendering HTML in in next cycle cuz html from text is expensive task.
let format = #"<span style="font-size:%.2fpx;font-family:'-apple-system';font-weight:400;color:#40485A;">%@</span>"#
let html = String(format: format, 14.0, htmlText)
let data = html.data(using: .utf8)!
let attributedText = try! NSAttributedString(data: data,
options: [.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
self.textView.attributedText = attributedText
}
}
}
创建一个 UITextView 工厂
public class FlutterUITextViewViewFactory: NSObject, FlutterPlatformViewFactory {
let messenger: FlutterBinaryMessenger
public init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
}
public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
return FlutterUITextView(withFrame: frame, viewIdentifier: viewId,
arguments: args, messenger: messenger)
}
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
设置Flutter引擎
这种设置对于iOS的项目没有了FlutterAppDelegate
1: 转到你想要展示 Flutter 应用的 swift 文件
2:进口
import Flutter
import FlutterPluginRegistrant
3:存储Flutter引擎,确保这个变量是你的类中的全局变量
let flutterEngine = FlutterEngine(name: "this_is_my_flutter_app")
- 名称:只显示引擎的名称
4:启动并注册引擎
flutterEngine.run()
GeneratedPluginRegistrant.register(with: flutterEngine)
有关 iOS 中 Flutter 引擎的更多详细信息 ( flutter.dev/docs/develo… )
5:将 FlutterUITextView 注册到 Flutter 引擎
let registrar = flutterEngine.registrar(forPlugin: "FlutterUITextView")!
let viewFactory = FlutterUITextViewViewFactory(messenger: registrar.messenger())
registrar.register(viewFactory, withId: "FlutterUITextView")
- param
withId
("FlutterUITextView"
) 应该与viewType
我们在 Flutter 代码中定义的UiTextView
's匹配viewType
。
6:展示 Flutter 应用
let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
parent?.present(flutterVC, animated: true, completion: nil)
- 底层相关的面试文章(github.com/iOS-Mayday/…
- 简历指导和常见算法(github.com/iOS-Mayday/…
转载自:https://juejin.cn/post/7027351992599052301