创建网格(Grid/GridItem)

目录

1、概述

2、布局与约束

3、设置排列方式

3.1设置行列数量与占比

3.2、设置子组件所占行列数

3.3、设置主轴方向

 3.4、在网格布局中显示数据

3.5、设置行列间距

4、构建可滚动的网格布局

5、实现简单的日历功能

6、性能优化


1、概述

        网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。

        ArkUI提供了Grid容器组件和子组件GridItem,用于构建网格布局。Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。Grid组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。

2、布局与约束

        Grid组件为网格容器,其中容器内每一个条目对应一个GridItem组件,如下图所示。

图1 Grid与GridItem组件关系

说明

Grid的子组件必须是GridItem组件。

        网格布局是一种二维布局。Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。当网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,从而实现网格布局的自适应能力。根据Grid的这些布局能力,可以构建出不同样式的网格布局,如下图所示。

图2 网格布局

        如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。

Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:

  • 行、列数量与占比同时设置:Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)
  • 只设置行、列数量与占比中的一个:元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。
  • 行列数量与占比都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且Grid不可滚动。

3、设置排列方式

3.1设置行列数量与占比

        通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。

        rowsTemplate和columnsTemplate属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列的宽度。

图3 行列数量占比示例

        如上图所示,构建的是一个三行三列的的网格布局,其在垂直方向上分为三等份,每行占一份;在水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份。

        只要将rowsTemplate的值为'1fr 1fr 1fr',同时将columnsTemplate的值为'1fr 2fr 1fr',即可实现上述网格布局。

@Entry
@Component
struct GridLayoutPage1 {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text(`1`).gridTextStyle("#1067c8ff")}GridItem() {Text(`2`).gridTextStyle("#2067c8ff")}GridItem() {Text(`3`).gridTextStyle("#3067c8ff")}GridItem() {Text(`4`).gridTextStyle("#4067c8ff")}GridItem() {Text(`5`).gridTextStyle("#5067c8ff")}GridItem() {Text(`6`).gridTextStyle("#6067c8ff")}GridItem() {Text(`7`).gridTextStyle("#7067c8ff")}GridItem() {Text(`8`).gridTextStyle("#8067c8ff")}GridItem() {Text(`9`).gridTextStyle("#9067c8ff")}}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 2fr 1fr')}.width('100%')}.height('40%')}
}@Extend(Text) function gridTextStyle(value: ResourceColor) {.backgroundColor(value).width('100%').height('100%').fontSize(22).textAlign(TextAlign.Center)
}

        效果如下:

 

3.2、设置子组件所占行列数

        除了大小相同的等比例网格布局,由不同大小的网格组成不均匀分布的网格布局场景在实际应用中十分常见,如下图所示。在Grid组件中,通过设置GridItem的rowStart、rowEnd、columnStart和columnEnd可以实现如图所示的单个网格横跨多行或多列的场景。

图4 不均匀网格布局

        例如计算器的按键布局就是常见的不均匀网格布局场景。如下图,计算器中的按键“0”和“=”,按键“0”横跨第一、二两列,按键“=”横跨第五、六两行。使用Grid构建的网格布局,其行列标号从1开始,依次编号。

图5 计算器

        在单个网格单元中,rowStart和rowEnd属性表示指定当前元素起始行号和终点行号,columnStart和columnEnd属性表示指定当前元素的起始列号和终点列号。

        所以“0”按键横跨第一列和第二列,只要将“0”对应GridItem的columnStart和columnEnd设为1和2,将“=”对应GridItem的的rowStart和rowEnd设为5和6即可。

        “=”按键横跨第五行和第六行,只要将将“=”对应GridItem的的rowStart和rowEnd设为5和6即可。

