更多文章請檢視 flutter從入門 到精通
本篇文章 中寫到的是 flutter 調用了Android 原生的 TextView 案例
添加原生元件的流程基本上可以描述為:
- 1 android 端實作原生元件PlatformView提供原生view
- 2 android 端建立PlatformViewFactory用于生成PlatformView
- 3 android 端建立FlutterPlugin用于注冊原生元件
- 4 flutter 平台嵌入 原生view
1 建立原生元件
建立在fLutter工程時會生成幾個檔案夾,lib是放flutter工程代碼,android和ios檔案夾分别是對應的雙平台的原生工程。
在這裡直接打開Android工程目錄,項目預設生成了GeneratedPluginRegistrant和MainActivity兩個檔案,GeneratedPluginRegistrant不要動,GeneratedPluginRegistrant是flutter中配制使用其他插件時,程式在編譯時自動進行插件注冊使用的類。
在MainActivity的包下建立自定義View,Flutter的原生View不能直接繼承自View,需要實作提供的PlatformView接口:
public class TestTextView implements PlatformView r{
private final TextView mTestTextView;
/**
*
* @param context
* @param messenger
* @param id
* @param params 初始化時 flutter 傳遞過來的參數
*/
TestTextView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
//建立 TextView
TextView lTextView = new TextView(context);
lTextView.setText("Android的原生TextView");
this.mTestTextView = lTextView;
//flutter 傳遞過來的參數
if (params!=null&¶ms.containsKey("content")) {
String myContent = (String) params.get("content");
lTextView.setText(myContent);
}
}
@Override
public View getView() {
return mTestTextView;
}
@Override
public void dispose() {
}
}
2 建立PlatformViewFactory
import android.content.Context;
import java.util.Map;
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 TestViewFactory extends PlatformViewFactory {
private final BinaryMessenger messenger;
public TestViewFactory(BinaryMessenger messenger) {
super(StandardMessageCodec.INSTANCE);
this.messenger = messenger;
}
/**
*
* @param context
* @param id
* @param args args是由Flutter傳過來的自定義參數
* @return
*/
@SuppressWarnings("unchecked")
@Override
public PlatformView create(Context context, int id, Object args) {
//flutter 傳遞過來的參數
Map<String, Object> params = (Map<String, Object>) args;
//建立 TestTextView
return new TestTextView(context, messenger, id, params);
}
3 建立Plugin并在ManActivity中注冊插件
/**
* flutter 調用 android 原生view
*
*/
public class TestFluttertoAndroidTextViewPlugin {
public static void registerWith(PluginRegistry registry) {
//防止多次注冊
final String key = TestFluttertoAndroidTextViewPlugin.class.getCanonicalName();
if (registry.hasPlugin(key)) return;
//初始化 PluginRegistry
PluginRegistry.Registrar registrar = registry.registrarFor(key);
//設定辨別
registrar.platformViewRegistry().registerViewFactory("com.flutter_to_native_test_textview", new TestViewFactory(registrar.messenger()));
}
}
MainActivity 中注冊
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.FlutterToAndroidPlugins
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//flutter 項目工程中預設生成的
GeneratedPluginRegistrant.registerWith(this)
//這是我們新建立的插件
TestFluttertoAndroidTextViewPlugin.registerWith(this)
}
override fun onDestroy() {
super.onDestroy()
}
}
4 flutter頁面中嵌入android 原生Textview
4.1 最簡單的調用

//這裡設定的 viewType值與 android 中插件注冊的辨別 一至
//registrar.platformViewRegistry().registerViewFactory("com.flutter_to_native_test_textview", new TestViewFactory(registrar.messenger()));
mTextWidget = Container(
height: 200,
child: AndroidView(
//設定辨別
viewType: "com.flutter_to_native_test_textview",
),
);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: appBar,
//顯示的頁面
body: mTextWidget,
);
}
4.2 flutter 調用 原生view并傳參數
mTextWidget = Container(
height: 200,
child: AndroidView(
//辨別
viewType: "com.flutter_to_native_test_textview",
creationParams: {
"content": "flutter 傳入的文本内容",
},
//參數的編碼方式
creationParamsCodec: const StandardMessageCodec(),
),
);
android 原生中的接收(隻會接收一次)
... ...
TestTextView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
... ..
//flutter 傳遞過來的參數
if (params!=null&&!params.isEmpty()&¶ms.containsKey("content")) {
String myContent = (String) params.get("content");
lTextView.setText(myContent);
}
... ...
}
4.3 flutter 更新 原生view 中的資料
原生元件初始化的參數并不會随着setState重複指派,可以通過MethodCall來實作更新資料。
首先讓原生view元件實作MethodCallHandler接口:
public class TestTextView implements PlatformView , MethodChannel.MethodCallHandler{
private final TextView mTestTextView;
TestTextView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
... ...
//com.flutter_to_native_test_view_ 是更新資料的通信辨別
MethodChannel methodChannel = new MethodChannel(messenger, "com.flutter_to_native_test_textview_" + id);
methodChannel.setMethodCallHandler(this);
}
... ...
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
//updateText 是flutter 中調用的方法名稱,可以随意定義
if ("updateText".equals(methodCall.method)) {
String text = (String) methodCall.arguments;
this.mTestTextView .setText(text);
//對flutter 的回調
result.success(null);
}
}
}
flutter 中調用 android 原生view
MethodChannel _channel;
int viewId=0;
mTextWidget = Container(
height: 200,
child: AndroidView(
//辨別
viewType: "com.flutter_to_native_test_textview",
creationParams: {
"content": "flutter 傳入的文本内容",
},
//參數的編碼方式
creationParamsCodec: const StandardMessageCodec(),
//view建立完成時的回調
onPlatformViewCreated: (id) {
viewId = id;
},
),
);
更新資料
//這裡設定的辨別 MethodChannel('com.flutter_to_native_test_textview_$viewId');
// 與android MethodChannel methodChannel = new MethodChannel(messenger, "com.flutter_to_native_test_textview_" + id); 中注冊的一至
void clickUpdtae(){
_channel = new MethodChannel('com.flutter_to_native_test_textview_$viewId');
updateTextView();
}
//這裡的辨別 updateText
//與android 中接收消息的方法中
//if ("updateText".equals(methodCall.method)) {...} 一至
void updateTextView() async {
return _channel.invokeMethod('updateText', "更新内容");
}
通過onPlatformViewCreated回調,監聽原始元件成功建立,并能夠在回調方法的參數中拿到目前元件的id,這個id是系統随機配置設定的,然後通過這個配置設定的id加上我們的元件名稱最為字首建立一個群組件通訊的MethodChannel,拿到channel對象之後就可以通過invokeMethod方法向原生元件發送消息了,這裡這裡調用的是‘updateText’這個方法,參數是一個String
本公衆号會首發系列專題文章,付費的視訊課程會在公衆号中免費刊登,在你上下班的路上或者是睡覺前的一刻,本公衆号都是你浏覽知識幹貨的一個小選擇,收藏不如行動,在那一刻,公衆号會提示你該學習了。