【译】Flutter PlatformView: 如何通过原生view创建widget

栏目: IOS · Android · 发布时间: 6年前

内容简介:最近想要实现一个flutter地图插件,但是flutter只提供了基于google map的官方插件,所以想要使用高德地图和百度地图自己做一个,就看到了这篇文章,顺便翻译一下分享给大家。这里先贴出google map插件文章以便有梯子的同学可以直接使用Flutter最近刚刚有了一个新的组件叫做

最近想要实现一个flutter地图插件,但是flutter只提供了基于google map的官方插件,所以想要使用高德地图和百度地图自己做一个,就看到了这篇文章,顺便翻译一下分享给大家。

这里先贴出google map插件文章以便有梯子的同学可以直接使用 Exploring Google Maps in Flutter

译文

【译】Flutter PlatformView: 如何通过原生view创建widget

Flutter最近刚刚有了一个新的组件叫做 PlatformView ,它允许开发者在flutter里面嵌入Android原生的view。这一开放举措为实现注入地图和webview提供了许多新的可能。( github.com/flutter/flu… ).

在这篇教程里,我们将探索如何创建一个 TextViewPlugin ,在plugin里我们会暴露一个android原生TextView作为flutter组件。

在进入代码实现之前需要注意以下几点:

  • 目前只支持Android(作者文章发布于2018.9.7, 目前已经支持ios )。
  • 需要android api版本在20及以上。
  • 嵌入Android views是一个昂贵的操作,所以应当避免在flutter能够实现的情况下去使用它。
  • 嵌入Android view的绘制和其他任何flutter widget一样,view的转换也同样使用。
  • 组件会撑满所有可获得控件,因此它的父组件需要提供一个布局边界。
  • 需要切换到flutter的master分支上使用(目前已经不需要)

下面开始实现部分

第一步就是创建一个flutter plugin项目。

【译】Flutter PlatformView: 如何通过原生view创建widget
【译】Flutter PlatformView: 如何通过原生view创建widget

在flutter plugin项目创建完成之后在 ./lib/text_view.dart 创建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) {
      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);
  }
}

复制代码

一个需要重点注意的是当我们在上面代码第24行创建了 AndroidView ,我们需要提供一个 viewType ,会在稍后介绍。

我们还提供了一个 onPlatformCompleted 实现,以便我们可以为 TextView 小部件提供一个 TextViewController ,然后可以使用它来使用 setText 方法更新它的文本。

完整的 AndroidView 文档请见 docs.flutter.io/flutter/wid…

接下来我们需要实现Android部分的 TextViewPlugin

我们打开另一个生成文件 ./android/src/main/java/{organization_name}/TextViewPlugin.java ,用一下内容替换文件内的内容。

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()));
  }
}
复制代码

我们需要做的就是实现 registerWith 方法,传入 text_view.dart 中定义的 viewType ,同时提供一个 TextViewFactory ,它将会创建原生 TextView 作为 PlatformView

接着我们需要创建 ./android/src/main/java/{organization_name}/TextViewFactory.java ,并继承 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);
    }
}
复制代码

TextViewFactory 实现了create方法,它会返回 PlatformView ,在我们的例子里叫做 FlutterTextView

然后,创建 ./android/src/main/java/{organization_name}/FlutterTextView.java 并且实现 PlatformViewMethodCallHandler 以至于我们可以将原生view绘制到flutter组件并且通过 MethodChannel 从dart接收数据。

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() {}
}

复制代码

FlutterTextView 创建了一个新的 TextView 并且设置了一个 MethodChannel ,因此TextView可以从dart代码接收数据进行视图更新。

为了实现 PlatformView ,我们需要重写 getView 方法返回textview对象,同时重写 dispose 方法。

为了实现 MethodCallHandler ,需要重写 onMethodCall ,在接收到 setText 调用指令时候更新TextView,或者在不支持的其他指令情况下返回 result.notImplemented

现在可以测试我们的新 TextView 组件。

打开 ./example/lib/main.dart 用下面的代码替换。

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!');
  }
}

复制代码

代码看着很熟悉,我们运行一个 MaterialApp ,最外层用 Scaffold 。有一个 TextViewContainer 包裹,这个container组件作为一个垂直排列组件的第一个子组件,第二个子组件是一个flutter Text

我们同样实现了方法 onTextViewCreated ,在这个方法里面去调用 setText

【译】Flutter PlatformView: 如何通过原生view创建widget

这个例子证明了可以对任何原生Android view转换成flutterwidget,并且像其他flutter组件一样绘制和转换。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HotSpot实战

HotSpot实战

陈涛 / 人民邮电出版社 / 2014-3 / 69

《HotSpot实战》深入浅出地讲解了HotSpot虚拟机的工作原理,将隐藏在它内部的本质内容逐一呈现在读者面前,包括OpenJDK与HotSpot项目、编译和调试HotSpot的方法、HotSpot内核结构、Launcher、OOP-Klass对象表示系统、链接、运行时数据区、方法区、常量池和常量池Cache、Perf Data、Crash分析方法、转储分析方法、垃圾收集器的设计演进、CMS和G......一起来看看 《HotSpot实战》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具