写点什么

Agora Flutter SDK:一套代码,实现双端通话(二)

  • 2019-11-30
  • 本文字数:2586 字

    阅读完需:约 8 分钟

Agora Flutter SDK:一套代码,实现双端通话(二)

绿色部分为我们定义的 Stingy,红色小方块为 Stingy 的 child ,这里是一个 Container


代码中的输入如下 (iphone 6 尺寸):


flutter: constraints: BoxConstraints(100.0<=w<=375.0, 100.0<=h<=300.0)flutter: childParentData: offset=Offset(275.0, 200.0)flutter: size: Size(375.0, 300.0)
复制代码


上述我们自定义 RenderBox 的 performLayout() 中做的事情可大概分为如下三个步骤:


  • 使用 child.layout(…) 来布局 child,这里是为 child 根据 parent 传递过来的约束选择一个大小

  • child.parentData.offset , 这是在为 child 如何摆放设置一个偏移量

  • 设置当前 widget 的 size


在我们的例子中,Stingy 的 child 是一个 Container,并且 Container 没有 child,因此他会使用 child.layout(…) 中设置的最大约束。通常,每个 widget 都会以不同的方式来处理提供给他的约束。如果我们使用 RaiseButton 替换 Container:


Stingy(    child: RaisedButton(      child: Text('Button'),    onPressed: (){}  )  )
复制代码


效果如下:



可以看到,RaisedButton 的 width 使用了 parent 给他传递的约束值 100,但是高度很明显没有 100,RaisedButton 的高度默认为 48 ,由此可见 RaisedButton 内部对 parent 传递过来的约束做了一些处理。


我们上面的 Stingy 继承的是 SingleChildRenderObjectWidget,也就是只能有一个 child。那如果有多个 child 怎么办,不用担心,这里还有一个 MultiChildRenderObjectWidget,而这个类有一个子类叫做 CustomMultiChildLayout,我们直接用这个子类就好。


先来看看 CustomMultiChildLayout 的构造方法如下:


/// The [delegate] argument must not be null.
CustomMultiChildLayout({ Key key, @required this.delegate, List<Widget> children = const <Widget>[],})
复制代码


  • key:widget 的一个标记,可以起到标识符的作用

  • delegate:这个特别重要,注释上明确指出这个参数一定不能为空,我们在下会说

  • children:这个就很好理解了,他是一个 widget 数组,也就是我们们需要渲染的 widget


上面的 delegate 参数类型如下:


  /// The delegate that controls the layout of the children.  final MultiChildLayoutDelegate delegate;
复制代码


可以看出 delegate 的类型为 MultiChildLayoutDelegate,并且注释也说明了它的作用:控制 children 的布局。也就是说,我们的 CustomMultiChildLayout 里面要怎么布局,完全取决于我们自定义的 MultiChildLayoutDelegate 里面的实现。所以 MultiChildLayoutDelegate 中也会有类似的 performLayout(…) 方法。


另外,CustomMultiChildLayout 中的每个 child 必须使用 LayoutId 包裹,注释如下:


/// Each child must be wrapped in a [LayoutId] widget to identify the widget for  /// the delegate.
复制代码


LayoutId 的构造方法如下:


  /// Marks a child with a layout identifier.  /// Both the child and the id arguments must not be null.  LayoutId({    Key key,    @required this.id,        @required Widget child  })
复制代码


注释的大概意思说的是:使用一个布局标识来标识一个 child;参数 child 和 参数 id 不定不能为空。 我们在布局 child 的时候会根据 child 的 id 来布局。


下面我们来使用 CustomMultiChildLayout 实现一个用于展示热门标签的效果:


Container(   child: CustomMultiChildLayout(     delegate: _LabelDelegate(itemCount: items.length, childId: childId),     children: items,   ), )
复制代码


我们的 _LabelDelegate 里面接受两个参数,一个为 itemCount,还有是 childId。


_LabelDelegate 代码如下:


