亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用PlatformView將?Android?控件view制作成Flutter插件

 更新時(shí)間:2022年11月14日 14:23:26   作者:李小轟_Rex  
這篇文章主要為大家介紹了使用PlatformView將?Android?控件view制作成Flutter插件實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

小編最近在項(xiàng)目中實(shí)現(xiàn)相機(jī)識(shí)別人臉的功能,將 Android 封裝的控件 view 進(jìn)行中轉(zhuǎn),制作成 FlutterPlugin 提供給 flutter 項(xiàng)目使用。為了方便后期的知識(shí)整理,下面,用簡(jiǎn)單的 demo 記錄 Android 控件如何封裝成 flutter 插件以及如何實(shí)現(xiàn)交互的過(guò)程。

1. FlutterPlugin 創(chuàng)建

第一步,創(chuàng)建一個(gè) FlutterPlugin 項(xiàng)目。

2. 創(chuàng)建 Android 控件

拋磚引玉,創(chuàng)建一個(gè)簡(jiǎn)單的自定義控件,控件內(nèi)包含三個(gè)元素

layout_custom_view.xml (布局文件)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/androidViewButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="20dp"
        android:text="發(fā)送數(shù)據(jù)給 flutter" />
    <!--用于展示從flutter層接收的數(shù)據(jù)-->
    <TextView
        android:id="@+id/androidViewText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/androidViewButton"
        android:layout_centerHorizontal="true"
        android:padding="20dp"
        android:text="" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:paddingBottom="10dp"
        android:text="Android-View"
        android:textSize="20dp"
        android:textStyle="bold" />
</RelativeLayout>

CustomView.kt

/**
 *  android 渲染的自定義view 提供 flutter 使用
 */
class CustomView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
    private var textView: TextView? = null
    private var onKeyEventCallback: OnKeyEventCallback? = null
    init {
        val rootView = LayoutInflater.from(context).inflate(R.layout.layout_custom_view, this, true)
        initView(rootView)
    }
    private fun initView(rootView: View) {
        textView = rootView.findViewById(R.id.androidViewText)
        rootView.findViewById<Button>(R.id.androidViewButton).setOnClickListener {
            //模擬生成一個(gè)隨機(jī)數(shù)傳遞到 flutter
            val randomNum = (0..10).random()
            onKeyEventCallback?.onKeyEventCallback(randomNum.toString())
        }
    }
    fun setOnKeyEventCallback(callback: OnKeyEventCallback?) {
        onKeyEventCallback = callback
    }
    @SuppressLint("SetTextI18n")
    fun getMessageFromFlutter(message: String) {
        textView?.text = "自來(lái)flutter的數(shù)據(jù):$message"
    }
}
interface OnKeyEventCallback {
    fun onKeyEventCallback(message: String)
}

自定義控件進(jìn)行UI繪制,顯示文本 Android-View。為了模擬雙向交互流程,控件內(nèi)放置了一個(gè)按鈕用于生成隨機(jī)數(shù)模擬 android 層向 flutter 層的數(shù)據(jù)傳輸;放置了一塊文本區(qū)域用于展示從 flutter 層接收到的數(shù)據(jù)。

3. 注冊(cè) Android 控件

在 plugin 的 onAttachToEngine 方法中對(duì)自定義控件進(jìn)行注冊(cè)

class CustomAndroidViewPlugin: FlutterPlugin, ActivityAware {
  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    /// 將 Android 控件進(jìn)行注冊(cè),提供 flutter 層使用
    flutterPluginBinding.platformViewRegistry
      .registerViewFactory(
        VIEW_TYPE_ID,
        CustomViewFactory(flutterPluginBinding.binaryMessenger)
      )
  }
 ...省略部分非關(guān)鍵代碼
  companion object {
    // 通過(guò)唯一值id進(jìn)行控件注冊(cè)
    private const val VIEW_TYPE_ID = "com.rex.custom.android/customView"
  }
}

實(shí)際注冊(cè)的對(duì)象 CustomViewFactory 代碼如下:

class CustomViewFactory(
    private val messenger: BinaryMessenger
) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(
        context: Context?,
        viewId: Int,
        args: Any?
    ): PlatformView {
        @Suppress("UNCHECKED_CAST")
        val params = args as HashMap<String, Any>
        return CustomViewController(
            context = requireNotNull(context),
            id = viewId,
            messenger = messenger,
            params = params
        )
    }
}

