Flutter PlatformView: How to create Widgets from Native Views

Flutter just recently got a new widget called PlatformView which allows developers to embed Android Views in the flutter widget hierarchy. This opens the door to many new possibilities like fully integrated maps and webviews (https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/platform_view.dart).

In this tutorial, we’re going to go through how to create a TextViewPlugin where we expose a native android TextView as a Flutter Widget.

Before we jump into the code some quick things to note are:

  • Currently only supported for Android (should be coming in the next few weeks for iOS)
  • Requires Android API level 20 or greater.
  • Embedding Android views is an expensive operation and should be avoided when a Flutter equivalent is possible.
  • The embedded Android view is painted just like any other Flutter widget and transformations apply to it as well.
  • The widget will fill all available space therefore the parent of this object must provide bounded layout constraints.
  • As of now, you need to switch to the flutter master channel in order to follow along. You can do that by running flutter channel master and making sure your new Flutter Project is pointing to the master branch of the flutter sdk.

Time to start coding :)

The first thing we’re going to need to do is create a new flutter plugin:

Create a new Flutter Project in Android Studio
Create a Flutter Plugin instead of a Flutter Application

After the Flutter Plugin has been created we can start by creating our TextView class in ./lib/text_view.dart

An important thing to note is when we create the AndroidView on line 24 we need to provide a viewType which we will get to in a bit.

We additionally provide an onPlatformCompleted implementation so that we can provide our TextView widget with a TextViewController which it can then use to update it’s text using the setText method.

For the full AndroidView documentation check out https://docs.flutter.io/flutter/widgets/AndroidView-class.html.

Next we need to work on the Android implementation of our TextViewPlugin.

We will start by opening another generated file called ./android/src/main/java/{organization_name}/TextViewPlugin.java. We can replace the contents of that file with the following:

All we are doing is implementing the registerWith method where we provide the viewType we defined earlier in text_view.dart as well as providing a TextViewFactory which will be creating our native TextView as a PlatformView.

Next, we need to create ./android/src/main/java/{organization_name}/TextViewFactory.java and extend PlatformViewFactory.

Our TextViewFactory implements the create method which returns a PlatformView (in our case it will return a FlutterTextView).

Next up, we need to create ./android/src/main/java/{organization_name}/FlutterTextView.java and implement PlatformView as well as MethodCallHandler so that we can have our native view painted as a flutter widget and be able to receive data from dart via a MethodChannel.

Our FlutterTextView creates a new TextView and sets up a MethodChannel so that the TextView can receive data from dart code and make updates (in this case update the text).

In order to implement PlatformView, we need to override getView and return our textView as well as override dispose (which in this case does nothing).

In order to implement MethodCallHandler, we need to override onMethodCall and, depending on the method, either call our internal setText method (to update the textView's text) or return result.notImplemented since we currently don’t support any other methods.

Now it’s time to test our new TextView widget!

Open ./example/lib/main.dart and replace it with the following code:

This should look familiar. We are running a MaterialApp that renders a Scaffold. We have our TextView widget nested within a Container widget (with some padding) which is embedded within a Center widget. The Center widget is the first child of a Column widget. Our Column’s second child is an Expanded widget and it contains a Container widget with the built in flutter Text widget.

We also have our implementation for onTextViewCreated where we call the setText method.

It’s time to run our example flutter app and take a look at what we’ve built.

Awesome! Even though you’d normally just use the built in flutter Text widget to accomplish this, we’ve proven that you can now “widgetize” any native Android view which is pretty powerful.

This example flutter app demonstrates that our TextView is painted just like any other Flutter widget and transformations apply to it as well.

We still need to write tests for our plugin in order for it to be production ready so we’ll do that in a follow up article. You can check out the complete source code at https://github.com/felangel/flutter_text_view_plugin.