class _LabelDelegate extends MultiChildLayoutDelegate {  final int itemCount;  final String childId;    // x 方向上的偏移量  double dx = 0.0;    // y 方向上的偏移量  double dy = 0.0;
_LabelDelegate({@required this.itemCount, @required this.childId}); @override void performLayout(Size size) { // 获取父控件的 width double parentWidth = size.width; for (int i = 0; i < itemCount; i++) { // 获取子控件的 id String id = '${this.childId}$i'; // 验证该 childId 是否对应一个 非空的 child if (hasChild(id)) { // layout child 并获取该 child 的 size Size childSize = layoutChild(id, BoxConstraints.loose(size)); // 换行条件判断 if (parentWidth - dx < childSize.width) { dx = 0; dy += childSize.height; } // 根据 Offset 来放置 child positionChild(id, Offset(dx, dy)); dx += childSize.width; } } } /// 该方法用来判断重新 layout 的条件 @override bool shouldRelayout(_LabelDelegate oldDelegate) { return oldDelegate.itemCount != this.itemCount; }}
复制代码


在 _LabelDelegate 中,重写了 performLayout(…) 方法。方法中有一个参数 size,这个 size 表示的是当前 widget 的 parent 的 size,在我们这个例子中也就表示 Container 的 size。我们可以看看 performLayout(…)方法的注释:


  /// Override this method to lay out and position all children given this  /// widget's size.  ///  /// This method must call [layoutChild] for each child. It should also specify  /// the final position of each child with [positionChild].  void performLayout(Size size);
复制代码


还有一个是 hasChild(…) 方法,这个方法接受一个 childId,childId 是由我们自己规定的,这个方法的作用是判断当前的 childId 是否对应着一个非空的 child。


满足 hasChild(…) 之后,接着就是 layoutChild(…) 来布局 child , 这个方法中我们会传递两个参数,一个是 childId,另外一个是 child 的约束(Constraints),这个方法返回的是当前这个 child 的 Size。


布局完成之后,就是如何摆放的问题了,也就是上述代码中的 positionChild(…) 了,此方法接受一个 childId 和 一个当前 child 对应的 Offset,parent 会根据这个 Offset 来放置当前的 child。


最后我们重写了 shouldRelayout(…) 方法用于判断重新 Layout 的条件。


完整源码在文章末尾给出。


效果如下:


2 Flutter 和 Native 的交互

我们这里说的 Native 指的是 Android 平台。


2019-11-30 15:04821

评论

发布
暂无评论
发现更多内容

使用CSS绘制一支口红

战场小包

CSS 口红 2月月更

这把“锁”不简单,让你畅游数字世界

华为云开发者联盟

SSL证书 ssl HTTP协议 HTTPS协议加密

直播预告 | PolarDB-X 动手实践系列——如何在 PolarDB-X 中进行 Online DDL

阿里云数据库开源

数据库 阿里云 开源 polarDB

Apache ShardingSphere 企业行|走进搜狐

SphereEx

数据库 开源 ShardingSphere SphereEx 搜狐

无需编程,基于PostgreSQL零代码生成CRUD增删改查RESTful API接口

crudapi

postgresql API crud crudapi 抽象工厂设计模式

Clusterpedia 加持 kubectl,检索多集群资源

Daocloud 道客

云原生 开源项目 K8s 多集群管理

ZEGO音视频服务的高可用架构设计与运营

ZEGO即构

架构 后台 高可用架构 音视频开发

人才短缺、成本高昂,制造企业智能化转型路径如何破局?

百度开发者中心

前端SSR的落地实践

百度Geek说

百度 前端 SSR

2种图像增强方法:图像点运算和图像灰度化处理

华为云开发者联盟

图像处理 图像 图像增强 图像点运算 灰度化处理

海关监管区域之陆路口岸作业

Geek_XOXO

国际贸易 海关监管 口岸

超27亿人参与!“云上冬奥”背后的技术革新

阿里云弹性计算

阿里云 冬奥会

k8s 源码Client-go中Reflector解析

华为云开发者联盟

Kubernetes Informer 事件 Client-go Reflector

系统学习 TypeScript(二)——开发流程和语法规则

编程三昧

typescript 前端 2月月更

海关监管区域之港口作业

Geek_XOXO

国际贸易 海关监管 港口作业

百度可观测系列 | 采集亿级别指标,Prometheus 集群方案这样设计

百度开发者中心

超硬核攻略!《2022金融云原生落地实用指南》重磅发布(限时免费下载)

York

如何通过 Jira Service Management 打造员工自助服务工具实现高效分布式工作

Atlassian

敏捷 Jira 远程协作 ITSM 开发管理

GPUSHARE-会员重磅上线啦~

恒源云

gpu 学生党

【元宵节快乐】Apache ShardingSphere 企业行|走进陌陌

SphereEx

数据库 开源 企业 ShardingSphere SphereEx

混合多云环境下的云成本管理与优化

鲸品堂

成本优化 实践案例 云资源

F6 汽车科技基于 Apache ShardingSphere 的核心业务分库分表实践

SphereEx

Apache 数据库 开源 ShardingSphere SphereEx

三维仿真智慧服务器 —— 信息安全监控平台

一只数据鲸鱼

信息安全 数据中心 数据可视化 智慧城市

美容机构预约小程序设计方案

CC同学

一周信创舆情观察(2.14~2.20)

统小信uos

FinClip邀你来出战|Hackthon Coding Party 一触即发

FinClip

【WEB安全】轻松检测钓鱼网站的技巧#建议收藏#

H

网络安全 WEB安全 钓鱼网站

创新推出 | Serverless 调试大杀器:端云联调

Serverless Devs

从 generator 的角度看 Rust 异步代码

SOFAStack

rust Generator

CNCF 沙箱项目 OCM Placement 多集群调度指南

阿里巴巴云原生

阿里云 云原生 OCM Placement

Agora Flutter SDK:一套代码,实现双端通话(二)_文化 & 方法_声网_InfoQ精选文章