Flutter中显示原生系统的视图控件

Flutter、Golang、Python、编译原理、算法、Chrome原理学习系列文章抢先看请关注【码农帮派】

 

Flutter接管了应用渲染层,方法通道可以获得原生底层能力,对于需要底层渲染的视图,比如浏览器、相机、地图以及一些原生自定义视图,我们自己在Flutter上再实现一遍,需要花费大量的精力。

 

为了复用原生系统已有的视图,我们可以采用混合视图的方式,我们在Flutter的Widget树中提前预留一块空白区域,在Flutter画板(即FlutterView/FlutterViewController)中嵌入一个与空白区域完全匹配的原生视图。但这种方案,由于嵌入的视图不在Flutter的渲染层级中,需要Flutter和原生宿主App上做大量的适配工作。

 

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

 

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

 

平台视图

为了解决Flutter层复用原生控件的问题,Flutter提供了平台视图(Platform View)让我们可以通过简单的Dart接口,将Android/iOS平台的原生视图插入到Flutter的渲染树中,实现Flutter视图和原生视图的混用。

一次完整的平台视图调用的流程(平台视图的使用过程和方法通道使用过程大致相似,也和一次网络请求类似):

  • 首先,Flutter通过向原生视图的Flutter封装类(Android上是AndroidView、iOS上是UIKitView)传入视图标志符,用于发起创建原生视图的请求;

  • 然后,原生系统接收到请求,创建原生视图,交给平台视图工厂类(PlatformViewFactory)实现;

  • 最后,原生系统将视图标识符和平台视图工厂类进行关联,让Flutter发起的原生视图创建请求可以直接找到对应的视图创建工厂。

 

Flutter实现平台视图调用接口

在Flutter中,针对不同的平台使用对应的视图封装类(Android使用AndroidView、iOS使用UIKitView),发送创建对应平台的原生视图,并传入视图的唯一标识符,用来建立和原生视图的关联:

上面的是Flutter端调用原生系统控件的代码,可以看出,Flutter端使用原生系统控件与普通的Flutter控件无明显差异,只是需要根据当前的平台使用AndroidView和UIKitView进行原生控件的调用。

 

Flutter端的代码实现了,剩下的就是Android、iOS端的控件实现了。在Flutter引用的原生宿主入口处,我们需要注册一个监听接口,用来监听来自Flutter的平台视图创建请求,当接收到请求之后,按照viewType(AndroidView/UIKitView中传递的viewType参数),来决定调用哪个视图工厂类,被调用的视图工厂类在其create方法中返回一个原生视图的封装类类,在该原生视图封装类中生成原生视图。Flutter在获得这个原生视图之后,已经是在Flutter层面的控件,就可以像普通控件一样加入到Flutter渲染树中。

 

Android端实现平台视图

首先是视图工厂类SampleViewFactory.java,在视图工厂类的create方法中返回一个原生视图封装类:

之后是原生视图封装类SimpleViewController.java,在这个类中我们创建并返回对应的原生视图:

在上面代码的第8行,可以初始化生成你需要的Android原生视图,比如地图控件等。

 

最后,我们需要绑定监听来自Flutter端的调用平台视图的请求,和方法通道一样,我们仍然是在原生宿主的Flutter入口处(MainActivity.java)进行注册:

这样Android端就可以监听到来自Flutter端的平台视图调用请求,并通过视图工厂/视图封装类生成原生视图,并将其返回给Flutter端,以Flutter控件的方式加入到Flutter层的渲染树进行渲染。

 

iOS端实现平台视图

首先,是平台视图封装类SampleViewController.m:

然后是平台视图工厂类SampleViewFactory.m:

最后需要在原生宿主的Flutter入口处进行接口注册(AppDelegate.m):

【注意】

在iOS平台上,Flutter内嵌UIKitView还处于技术预览的状态,因此我们若要在iOS平台上使用平台视图,还需要在Info.plist文件中开启:

<dic>    ...    <key>io.flutter.embedded_views_preview</key>    <true/></dic>

之后我们就可以在Flutter中使用平台视图了:​​​​​​​

Scaffold(    backgroundColor: Colors.yellow,    body: Container(        width: 200,        height: 200,        child: SampleView(),    ),);

代码实现效果:

上面的代码实现了在Flutter端,通过平台视图显示原生系统的视图控件,如何实现Flutter和平台视图的交互呢,这就要使用方法通道。

 

我们知道Android/iOS的视图控件状态的改变是命令式的,所以我们可以在原生视图封装类中将修改视图实例的接口,以方法通道的方式暴露给Flutter,从而让Flutter可以修改原生视图的状态。

 

下面的例子中在Flutter端创建了一个原生视图控制器,通过方法通道,实现与平台视图的交互:

然后声明Flutter端的StatefulWidget控件:

 

Android端的代码实现:

 

iOS端代码的实现:

之后我们就可以在Flutter中实现平台视图的通信了:

class DefaultState extends State<DefaultPage> {
    NativeViewController _controller;

    @override
    void initState() {
        // 初始化原生 View 控制器
        _controller = NativeViewController();
        super.initState();
    }

    @override
    Widget build(BuildContext context) {
      return Scaffold(
           // ...
           // 内嵌原生 View
           body:  Container(
               width: 200, 
               height:200,
               child: SampleView(controller: _controller)
           ),
           // 设置点击行为:改变视图颜色 
           floatingActionButton: FloatingActionButton(onPressed: () {
                _controller.changeBackgroundColor();
           }),
      );
    }
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值