<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    Flutter 中嵌入Android原生View

    共 12454字,需瀏覽 25分鐘

     ·

    2021-11-20 19:48

    建議使用 Android Studio 進行開發(fā),在 Android Studio 左側(cè) project tab下選中 android 目錄下任意一個文件,右上角會出現(xiàn) 「Open for Editing in Android Studio」


    點擊即可打開,打開后 project tab 并不是一個 Android 項目,而是項目中所有 Android 項目,包含第三方:


    app 目錄是當(dāng)前項目的 android 目錄,其他則是第三方的 android 目錄。

    「App」 項目的 「java/包名」 目錄下創(chuàng)建嵌入 Flutter 中的 Android View,此 View 繼承 「PlatformView」

    class?MyFlutterView(context:?Context)?:?PlatformView?{
    ????override?fun?getView():?View?{
    ????????TODO("Not?yet?implemented")
    ????}

    ????override?fun?dispose()?{
    ????????TODO("Not?yet?implemented")
    ????}
    }
    • 「getView」 :返回要嵌入 Flutter 層次結(jié)構(gòu)的Android View
    • 「dispose」:釋放此View時調(diào)用,此方法調(diào)用后 View 不可用,此方法需要清除所有對象引用,否則會造成內(nèi)存泄漏。


    返回一個簡單的 「TextView」

    class?MyFlutterView(context:?Context,?messenger:?BinaryMessenger,?viewId:?Int,?args:?Map<String,?Any>?)?:?PlatformView?{

    ????val?textView:?TextView?=?TextView(context)

    ????init?{
    ????????textView.text?=?"我是Android?View"
    ????}

    ????override?fun?getView():?View?{

    ????????return?textView
    ????}

    ????override?fun?dispose()?{
    ????????TODO("Not?yet?implemented")
    ????}
    }
    ????
    • 「messenger」:用于消息傳遞,后面介紹 Flutter 與 原生通信時用到此參數(shù)。
    • 「viewId」:View 生成時會分配一個唯一 ID。
    • 「args」:Flutter 傳遞的初始化參數(shù)。

    注冊PlatformView

    創(chuàng)建PlatformViewFactory:

    class?MyFlutterViewFactory(val?messenger:?BinaryMessenger)?:?PlatformViewFactory(StandardMessageCodec.INSTANCE)?{

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

    }
    ????

    創(chuàng)建 「MyPlugin」

    class?MyPlugin?:?FlutterPlugin?{

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

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

    ????override?fun?onDetachedFromEngine(binding:?FlutterPlugin.FlutterPluginBinding)?{

    ????}
    }
    ????

    記住 「plugins.flutter.io/custom_platform_view」 ,這個字符串在 Flutter 中需要與其保持一致。

    「App 中 MainActivity」 中注冊:

    class?MainActivity?:?FlutterActivity()?{
    ????override?fun?configureFlutterEngine(flutterEngine:?FlutterEngine)?{
    ????????super.configureFlutterEngine(flutterEngine)
    ????????flutterEngine.plugins.add(MyPlugin())
    ????}
    }

    ????

    如果是 Flutter Plugin,沒有「MainActivity」,則在對應(yīng)的 「Plugin onAttachedToEngine 和 registerWith」 方法修改如下:

    public?class?CustomPlatformViewPlugin?:?FlutterPlugin,MethodCallHandler?{
    ????///?The?MethodChannel?that?will?the?communication?between?Flutter?and?native?Android
    ????///
    ????///?This?local?reference?serves?to?register?the?plugin?with?the?Flutter?Engine?and?unregister?it

    ????///?when?the?Flutter?Engine?is?detached?from?the?Activity
    ????private?lateinit?var?channel:?MethodChannel

    ????override?fun?onAttachedToEngine(@NonNull?flutterPluginBinding:?FlutterPlugin.FlutterPluginBinding)?{
    ????????channel?=?MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(),?"custom_platform_view")
    ????????channel.setMethodCallHandler(this)

    ????????val?messenger:?BinaryMessenger?=?flutterPluginBinding.binaryMessenger
    ????????flutterPluginBinding
    ????????????????.platformViewRegistry
    ????????????????.registerViewFactory(
    ????????????????????????"plugins.flutter.io/custom_platform_view",?MyFlutterViewFactory(messenger))

    ????}

    ????//?This?static?function?is?optional?and?equivalent?to?onAttachedToEngine.?It?supports?the?old
    ????//?pre-Flutter-1.12?Android?projects.?You?are?encouraged?to?continue?supporting
    ????//?plugin?registration?via?this?function?while?apps?migrate?to?use?the?new?Android?APIs
    ????//?post-flutter-1.12?via?https://flutter.dev/go/android-project-migration.
    ????//
    ????//?It?is?encouraged?to?share?logic?between?onAttachedToEngine?and?registerWith?to?keep
    ????//?them?functionally?equivalent.?Only?one?of?onAttachedToEngine?or?registerWith?will?be?called
    ????//?depending?on?the?user's?project.?onAttachedToEngine?or?registerWith?must?both?be?defined
    ????//?in?the?same?class.
    ????companion?object?{
    ????????@JvmStatic
    ????????fun?registerWith(registrar:?Registrar)?{
    ????????????val?channel?=?MethodChannel(registrar.messenger(),?"custom_platform_view")
    ????????????channel.setMethodCallHandler(CustomPlatformViewPlugin())

    ????????????registrar
    ????????????????????.platformViewRegistry()
    ????????????????????.registerViewFactory(
    ????????????????????????????"plugins.flutter.io/custom_platform_view",
    ????????????????????????????MyFlutterViewFactory(registrar.messenger()))
    ????????}
    ????}

    ????override?fun?onMethodCall(@NonNull?call:?MethodCall,?@NonNull?result:?Result)?{
    ????????if?(call.method?==?"getPlatformVersion")?{
    ????????????result.success("Android?${android.os.Build.VERSION.RELEASE}")
    ????????}?else?{
    ????????????result.notImplemented()
    ????????}
    ????}

    ????override?fun?onDetachedFromEngine(@NonNull?binding:?FlutterPlugin.FlutterPluginBinding)?{
    ????????channel.setMethodCallHandler(null)
    ????}
    }

    ????

    嵌入Flutter

    在 Flutter 中調(diào)用

    class?PlatformViewDemo?extends?StatelessWidget?{
    ??@override
    ??Widget?build(BuildContext?context)?{
    ????Widget?platformView(){
    ??????if(defaultTargetPlatform?==?TargetPlatform.android){
    ????????return?AndroidView(
    ??????????viewType:?'plugins.flutter.io/custom_platform_view',
    ????????);
    ??????}
    ????}
    ????return?Scaffold(
    ??????appBar:?AppBar(),
    ??????body:?Center(
    ????????child:?platformView(),
    ??????),
    ????);
    ??}
    }
    ????

    上面嵌入的是 Android View,因此通過 「defaultTargetPlatform == TargetPlatform.android」 判斷當(dāng)前平臺加載,在 Android 上運行效果:


    設(shè)置初始化參數(shù)

    Flutter 端修改如下:

    AndroidView(
    ??????????viewType:?'plugins.flutter.io/custom_platform_view',
    ??????????creationParams:?{'text':?'Flutter傳給AndroidTextView的參數(shù)'},
    ??????????creationParamsCodec:?StandardMessageCodec(),
    ????????)

    ????
    • 「creationParams」 :傳遞的參數(shù),插件可以將此參數(shù)傳遞給 AndroidView 的構(gòu)造函數(shù)。

    • creationParamsCodec

      :將 creationParams 編碼后再發(fā)送給平臺側(cè),它應(yīng)該與傳遞給構(gòu)造函數(shù)的編解碼器匹配。值的范圍:

      • StandardMessageCodec
      • JSONMessageCodec
      • StringCodec
      • BinaryCodec

    修改 MyFlutterView :

    class?MyFlutterView(context:?Context,?messenger:?BinaryMessenger,?viewId:?Int,?args:?Map<String,?Any>?)?:?PlatformView?{

    ????val?textView:?TextView?=?TextView(context)

    ????init?{
    ????????args?.also?{
    ????????????textView.text?=?it["text"]?as?String
    ????????}
    ????}

    ????override?fun?getView():?View?{

    ????????return?textView
    ????}

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

    ????

    最終效果:


    Flutter 向 Android View 發(fā)送消息

    修改 Flutter 端,創(chuàng)建 「MethodChannel」 用于通信:

    class?PlatformViewDemo?extends?StatefulWidget?{
    ??@override
    ??_PlatformViewDemoState?createState()?=>?_PlatformViewDemoState();
    }

    class?_PlatformViewDemoState?extends?State<PlatformViewDemo>?{
    ??static?const?platform?=
    ??????const?MethodChannel('com.flutter.guide.MyFlutterView');

    ??@override
    ??Widget?build(BuildContext?context)?{
    ????Widget?platformView()?{
    ??????if?(defaultTargetPlatform?==?TargetPlatform.android)?{
    ????????return?AndroidView(
    ??????????viewType:?'plugins.flutter.io/custom_platform_view',
    ??????????creationParams:?{'text':?'Flutter傳給AndroidTextView的參數(shù)'},
    ??????????creationParamsCodec:?StandardMessageCodec(),
    ????????);
    ??????}
    ????}

    ????return?Scaffold(
    ??????appBar:?AppBar(),
    ??????body:?Column(children:?[
    ????????RaisedButton(
    ??????????child:?Text('傳遞參數(shù)給原生View'),
    ??????????onPressed:?()?{
    ????????????platform.invokeMethod('setText',?{'name':?'laomeng',?'age':?18});
    ??????????},
    ????????),
    ????????Expanded(child:?platformView()),
    ??????]),
    ????);
    ??}
    }
    ????

    在 原生View 中也創(chuàng)建一個 「MethodChannel」 用于通信:

    class?MyFlutterView(context:?Context,?messenger:?BinaryMessenger,?viewId:?Int,?args:?Map<String,?Any>?)?:?PlatformView,?MethodChannel.MethodCallHandler?{

    ????val?textView:?TextView?=?TextView(context)
    ????private?var?methodChannel:?MethodChannel

    ????init?{
    ????????args?.also?{
    ????????????textView.text?=?it["text"]?as?String
    ????????}
    ????????methodChannel?=?MethodChannel(messenger,?"com.flutter.guide.MyFlutterView")
    ????????methodChannel.setMethodCallHandler(this)
    ????}

    ????override?fun?getView():?View?{

    ????????return?textView
    ????}

    ????override?fun?dispose()?{
    ????????methodChannel.setMethodCallHandler(null)
    ????}

    ????override?fun?onMethodCall(call:?MethodCall,?result:?MethodChannel.Result)?{
    ????????if?(call.method?==?"setText")?{
    ????????????val?name?=?call.argument("name")?as?String?
    ????????????val?age?=?call.argument("age")?as?Int?

    ????????????textView.text?=?"hello,$name,年齡:$age"
    ????????}?else?{
    ????????????result.notImplemented()
    ????????}
    ????}
    }

    Flutter 向 Android View 獲取消息

    與上面發(fā)送信息不同的是,F(xiàn)lutter 向原生請求數(shù)據(jù),原生返回數(shù)據(jù)到 Flutter 端,修改 「MyFlutterView onMethodCall」

    override?fun?onMethodCall(call:?MethodCall,?result:?MethodChannel.Result)?{
    ????if?(call.method?==?"setText")?{
    ????????val?name?=?call.argument("name")?as?String?
    ????????val?age?=?call.argument("age")?as?Int?
    ????????textView.text?=?"hello,$name,年齡:$age"
    ????}?else?if?(call.method?==?"getData")?{
    ????????val?name?=?call.argument("name")?as?String?
    ????????val?age?=?call.argument("age")?as?Int?

    ????????var?map?=?mapOf("name"?to?"hello,$name",
    ????????????????"age"?to?"$age"
    ????????)
    ????????result.success(map)
    ????}?else?{
    ????????result.notImplemented()
    ????}
    }

    ????

    「result.success(map)」 是返回的數(shù)據(jù)。

    Flutter 端接收數(shù)據(jù):

    var?_data?=?'獲取數(shù)據(jù)';

    RaisedButton(
    ??child:?Text('$_data'),
    ??onPressed:?()?async?{
    ????var?result?=?await?platform
    ????????.invokeMethod('getData',?{'name':?'laomeng',?'age':?18});
    ????setState(()?{
    ??????_data?=?'${result['name']},${result['age']}';
    ????});
    ??},
    ),

    ????


    解決多個原生View通信沖突問題

    當(dāng)然頁面有3個原生View,

    class?PlatformViewDemo?extends?StatefulWidget?{
    ??@override
    ??_PlatformViewDemoState?createState()?=>?_PlatformViewDemoState();
    }

    class?_PlatformViewDemoState?extends?State<PlatformViewDemo>?{
    ??static?const?platform?=
    ??????const?MethodChannel('com.flutter.guide.MyFlutterView');

    ??var?_data?=?'獲取數(shù)據(jù)';

    ??@override
    ??Widget?build(BuildContext?context)?{
    ????Widget?platformView()?{
    ??????if?(defaultTargetPlatform?==?TargetPlatform.android)?{
    ????????return?AndroidView(
    ??????????viewType:?'plugins.flutter.io/custom_platform_view',
    ??????????creationParams:?{'text':?'Flutter傳給AndroidTextView的參數(shù)'},
    ??????????creationParamsCodec:?StandardMessageCodec(),
    ????????);
    ??????}
    ????}

    ????return?Scaffold(
    ??????appBar:?AppBar(),
    ??????body:?Column(children:?[
    ????????Row(
    ??????????children:?[
    ????????????RaisedButton(
    ??????????????child:?Text('傳遞參數(shù)給原生View'),
    ??????????????onPressed:?()?{
    ????????????????platform
    ????????????????????.invokeMethod('setText',?{'name':?'laomeng',?'age':?18});
    ??????????????},
    ????????????),
    ????????????RaisedButton(
    ??????????????child:?Text('$_data'),
    ??????????????onPressed:?()?async?{
    ????????????????var?result?=?await?platform
    ????????????????????.invokeMethod('getData',?{'name':?'laomeng',?'age':?18});
    ????????????????setState(()?{
    ??????????????????_data?=?'${result['name']},${result['age']}';
    ????????????????});
    ??????????????},
    ????????????),
    ??????????],
    ????????),
    ????????Expanded(child:?Container(color:?Colors.red,?child:?platformView())),
    ????????Expanded(child:?Container(color:?Colors.blue,?child:?platformView())),
    ????????Expanded(child:?Container(color:?Colors.yellow,?child:?platformView())),
    ??????]),
    ????);
    ??}
    }
    ????

    此時點擊 「傳遞參數(shù)給原生View」 按鈕哪個View會改變內(nèi)容,實際上只有最后一個會改變。


    如何改變指定View的內(nèi)容?重點是 「MethodChannel」,只需修改上面3個通道的名稱不相同即可:

    • 「第一種方法」:將一個唯一 id 通過初始化參數(shù)傳遞給原生 View,原生 View使用這個id 構(gòu)建不同名稱的 「MethodChannel」
    • 「第二種方法(推薦)」:原生 View 生成時,系統(tǒng)會為其生成唯一id:viewId,使用 viewId 構(gòu)建不同名稱的 「MethodChannel」。

    原生 View 使用 viewId 構(gòu)建不同名稱的 「MethodChannel」

    class?MyFlutterView(context:?Context,?messenger:?BinaryMessenger,?viewId:?Int,?args:?Map<String,?Any>?)?:?PlatformView,?MethodChannel.MethodCallHandler?{

    ????val?textView:?TextView?=?TextView(context)
    ????private?var?methodChannel:?MethodChannel

    ????init?{
    ????????args?.also?{
    ????????????textView.text?=?it["text"]?as?String
    ????????}
    ????????methodChannel?=?MethodChannel(messenger,?"com.flutter.guide.MyFlutterView_$viewId")
    ????????methodChannel.setMethodCallHandler(this)
    ????}
    ??...
    }
    ????

    Flutter 端為每一個原生 View 創(chuàng)建不同的「MethodChannel」

    var?platforms?=?[];

    AndroidView(
    ??viewType:?'plugins.flutter.io/custom_platform_view',
    ??onPlatformViewCreated:?(viewId)?{
    ????print('viewId:$viewId');
    ????platforms
    ????????.add(MethodChannel('com.flutter.guide.MyFlutterView_$viewId'));
    ??},
    ??creationParams:?{'text':?'Flutter傳給AndroidTextView的參數(shù)'},
    ??creationParamsCodec:?StandardMessageCodec(),
    )

    ????

    給第一個發(fā)送消息:

    platforms[0]
    ????.invokeMethod('setText',?{'name':?'laomeng',?'age':?18});


    瀏覽 107
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    久久国产性爱 | 日本在线观看 | 日本日逼黄色 | 无码高清一区二区 | 日韩精品免费一区二区三区竹菊 |