@Entry
@Component
struct CalculatorLayoutPage {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text(`0`).gridTextStyle2("#1067c8ff").textAlign(TextAlign.End).padding(2)}.rowStart(0).rowEnd(1).columnStart(0).columnEnd(3)GridItem() {Text(`CE`).gridTextStyle2("#2067c8ff")}GridItem() {Text(`C`).gridTextStyle2("#3067c8ff")}GridItem() {Text(`/`).gridTextStyle2("#4067c8ff")}GridItem() {Text(`X`).gridTextStyle2("#5067c8ff")}GridItem() {Text(`7`).gridTextStyle2("#6067c8ff")}GridItem() {Text(`8`).gridTextStyle2("#7067c8ff")}GridItem() {Text(`9`).gridTextStyle2("#8067c8ff")}GridItem() {Text(`-`).gridTextStyle2("#9067c8ff")}GridItem() {Text(`4`).gridTextStyle2("#A067c8ff")}GridItem() {Text(`5`).gridTextStyle2("#B067c8ff")}GridItem() {Text(`6`).gridTextStyle2("#C067c8ff")}GridItem() {Text(`+`).gridTextStyle2("#D067c8ff")}GridItem() {Text(`1`).gridTextStyle2("#E067c8ff")}GridItem() {Text(`2`).gridTextStyle2("#F067c8ff")}GridItem() {Text(`3`).gridTextStyle2("#F167c8ff")}GridItem() {Text(`=`).gridTextStyle2("#F267c8ff")}.rowStart(5).rowEnd(6).columnStart(3).columnEnd(3)GridItem() {Text(`0`).gridTextStyle2("#F367c8ff")}.columnStart(0).columnEnd(1)GridItem() {Text(`.`).gridTextStyle2("#F467c8ff")}}.margin(12).rowsGap(12).columnsGap(8).rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr')}.width('100%')}.height('80%')}
}@Extend(Text) function gridTextStyle2(value: ResourceColor) {.backgroundColor(value).width('100%').height('100%').fontSize(40).textAlign(TextAlign.Center).borderRadius(5)
}

         效果如下:

3.3、设置主轴方向

        使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。

图6 主轴方向示意图

        当前layoutDirection设置为Row时,先从左到右排列,排满一行再排一下一行。当前layoutDirection设置为Column时,先从上到下排列,排满一列再排一下一列,如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。

@Entry
@Component
struct GridLayoutPage2 {@State array: Array<string> = ['1', '2', '3', '4', '5', '6', '7', '8', '9']build() {Row() {Column() {Grid() {ForEach(this.array, (item: string, index) => {GridItem() {Text(item).gridTextStyle_page2('#67c8ff')}}, item => item)}.rowsGap(12).columnsGap(8).margin(4).maxCount(3).minCount(3).layoutDirection(GridDirection.Column)}.width('100%')}.height('40%')}
}@Extend(Text) function gridTextStyle_page2(value: ResourceColor) {.backgroundColor(value).width('30%').height('30%').fontSize(22).textAlign(TextAlign.Center)
}

        效果如下:

说明

1. layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效,此时元素在layoutDirection方向上排列。

2. 仅设置rowsTemplate时,Grid主轴为水平方向,交叉轴为垂直方向。

2. 仅设置columnsTemplate时,Grid主轴为垂直方向,交叉轴为水平方向。

 3.4、在网格布局中显示数据

        网格布局采用二维布局的方式组织其内部元素,如下图所示。

图7 通用办公服务

        Grid组件可以通过二维布局的方式显示一组GridItem子组件。

@Entry
@Component
struct GridLayoutPage3 {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text('会议')}.backgroundColor('#1067c8ff')GridItem() {Text('签到')}.backgroundColor('#3067c8ff')GridItem() {Text('培训')}.backgroundColor('#5067c8ff')GridItem() {Text('打印')}.backgroundColor('#7067c8ff')}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr')}.width('100%').height('40%')}.height('100%').alignItems(VerticalAlign.Top)}
}

        对于内容结构相似的多个GridItem,通常更推荐使用循环渲染ForEach语句中嵌套GridItem的形式,来减少重复代码。

@Entry
@Component
struct GridLayoutPage3 {@State message: Bean[] = [{ title: '会议', color: '#1067c8ff' },{ title: '签到', color: '#3067c8ff' },{ title: '培训', color: '#5067c8ff' },{ title: '打印', color: '#7067c8ff' }]build() {Row() {Column() {Grid() {ForEach(this.message, (item: Bean) => {GridItem() {Text(item.title).backgroundColor(item.color).width('100%').height('100%').textAlign(TextAlign.Center)}}, item => JSON.stringify(item))}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr')}.width('100%').height('40%')}.height('100%').alignItems(VerticalAlign.Top)}
}class Bean {title: stringcolor: ResourceColor
}

        效果同上。

3.5、设置行列间距

        在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距,如下图所示。

图8 网格的行列间距