4. 封裝 Android 層通信交互 ‘CustomViewController’

/**
 * 提供 AndroidView 與 flutter 間的交互能力
 */
class CustomViewController(
    private val context: Context,
    messenger: BinaryMessenger,
    val id: Int,
    val params: HashMap<String, Any>
) : PlatformView {
    private var customView: CustomView? = null
    private val channel: MethodChannel = MethodChannel(
        messenger, "com.rex.custom.android/customView$id"
    )
    init {
        // 如果需要在自定義view交互中申請(qǐng)監(jiān)聽(tīng)權(quán)限可以加上下面這句話
        // CustomShared.binding?.addRequestPermissionsResultListener(this)
        channel.setMethodCallHandler(this)
        params.entries.forEach {
            Log.i("rex", "CustomView初始化接收入?yún)ⅲ?{it.key} - ${it.value}")
        }
    }
    override fun getView(): View = initCustomView()
    private fun initCustomView(): View {
        if (customView == null) {
            customView = CustomView(context, null)
            customView!!.setOnKeyEventCallback(object : OnKeyEventCallback {
                override fun onKeyEventCallback(message: String) {
                    // 將 Android 層的數(shù)據(jù)傳遞到 flutter 層
                    channel.invokeMethod(
                        "getMessageFromAndroidView",
                        "native - $message"
                    )
                }
            })
        }
        return customView!!
    }
    override fun dispose() {
        // flutterView dispose 生命周期 在此響應(yīng)
        Log.i("rex", "flutterView on Dispose")
    }
    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        when (call.method) {
            "getMessageFromFlutterView" -> {
                customView?.getMessageFromFlutter(call.arguments.toString())
                result.success(true)
            }
            else -> result.notImplemented()
        }
    }
}

代碼說(shuō)明

  • CustomViewController 需實(shí)現(xiàn) PlatformView 實(shí)現(xiàn) getView 方法返回 自定義UI控件
  • 通過(guò) MethodChannel 實(shí)現(xiàn) Android - Flutter 間的交互通信能力。
  • Android代碼中,自定義控件如何接收 flutter 端的方法調(diào)用? 在 onMethodCall 方法中接收來(lái)自 flutter 端的方法調(diào)用,通過(guò)方法名區(qū)分,調(diào)用指定功能。如:示例中的getMessageFromFlutterView 接收 flutter 端傳遞的數(shù)據(jù) call.arguments ,然后在自定義 Android-UI 控件中展示出來(lái) customView.getMessageFromFlutter。
  • Android代碼中,自定義控件如何調(diào)用 flutter 端方法? 使用方法 channel.invokeMethod(param1, param2) ,param1 為約定的方法名稱,如示例中的 getMessageFromAndroidView, 生成一個(gè)隨機(jī)數(shù)傳遞給 flutter 端;param2 為 想要傳遞給 flutter 端的數(shù)據(jù),數(shù)據(jù)類型可以是任意類型,示例中使用的是字符串類型。

5. 在 flutter 中如何使用已注冊(cè)的 Android 控件(view)

創(chuàng)建 custom_android_view.dart 用于包裹 Android 控件

關(guān)鍵點(diǎn):通過(guò)原生層中注冊(cè)的 id 路徑獲取 AndroidView 要求:AndroidView 中 viewType 參數(shù)就是原生層中注冊(cè)的自定義控件的映射路徑,如示例中 CustomAndroidViewPlugin 內(nèi)的 viewTypeId

AndroidView(
      viewType: 'com.rex.custom.android/customView', //要與注冊(cè)的路徑保持一致
      onPlatformViewCreated: _onPlatformViewCreated,
      creationParams: const <String, dynamic>{'initParams': 'hello world'},
      creationParamsCodec: const StandardMessageCodec(),
    )

將 AndroidView 進(jìn)行封裝,控件名稱為 CustomAndroidView ,完整代碼如下:

