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 withviewTypeWe 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/…