flutter學習之嵌入原生View - android

語言: CN / TW / HK

highlight: androidstudio

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第26天,點選檢視活動詳情

  • 本文主要介紹如何在 flutter中載入原生android的view,之前我們介紹了flutter載入iOS view。原理也是類似。

1. 建立android中view

我們是iOS開發,這裡簡單介紹下如何載入原生android的view,其流程和我們iOS view類似。

我們在android專案的建立一個測試view ```Dart package com.example.flutter_android_view import android.content.Context import android.view.View import android.widget.TextView import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.platform.PlatformView

class TestView(context: Context, messenger: BinaryMessenger, viewId: Int, args: Map?) : PlatformView {

private val textView: TextView = TextView(context)

init {
    textView.text = "這是一個Android View"
}

override fun getView(): View {

    return textView
}

override fun dispose() {
    TODO("Not yet implemented")
}

} 我們繼續建立`TestViewFactory`Dart 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

class TestViewFactory(private val messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {

override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
    return TestView(context, messenger, viewId, args as Map<String, Any>?)
}

} 建立TestPluginDart import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.PluginRegistry

class TestViewPlugin : FlutterPlugin {

override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    val messenger: BinaryMessenger = binding.binaryMessenger
    binding
        .platformViewRegistry
        .registerViewFactory(
            "plugins.flutter.io/custom_platform_view", TestViewFactory(messenger))
}

companion object {
    @JvmStatic
    fun registerWith(registrar: PluginRegistry.Registrar) {
        registrar
            .platformViewRegistry()
            .registerViewFactory(
                "plugins.flutter.io/custom_platform_view",
                TestViewFactory(registrar.messenger()))
    }
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {

}

} 在 **App 中 MainActivity** 中註冊:Dart package com.example.flutter_android_view import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine

class MainActivity: FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) flutterEngine.plugins.add(TestViewPlugin()) } } ``` 最後的目錄結構

image.png 嵌入flutter

```Dart import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart';

class AndroidViewPage extends StatelessWidget { const AndroidViewPage({Key? key}) : super(key: key);

@override Widget build(BuildContext context) { String? title = "androidView";

return Scaffold(

  appBar: AppBar(title: Text(title ?? ''),),
  body: Center(
    child:iosView(),
  ),
);

} Widget iosView() { if(defaultTargetPlatform == TargetPlatform.android){ return const AndroidView( viewType: 'plugins.flutter.io/custom_platform_view', ); }else { return Container(); } } } ``` 使用android模擬器執行結果

image.png

2. Flutter向android傳值

Dart AndroidView( viewType: 'plugins.flutter.io/custom_platform_view', creationParams: {'text': 'Flutter傳給Android中TextView的引數'}, creationParamsCodec: StandardMessageCodec(), ); 這裡viewType就是我們註冊的時候使用的識別符號creationParams為建立AndroidView時帶的引數creationParamsCodec:將 creationParams編碼後再發送給平臺側,它應該與傳遞給建構函式的編解碼器匹配

我們在Android專案中TestView判斷是否傳遞了引數 Dart init { args?.also { textView.text = it["text"] as String } }

image.png 我們在執行中通過按鈕點選改變AndroidView的內容

js static const platform = MethodChannel('com.flutter.test.TestView'); 我們在flutter頁面定義一個方法通道

```js RaisedButton( child: const Text('傳遞引數給原生View'), onPressed: () { platform.invokeMethod('userInfo', {'name': 'Jack', 'city': "New York"}); },

``` 點選的時候傳參給Android頁面,我們在onMethodCall方法中獲取我們的引數

```js override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { if (call.method == "userInfo") {

    val name = call.argument("name") as String?
    val city = call.argument("city") as String?

    textView.text = "my Name is:,$name,from:$city"
} else {
    result.notImplemented()
}

} ```

3. 小結

關於 android中view的傳值邏輯基本和之前的iOS頁面差不多,邏輯上都是通過viewID來標記唯一性來確定,根據一些key, method方法等進行互動回撥函式的相互回撥實現通訊