typedef OnViewCreated = Function(CustomViewController);
///自定義AndroidView
class CustomAndroidView extends StatefulWidget {
  final OnViewCreated onViewCreated;
  const CustomAndroidView(this.onViewCreated, {Key? key}) : super(key: key);
  @override
  State<CustomAndroidView> createState() => _CustomAndroidViewState();
}
class _CustomAndroidViewState extends State<CustomAndroidView> {
  late MethodChannel _channel;
  @override
  Widget build(BuildContext context) {
    return _getPlatformFaceView();
  }
  Widget _getPlatformFaceView() {
    return AndroidView(
      viewType: 'com.rex.custom.android/customView',
      onPlatformViewCreated: _onPlatformViewCreated,
      creationParams: const <String, dynamic>{'initParams': 'hello world'},
      creationParamsCodec: const StandardMessageCodec(),
    );
  }
  void _onPlatformViewCreated(int id) {
    _channel = MethodChannel('com.rex.custom.android/customView$id');
    final controller = CustomViewController._(
      _channel,
    );
    widget.onViewCreated(controller);
  }
}
class CustomViewController {
  final MethodChannel _channel;
  final StreamController<String> _controller = StreamController<String>();
  CustomViewController._(
    this._channel,
  ) {
    _channel.setMethodCallHandler(
      (call) async {
        switch (call.method) {
          case 'getMessageFromAndroidView':
            // 從native端獲取數(shù)據(jù)
            final result = call.arguments as String;
            _controller.sink.add(result);
            break;
        }
      },
    );
  }
  Stream<String> get customDataStream => _controller.stream;
  // 發(fā)送數(shù)據(jù)給native
  Future<void> sendMessageToAndroidView(String message) async {
    await _channel.invokeMethod(
      'getMessageFromFlutterView',
      message,
    );
  }
}

代碼說(shuō)明

  • AndroidView 在加載完成時(shí)會(huì)回調(diào)我們的 _onPlatformViewCreated 方法,小編在 _onPlatformViewCreated 方法內(nèi)將 methodChannel 初始化,用于監(jiān)聽(tīng) Android 端的方法調(diào)用,以及后續(xù)用其調(diào)用 Android控件內(nèi)封裝的方法。
  • 小編給 CustomAndroidView 封裝了一個(gè) controller 控制類,在 CustomAndroidView 的構(gòu)造方法中回傳給調(diào)用者,調(diào)用者可通過(guò) controller 進(jìn)行監(jiān)聽(tīng) Android 端傳送過(guò)來(lái)的數(shù)據(jù),以及通過(guò) controller 調(diào)用控件提供的能力方法。

如何使用這個(gè)View

展示 CustomAndroidView :

Widget _buildAndroidView() {
    return CustomAndroidView(_onCustomAndroidViewCreated)
}

接收來(lái)自 Android 層的傳輸數(shù)據(jù)

void _onCustomAndroidViewCreated(CustomViewController controller) {
    _controller = controller;
    _controller?.customDataStream.listen((data) {
      //接收到來(lái)自Android端的數(shù)據(jù)
      setState(() {
        receivedData = '來(lái)自Android的數(shù)據(jù):$data';
      });
    });
  }

通過(guò)控件發(fā)送數(shù)據(jù)給 Android 層

final randomNum = Random().nextInt(10);
_controller?.sendMessageToAndroidView('flutter - $randomNum ');
// _controller 在CustomAndroidView 的構(gòu)造方法回調(diào)中獲取,如標(biāo)簽2

6. 附上 example 完整代碼

example/main.dart

void main() {
  runApp(const MaterialApp(home: MyHome()));
}
class MyHome extends StatelessWidget {
  const MyHome({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: CustomExample(),
    );
  }
}
class CustomExample extends StatefulWidget {
  const CustomExample({Key? key}) : super(key: key);
  @override
  State<CustomExample> createState() => _CustomExampleState();
}
class _CustomExampleState extends State<CustomExample> {
  String receivedData = '';
  CustomViewController? _controller;
  void _onCustomAndroidViewCreated(CustomViewController controller) {
    _controller = controller;
    _controller?.customDataStream.listen((data) {
      //接收到來(lái)自Android端的數(shù)據(jù)
      setState(() {
        receivedData = '來(lái)自Android的數(shù)據(jù):$data';
      });
    });
  }
  Widget _buildAndroidView() {
    return Expanded(
      child: Container(
        color: Colors.blueAccent.withAlpha(60),
        child: CustomAndroidView(_onCustomAndroidViewCreated),
      ),
      flex: 1,
    );
  }
  Widget _buildFlutterView() {
    return Expanded(
      child: Stack(
        alignment: AlignmentDirectional.bottomCenter,
        children: [
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              TextButton(
                onPressed: () {
                  final randomNum = Random().nextInt(10);
                  _controller
                      ?.sendMessageToAndroidView('flutter - $randomNum ');
                },
                child: const Text('發(fā)送數(shù)據(jù)給Android'),
              ),
              const SizedBox(height: 10),
              Text(receivedData),
            ],
          ),
          const Padding(
            padding: EdgeInsets.only(bottom: 15),
            child: Text(
              'Flutter - View',
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
        ],
      ),
      flex: 1,
    );
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        _buildAndroidView(),
        _buildFlutterView(),
      ],
    );
  }
}

