flutter学习之嵌入原生View - android

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

  • 本文主要介绍如何在 flutter中加载原生android的view,之前我们介绍了flutter加载iOS view。原理也是类似。

1. 创建android中view

我们是iOS开发,这里简单介绍下如何加载原生android的view,其流程和我们iOS view类似。

我们在android项目的创建一个测试view

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<String, Any>?) :
    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

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>?)
    }

}

创建TestPlugin

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 中注册:

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

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传值

AndroidView(
  viewType: 'plugins.flutter.io/custom_platform_view',
   creationParams: {'text': 'Flutter传给Android中TextView的参数'},
   creationParamsCodec: StandardMessageCodec(),
);

这里viewType就是我们注册的时候使用的标识符creationParams为创建AndroidView时带的参数creationParamsCodec:将 creationParams 编码后再发送给平台侧,它应该与传递给构造函数的编解码器匹配

我们在Android项目中TestView判断是否传递了参数

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

image.png 我们在运行中通过按钮点击改变AndroidView的内容

static const platform = MethodChannel('com.flutter.test.TestView');

我们在flutter页面定义一个方法通道

RaisedButton( child: const Text('传递参数给原生View'), onPressed: () { platform.invokeMethod('userInfo', {'name': 'Jack', 'city': "New York"}); },

点击的时候传参给Android页面,我们在onMethodCall方法中获取我们的参数

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方法等进行交互回调函数的相互回调实现通信

猜你喜欢

转载自juejin.im/post/7113187699028131877