Currently Flutter does not have a TextView, so we must have a native TextView injected from iOS and Android into the Flutter project.
Platform view and platform channel
Flutter. Dev/docs/develo…
- This is an API for Flutter, used to create widgets from native views!
- And how Dart and iOS/Android communicate with each order
perform
In the Flutter project
Create a Widget calling TextView on the Flutter side
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);
}
}
Copy the code
We can also have more methods setHtmlText to set more data to the TextView from the local side
From the caller of Flutter
TextView(onTextViewCreated: (TextViewController controller) {
controller.setHtmlText(text: "<html><body>Hello World</body></html>");
})
Copy the code
In the iOS project
Set the preview
Open info.plist, add keyio.flutter. Embedded_views_preview and value is true to make flutter preview on UIView.
<key>io.flutter.embedded_views_preview</key>
<true/>
Copy the code
Create a TextView compatible with FlutterPlatformView
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 } } }Copy the code
Create a UITextView factory
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()
}
}
Copy the code
Set up the Flutter engine
This setting has no FlutterAppDelegate for iOS projects
1: Go to the Swift file where you want to display the Flutter application
2: import
import Flutter
import FlutterPluginRegistrant
Copy the code
3: Store the Flutter engine, ensuring that this variable is a global variable in your class
let flutterEngine = FlutterEngine(name: "this_is_my_flutter_app")
Copy the code
- Name: Displays only the engine name
4: Start and register the engine
flutterEngine.run()
GeneratedPluginRegistrant.register(with: flutterEngine)
Copy the code
Dev /docs/develo…
5: Register FlutterUITextView with the Flutter engine
let registrar = flutterEngine.registrar(forPlugin: "FlutterUITextView")!
let viewFactory = FlutterUITextViewViewFactory(messenger: registrar.messenger())
registrar.register(viewFactory, withId: "FlutterUITextView")
Copy the code
- param
withId
("FlutterUITextView"
) should be withviewType
We defined this in the Flutter codeUiTextView
‘s matchviewType
.
6: Show the application of Flutter
let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil) parent? .present(flutterVC, animated: true, completion: nil)Copy the code
- Underlying related interview articles (github.com/iOS-Mayday/…
- Resume guides and common algorithms (github.com/iOS-Mayday/…