如上,demo 將一個(gè)頁(yè)面均分為上下兩塊,上半部分使用 Android 控件,下半部分使用 Flutter 控件,兩組控件間進(jìn)行通信交互。

demo 已上傳:github.com/liyufengrex…

以上就是使用PlatformView將 Android 控件view制成Flutter插件的詳細(xì)內(nèi)容,更多關(guān)于Android view制成Flutter的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android Studio添加日志過(guò)濾方式

    Android Studio添加日志過(guò)濾方式

    這篇文章主要介紹了Android Studio添加日志過(guò)濾方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04
  • Android繪圖常用方法匯總

    Android繪圖常用方法匯總

    這篇文章主要為大家總結(jié)了Android繪圖的常用方法,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2016-05-05
  • Android中刷新界面的二種方法

    Android中刷新界面的二種方法

    這篇文章主要介紹了Android中刷新界面的二種方法,本文使用Handler、postInvalidate兩種方法實(shí)現(xiàn)界面刷新,需要的朋友可以參考下
    2014-10-10
  • kotlin源碼結(jié)構(gòu)層次詳解

    kotlin源碼結(jié)構(gòu)層次詳解

    這篇文章主要為大家介紹了kotlin源碼結(jié)構(gòu)層次詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Android WebView 常見(jiàn)問(wèn)題及處理方案

    Android WebView 常見(jiàn)問(wèn)題及處理方案

    這篇文章主要介紹了Android WebView 常見(jiàn)問(wèn)題及處理方案,需要的朋友可以參考下
    2015-08-08
  • Android網(wǎng)絡(luò)監(jiān)聽(tīng)和網(wǎng)絡(luò)判斷示例介紹

    Android網(wǎng)絡(luò)監(jiān)聽(tīng)和網(wǎng)絡(luò)判斷示例介紹

    大家好,本篇文章主要講的是Android網(wǎng)絡(luò)監(jiān)聽(tīng)和網(wǎng)絡(luò)判斷示例介紹,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Android音視頻開(kāi)發(fā)只硬件解碼組件MediaCodec講解

    Android音視頻開(kāi)發(fā)只硬件解碼組件MediaCodec講解

    在Android開(kāi)發(fā)中提供了實(shí)現(xiàn)音視頻編解碼工具M(jìn)ediaCodec,針對(duì)對(duì)應(yīng)音視頻解碼類型通過(guò)該類創(chuàng)建對(duì)應(yīng)解碼器就能實(shí)現(xiàn)對(duì)數(shù)據(jù)進(jìn)行解碼操作。本文通過(guò)示例詳細(xì)講解了MediaCodec的使用,需要的可以參考一下
    2023-01-01
  • android使用SkinManager實(shí)現(xiàn)換膚功能的示例

    android使用SkinManager實(shí)現(xiàn)換膚功能的示例

    本篇文章主要介紹了android使用SkinManager實(shí)現(xiàn)換膚功能的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • Android 項(xiàng)目正式簽名打包教程分享

    Android 項(xiàng)目正式簽名打包教程分享

    這篇文章主要介紹了Android 項(xiàng)目正式簽名打包教程分享,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-03-03
  • 詳解androidstudio項(xiàng)目上傳到github方法以及步驟

    詳解androidstudio項(xiàng)目上傳到github方法以及步驟

    在使用studio開(kāi)發(fā)的項(xiàng)目過(guò)程中有時(shí)候我們想將項(xiàng)目發(fā)布到github上,studio其實(shí)是自帶這種功能的,那么如何使用呢,下面我們就一起來(lái)了解一下
    2019-01-01

最新評(píng)論