        通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。

@Entry
@Component
struct GridLayoutPage3 {@State message: Bean[] = [{ title: '会议', color: '#1067c8ff' },{ title: '签到', color: '#3067c8ff' },{ title: '培训', color: '#5067c8ff' },{ title: '打印', color: '#7067c8ff' }]build() {Row() {Column() {Grid() {ForEach(this.message, (item: Bean) => {GridItem() {Text(item.title).backgroundColor(item.color).width('100%').height('100%').textAlign(TextAlign.Center)}}, item => JSON.stringify(item))}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr').rowsGap(10).columnsGap(10).margin(10)}.width('100%').height('40%').backgroundColor('#eee')}.height('100%').alignItems(VerticalAlign.Top)}
}class Bean {title: stringcolor: ResourceColor
}

        效果如下:

4、构建可滚动的网格布局

        可滚动的网格布局常用在文件管理、购物或视频列表等页面中,如下图所示。在设置Grid的行列数量与占比时,如果仅设置行、列数量与占比中的一个,即仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。

图9 横向可滚动网格布局

        如果设置的是columnsTemplate,Grid的滚动方向为垂直方向;如果设置的是rowsTemplate,Grid的滚动方向为水平方向。

        如上图所示的横向可滚动网格布局,只要设置rowsTemplate属性的值且不设置columnsTemplate属性,当内容超出Grid组件宽度时,Grid可横向滚动进行内容展示。

@Entry
@Component
struct GridScrollLayoutPage {@State services: Array<string> = ['直播', '进口', '国外', '乡里', '本地', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']color: ResourceColor[] = [Color.Blue, Color.Green, Color.Orange, Color.Pink, Color.Yellow]build() {Column({ space: 5 }) {Grid() {ForEach(this.services, (service: string, index) => {GridItem() {Text(service).backgroundColor(this.color[index % this.color.length]).fontColor(Color.White).width(72).height(72).fontSize(24).borderRadius(8).textAlign(TextAlign.Center).borderRadius(36)}.width('25%')}, service => service)}.rowsTemplate('1fr 1fr') // 只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动。.rowsGap(15).columnsGap(12).height('25%')}.borderColor(Color.Pink).borderWidth(1).borderRadius(8).margin(8).backgroundColor("#1067c8ff")}
}

5、实现简单的日历功能

import hilog from '@ohos.hilog';@Entry
@Component
struct CalendarLayoutPage {private scroller: Scroller = new Scroller()private headLabel: string[] = ['一', '二', '三', '四', '五', '六', '日']private curDate: Date;@State curDateStr: string = ''@State dateArray: number[] = []aboutToAppear() {let date = new Date();this.curDate = date;this.changeMonthData()}changeMonthData() {let monthLength = this.getMonthLength(this.curDate);this.dateArray = []for (let index = 0; index < monthLength; index++) {this.dateArray.push(index + 1)}this.curDateStr = `${this.curDate.getFullYear()}-${this.curDate.getMonth() + 1}`}private nextMonth() {this.curDate.setMonth(this.curDate.getMonth() + 1)}private prevMonth() {this.curDate.setMonth(this.curDate.getMonth() - 1)}private getMonthLength(date: Date): number {let copyDate = new Date(date.getFullYear(), date.getMonth() + 1, 0)return copyDate.getDate()}build() {Row() {Column() {Text(this.curDateStr).backgroundColor(Color.Pink).fontColor(Color.White).height(48).padding({ left: 24, right: 24 }).borderRadius(24)Row({ space: 8 }) {ForEach(this.headLabel, (item) => {Text(item).fontSize(14).layoutWeight(1).textAlign(TextAlign.Center).height('40%').borderRadius(26).backgroundColor('#67c8ff')}, item => JSON.stringify(item))}.height(52).backgroundColor('#999').margin({top: 24})Grid() {ForEach(this.dateArray, (item) => {GridItem() {Button(item + "").width(52).height(52).borderWidth(1).borderColor('#67c8ff')}}, item => JSON.stringify(item))}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsGap(5).rowsGap(5).margin({ top: 12 }).height('40%')Row({ space: 20 }) {Button('上一页').onClick(() => {this.prevMonth()this.changeMonthData()// this.scroller.scrollPage({//   next: false// })})Button('下一页').onClick(() => {this.nextMonth()this.changeMonthData()// this.scroller.scrollPage({//   next: true// })})}}.width('100%').backgroundColor('#eee').borderRadius(24)}.height('100%').alignItems(VerticalAlign.Top).margin({top: 48, left: 12, right: 12})}
}

        通过 @State dateArray来刷新UI,当点击前一页的时候,当前月份减少1,然后改变dateArray的数据,触发UI更新;点击下一页同理。效果如下:

6、性能优化

        与长列表的处理类似,循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载方式实现按需迭代加载数据,从而提升列表性能。

        关于按需加载优化的具体实现可参考数据懒加载章节中的示例。

        当使用懒加载方式渲染网格时,为了更好的滚动体验,减少滑动时出现白块,Grid组件中也可通过cachedCount属性设置GridItem的预加载数量,只在懒加载LazyForEach中生效。

        设置预加载数量后,会在Grid显示区域前后各缓存cachedCount*列数个GridItem,超出显示和缓存范围的GridItem会被释放。

 

Grid() {LazyForEach(this.dataSource, item => {GridItem() {...}})
}
.cachedCount(3)

说明

cachedCount的增加会增大UI的CPU、内存开销。使用时需要根据实际情况,综合性能和用户体验进行调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/611988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【mysql】报错1349 - View‘s SELECT contains a subquery in the FROM clause

操作 创建视图的sql语句中有不支持子查询 mysql创建视图 select * from (select name,age from table_name where 11 and namea ) tb where 11 and type1问题 报错1349 - View’s SELECT contains a subquery in the FROM clause 原因 原因创建视图的sql语句中有不支持子查…

软件测试|MySQL HAVING分组筛选详解

简介 在 MySQL 数据库中&#xff0c;HAVING 子句用于在使用 GROUP BY 子句对结果进行分组后&#xff0c;对分组后的数据进行筛选和过滤。它允许我们对分组后的结果应用聚合函数&#xff0c;并基于聚合函数的结果进行条件过滤&#xff0c;从而得到我们需要的最终结果集。本文将…

条款21:必须返回对象时,别妄想返回其引用

考虑一个表示有理数的类&#xff0c;其中包含一个计算两个有理数相乘的函数: class Rational { public:Rational(int numerator 0, int denominator 1) :n{ numerator }, d{ denominator }{} private:int n, d; // 分子和分母friend const Rational& operator*(const R…

Web应用防火墙是什么?聊聊领先WAF解决方案

数字化进程的加速发展&#xff0c;Web站点及各类应用的数量呈现爆发式增长态势。与此同时&#xff0c;利用Web漏洞进行攻击的事件也与日俱增&#xff0c;黑客攻击手段不断升级&#xff0c;包括各种拟人化自动化攻击、API攻击以及0day攻击等&#xff0c;给Web应用安全防护带来了…

通过两台linux主机配置ssh实现互相免密登入

一 1.使用Xshell远程连接工工具生成公钥文件 2.生产密钥参数 3.生成公钥对 4.用户密钥信息 5.公钥注册 二 1.关闭服务端防火墙 ---systemctl stop firewalld 2.检查是否有/root/.ssh目录&#xff0c;没有则创建有则打开/root/.ssh/authorized_keys文件将密钥粘贴创建/ro…

C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解

文章目录 前言相关资料Attribute特性个人原理理解特性的声明与使用类型特性运行结果&#xff1a; 找到类的Attribute属性方法特性和变量特性代码封装测试类TestService1TestService2TestService3 测试代码运行结果 对封装的代码进行优化封装代码测试代码运行结果&#xff08;和…

66、python - 代码仓库介绍

上一节,我们可以用自己手写的算法以及手动搭建的神经网络完成预测了,不知各位同学有没有自己尝试来预测一只猫或者一只狗,看看准确度如何? 本节应一位同学的建议,来介绍下 python 代码仓库的目录结构,以及每一部分是做什么? 我们这个小课的代码实战仓库链接为:cv_lea…

12.1SPI驱动框架

SPI硬件基础 总线拓扑结构 引脚含义 DO(MOSI)&#xff1a;Master Output, Slave Input&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收数据 DI(MISO) &#xff1a;Master Input, Slave Output&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收…

threejs 光带扩散动画

目录 一、创建光带 (1) 设置光带顶点 (2) 设置光带顶点透明度属性 二、光带动画 完整代码 html文件代码 js文件代码 最后展示一下项目里的效果&#xff1a; 最近项目中要求做一段光带效果动画&#xff0c;尝试着写了一下&#xff0c;下面是本次分享光带扩散动画的效果预…

代码随想录算法训练营第一天|数组理论基础、704二分查找、27移除元素

数组理论基础 一维数组 数组中的元素在内存空间中是连续的数组名与数组中第一个元素的地址相同&#xff08;一维数组&#xff09;数组的下标从0开始删除数组的元素其实是用后面的元素覆盖掉要删除的元素数组的长度不能改变 二维数组 二维数组是按照行存储的&#xff0c;也是…

Kali Linux——aircrack-ng无线教程

目录 一、准备 二、案例 1、连接usb无线网卡 2、查看网卡信息 3、开启网卡监听 4、扫描wifi信号 5、抓取握手包 6、强制断开连接 7、破解握手包 三、预防 一、准备 1、usb无线网卡&#xff08;笔记本也是需要用到&#xff09; 2、密码字典&#xff08;Kali 系统自带…

项目整体管理

整体管理之10大项目管理&#xff1a; 核心域&#xff1a;进度&#xff0c;成本&#xff0c;质量&#xff0c;范围 辅助域&#xff1a;风险&#xff0c;沟通&#xff0c;采购&#xff0c;人力资源&#xff0c;干系人 项目管理相关方&#xff1a; 招标&#xff1a;买方&#x…

Acrel-5000重点用能单位能耗在线监测系统的实际应用分析-安科瑞 蒋静

摘要&#xff1a;根据《重点用能节能办法》&#xff08;国家发展改革委等第七部委2018年15号令&#xff09;、《重点用能单位能耗在线监测系统推广建设工作方案》&#xff08;发改环资[2017]1711号&#xff09;和《关于加速推进重点用能单位能耗在线监测系统建设的通知》&#…

评估LLM在细胞数据上的实用性(1)-基本概述

基于LLM的基础模型在工业和科学领域都取得了重大进展。本报告通过八个与单细胞数据相关的下游任务的综合实验&#xff0c;评估了LLM在单细胞测序数据分析中的性能。通过将七种不同的单细胞LLM与特定任务下的baselines进行比较&#xff0c;结果发现单细胞LLMs在所有任务中可能并…

Js-基础语法(二)

运算符 赋值运算符 赋值运算符&#xff1a;对变量进行赋值的运算符 已经学过的赋值运算符&#xff1a; 将等号右边的值赋予给左边, 要求左边必须是一个容器 其他赋值运算符&#xff1a; - */% 使用这些运算符可以在对变量赋值时进行快速操作 一元运算符 众多的 JavaScrip…

固定翼仿真的切换

delta固定翼飞行器模型 接着这篇文章文章链接&#xff0c;我们对飞行器模型进行改进&#xff0c; 我们知道&#xff0c;我们打开仿真模型 gazebo --verbose zephyr_ardupilot_demo.world 我们注意这最后一个语句 <model name"zephyr_delta_wing_demo">//加载z…

图像分类任务的可视化脚本,生成类别json字典文件

1. 前言 之前的图像分类任务可视化&#xff0c;都是在train脚本里&#xff0c; 用torch中dataloader将图片和类别加载&#xff0c;然后利用matplotlib库进行可视化。 如这篇文章中&#xff1a;CNN 卷积神经网络对染色血液细胞分类(blood-cells) 在分类任务中&#xff0c;必定…

零基础学习数学建模——(一)什么是数学建模

本篇博客将详细介绍什么是数学建模。 文章目录 个人简介什么是数学建模&#xff08;一&#xff09;引例&#xff1a;高中数学里的简单线性规划问题数学建模的定义及用途数学建模的定义数学建模的用途 正确认识数学建模 个人简介 ​ 本人在本科阶段获得过国赛省一、mathorcup数…

ssm基于Web的汽车客运订票系统的设计与实现论文

毕业设计&#xff08;论文&#xff09; 汽车客运订票系统 姓 名 ______________________ 学 号 ______________________ 班 级 ______________________ 专 业 ______________________ 院 部 ______________________ 指导教师 ______________________ 年 月 日 目 录 目 录 …

Unity3d 实现直播功能(无需sdk接入)

Unity3d 实现直播功能 需要插件 :VideoCapture 插件地址(免费的就行) 原理:客户端通过 VideoCapture 插件实现推流nodejs视频流转服务进行转发,播放器实现rtmp拉流 废话不多说,直接上 CaptureSource我选择的是屏幕录制,也可以是其他源 CaptureType选择LIVE–直播形式 LiveSt…