美文网首页Android开发Flutter圈子Android开发经验谈
Flutter中如何使用原生控件或组件

Flutter中如何使用原生控件或组件

作者: 闲庭 | 来源:发表于2020-04-25 22:51 被阅读0次

    开发集成环境
    [✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Mac OS X 10.14.6 18G103, locale zh-Hans-CN)

    一、简述Flutter集成到Android原生项目
    二、Android原生以AAR形式集成Flutter项目
    三、Flutter与原生(Android/IOS)的消息通信
    四、Flutter中如何使用原生控件/组件
    五、Flutter状态管理Provider与Redux
    六、Flutter升级及开发中遇到的问题汇总

    为了解决在Flutter上复用原生视图的问题,Flutter提供了平台视图(Platform View)。通过平台视图,我们可以将原生控件包装成Flutter控件,从而加入到Flutter的渲染树中,获得与Flutter控件一致的用户体验。

    方法通道(MethodChannel)解决的是Flutter与原生系统之间的逻辑通信问题,平台视图(PlatformView)解决的是Flutter与原生系统之间的视图复用问题。

    一、完整的平台视图调用的流程:

    平台视图的使用过程和方法通道使用过程大致相似,流程如下:

    1. Flutter通过向原生视图的Flutter封装类(Android上是AndroidView、iOS上是UIKitView)传入视图标志符,用于发起创建原生视图的请求;
    2. 原生系统接收到请求,创建原生视图,交给平台视图工厂类(PlatformViewFactory)实现;
    3. 原生系统将视图标识符和平台视图工厂类进行关联,让Flutter发起的原生视图创建请求可以直接找到对应的视图创建工厂。

    二、如何在Android项目中注册原生组件

    大致逻辑流程如下:

    1. 实现原生组件PlatformView提供原生view
    2. 创建PlatformViewFactory用于生成PlatformView
    3. 创建FlutterPlugin用于注册原生组件
    4. 在容器页注册FlutterPlugin
    5. Flutter中开始使用原生View,展示及修改对应属性。

    具体实现步骤如下:

    1、实现原生组件PlatformView提供原生view

    package com.liujc.testapplication.flutter.androidview;
    
    import android.content.Context;
    import android.support.annotation.NonNull;
    import android.view.View;
    import android.widget.TextView;
    
    import java.util.Map;
    
    import io.flutter.plugin.common.BinaryMessenger;
    import io.flutter.plugin.common.MethodCall;
    import io.flutter.plugin.common.MethodChannel;
    import io.flutter.plugin.platform.PlatformView;
    
    import static com.liujc.testapplication.util.CCViewPlugin.NATIVE_CCTV_VIEW_TYPE_ID;
    
    /**
     * @author liujc
     * @date 2020/3/28
     * @Description 此处封装原生的TextView给Flutter使用
     */
    public class CCTextView implements PlatformView, MethodChannel.MethodCallHandler {
    
        private final TextView myNativeView;
    
        CCTextView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params) {
            TextView myNativeView = new TextView(context);
            myNativeView.setText("我是来自Android的原生TextView");
            this.myNativeView = myNativeView;
            if (params.containsKey("myContent")) {
                String myContent = (String) params.get("myContent");
                myNativeView.setText(myContent);
            }
            MethodChannel methodChannel = new MethodChannel(messenger, NATIVE_CCTV_VIEW_TYPE_ID+"_" + id);
            methodChannel.setMethodCallHandler(this);
        }
    
        @Override
        public View getView() {
            return myNativeView;
        }
    
        @Override
        public void dispose() {
    
        }
    
        @Override
        public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
            System.out.println("CCTextView MethodChannel call.method:"+methodCall.method+ "  call arguments:"+methodCall.arguments);
            if ("setText".equals(methodCall.method)) {
                String text = (String) methodCall.arguments;
                myNativeView.setText(text);
                result.success("修改成功");
            }
        }
    
    }
    
    

    2、 创建PlatformViewFactory用于生成PlatformView

    package com.liujc.testapplication.flutter.androidview;
    
    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;
    
    /**
     * @author liujc
     * @date 2020/3/28
     * @Description 用于生成PlatformView
     */
    public class CCViewFactory extends PlatformViewFactory {
        /**
         * @param messenger the codec used to decode the args parameter of {@link #create}.
         */
        private final BinaryMessenger messenger;
    
        public CCViewFactory(BinaryMessenger messenger) {
            super(StandardMessageCodec.INSTANCE);
            this.messenger = messenger;
        }
    
        @Override
        public PlatformView create(Context context, int viewId, Object args) {
            Map<String, Object> params = (Map<String, Object>) args;
            return new CCTextView(context, messenger, viewId, params);
        }
    
    
    }
    
    

    3、创建FlutterPlugin用于注册原生组件

    package com.liujc.testapplication.flutter.androidview;
    
    import com.liujc.testapplication.util.AhsNativePlugin;
    
    import io.flutter.embedding.engine.FlutterEngine;
    import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry;
    import io.flutter.plugin.common.PluginRegistry;
    
    
    /**
     * @author liujc
     * @date 2020/3/10
     * @Description 用户注册原生组件
     */
    public class CCViewPlugin{
    
        public static String NATIVE_CCTV_VIEW_TYPE_ID = "com.cc.flutter/cctextview";//原生控件对应的viewtypeid
        ///
        /// @Params:
        /// @Desc: 兼容1.12以前旧版本
        ///
        public static void registerWith(PluginRegistry registry) {
            final String key = AhsNativePlugin.class.getCanonicalName();
            if (registry.hasPlugin(key)){
                return;
            }
    
            PluginRegistry.Registrar registrar = registry.registrarFor(key);
            registrar.platformViewRegistry().registerViewFactory(NATIVE_CCTV_VIEW_TYPE_ID, new CCViewFactory(registrar.messenger()));
        }
    
        ///
        /// @Params:
        /// @Desc: 新版本注册方式
        ///
        public static void registerWith(FlutterEngine flutterEngine) {
            final String key = CCViewPlugin.class.getCanonicalName();
            ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
    
            if (shimPluginRegistry.hasPlugin(key)){
                return;
            }
    
            PluginRegistry.Registrar registrar = shimPluginRegistry.registrarFor(key);
            registrar.platformViewRegistry().registerViewFactory(NATIVE_CCTV_VIEW_TYPE_ID, new CCViewFactory(registrar.messenger()));
        }
    }
    

    4、 将封装的原生View注册给Flutter使用

    public class MainActivity extends FlutterActivity {
      @Override
      public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        CCViewPlugin.registerWith(flutterEngine);
        }
    }
    

    5、在Flutter中使用CCTextView

    Container(
        width: deviceUtil.setWidth(200),
        height: deviceUtil.setHeight(100),
        child: AndroidView(viewType: "com.cc.flutter/cctextview",
          creationParams: {
          "myContent": "我是flutter通过参数传入的文本内容",
          },
          creationParamsCodec: const StandardMessageCodec(),
          onPlatformViewCreated: onCCViewCreated, //初始化
        ),
      )
      
      //具体根据平台判断 defaultTargetPlatform == TargetPlatform.android
    

    初始化MethodChannel信息,用来更新CCTextView的属性值

      MethodChannel _channel;
    
      void onCCViewCreated(int id) {
        _channel = new MethodChannel('com.aihuishou.business/cctextview_$id');
        setMyViewText("默认值");
      }
    
      //调用setCCViewText可执行setText方法,对应上面CCTextView的onMethodCall对应接收操作
      Future<void> setCCViewText(String text) async {
        assert(text != null);
        return _channel.invokeMethod('setText', text);
      }
    

    相关文章

      网友评论

        本文标题:Flutter中如何使用原生控件或组件

        本文链接:https://www.haomeiwen.com/subject/kpyhphtx.html