Flutter提供PlatformView
,可以用来创建显示Native的控件的Widget,例如Android端的WebView、MapView等。
需注意显示PlatformView的Widget默认时无边界的,这要求其parent必须提供边界约束,在没有边界约束的容器中使用会出现如下情况
接下来通过例子演示如何基于PlatformView实现一个Widget:一个可以显示Android端TextView的Widget。
创建显示PlatformView的Widget:./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.my.example/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);
}
}
AndroidView
的子Widget,并制定了ViewType
。AndroidView就是在Android端对应的PlatformViewonPlatformViewCreated
回调,在此时可以做一些初始化操作,我们在这里创建了一个TextViewController
并传递了出去,TextViewController通过MethodChannel
与Native的TextView建立通信。MethodChannel
Android端实现插件类./android/src/main/java/{organization_name}/TextViewPlugin.java
import io.flutter.plugin.common.PluginRegistry.Registrar;
public class TextViewPlugin {
public static void registerWith(Registrar registrar) {
registrar
.platformViewRegistry()
.registerViewFactory(
"plugins.my.example/textview", new TextViewFactory(registrar.messenger()));
}
}
使用前面AndroidView中ViewType
注册一个Factory,此Factory用于创建真正的Native控件:FlutterTextView
./android/src/main/java/{organization_name}/TextViewFactory.java
创建上述Factory,继承自PlatformViewFactory
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);
}
}
Factory会创建被显示的Native View
实现FlutterTextView,继承自PlatformView
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.my.example/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
同时继承MethodCallHandler
,需要实现onMethodCall
与Flutter通信
./example/lib/main.dart
使用Widget效果如下:
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!');
}
}
创建TextView的同时,通过onTextViewCreated
回调获取TextViewController
,上文已经知道TextViewController可以帮助我们调用native的setText
方法,显示我们想显示的内容