알쓸전컴(알아두면 쓸모있는 전자 컴퓨터)

Flutter 에서 Android Widgets 불러와서 사용하기 본문

Flutter,Dart

Flutter 에서 Android Widgets 불러와서 사용하기

백곳 2019. 10. 16. 13:27

소스

github : https://github.com/felangel/flutter_text_view_plugin

 

원 게시글 

https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6

 

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…

medium.com

 

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

 

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) {
      return AndroidView(
        viewType: 'plugins.felix.angelov/textview',
        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 {
  TextViewController._(int id)
      : _channel = new MethodChannel('plugins.felix.angelov/textview_$id');

  final MethodChannel _channel;

  Future<void> setText(String text) async {
    assert(text != null);
    return _channel.invokeMethod('setText', text);
  }
}​

 

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:

package angelov.felix.textview;

import io.flutter.plugin.common.PluginRegistry.Registrar;

public class TextViewPlugin {
  public static void registerWith(Registrar registrar) {
    registrar
            .platformViewRegistry()
            .registerViewFactory(
                    "plugins.felix.angelov/textview", new TextViewFactory(registrar.messenger()));
  }
}

 

 

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.

 

package angelov.felix.textview;

import android.content.Context;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;

public class TextViewFactory extends PlatformViewFactory {
    private final BinaryMessenger messenger;

    public TextViewFactory(BinaryMessenger messenger) {
        super(StandardMessageCodec.INSTANCE);
        this.messenger = messenger;
    }

    @Override
    public PlatformView create(Context context, int id, Object o) {
        return new FlutterTextView(context, messenger, id);
    }
}

 

 

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.

package angelov.felix.textview;

import android.content.Context;
import android.view.View;
import android.widget.TextView;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import static io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import static io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;

public class FlutterTextView implements PlatformView, MethodCallHandler  {
    private final TextView textView;
    private final MethodChannel methodChannel;

    FlutterTextView(Context context, BinaryMessenger messenger, int id) {
        textView = new TextView(context);
        methodChannel = new MethodChannel(messenger, "plugins.felix.angelov/textview_" + id);
        methodChannel.setMethodCallHandler(this);
    }

    @Override
    public View getView() {
        return textView;
    }

    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        switch (methodCall.method) {
            case "setText":
                setText(methodCall, result);
                break;
            default:
                result.notImplemented();
        }

    }

    private void setText(MethodCall methodCall, Result result) {
        String text = (String) methodCall.arguments;
        textView.setText(text);
        result.success(null);
    }

    @Override
    public void dispose() {}
}

 

 

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:

 

import 'package:flutter/material.dart';
import 'package:text_view/text_view.dart';

void main() => runApp(MaterialApp(home: TextViewExample()));

class TextViewExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text('Flutter TextView example')),
        body: Column(children: [
          Center(
              child: Container(
                  padding: EdgeInsets.symmetric(vertical: 30.0),
                  width: 130.0,
                  height: 100.0,
                  child: TextView(
                    onTextViewCreated: _onTextViewCreated,
                  ))),
          Expanded(
              flex: 3,
              child: Container(
                  color: Colors.blue[100],
                  child: Center(child: Text("Hello from Flutter!"))))
        ]));
  }

  void _onTextViewCreated(TextViewController controller) {
    controller.setText('Hello from Android!');
  }
}

 

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.

Comments