OpenHarmony4.1Release版本的配套文档,对应API能力级别为API10Release
OpenHarmony4.1Beta1版本开始提供首批APILevel11接口
ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,使用if、else和elseif渲染对应状态下的UI内容。
更新机制
当if、elseif后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:
条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。
@ComponentstructCounterView{@Linkcounter:number;label:string='unknown';build(){Row(){Text(`${this.label}`)Button(`counter${this.counter}+1`).onClick(()=>{this.counter+=1;})}}}@Entry@ComponentstructMainView{@Statetoggle:boolean=true;@Statecounter:number=0;build(){Column(){if(this.toggle){CounterView({counter:this.counter,label:'CounterView#positive'})}else{CounterView({counter:this.counter,label:'CounterView#negative'})}Button(`toggle${this.toggle}`).onClick(()=>{this.toggle=!this.toggle;})}}}if语句的每个分支都包含一个构建函数。此类构建函数必须创建一个或多个子组件。在初始渲染时,if语句会执行构建函数,并将生成的子组件添加到其父组件中。
每当if或elseif条件语句中使用的状态变量发生变化时,条件语句都会更新并重新评估新的条件值。如果条件值评估发生了变化,这意味着需要构建另一个条件分支。此时ArkUI框架将:
ForEach接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为List组件。
ForEach(arr:Array,itemGenerator:(item:any,index:number)=>void,keyGenerator:(item:any,index:number)=>string)以下是参数的详细说明:
说明:
键值生成规则
在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。
ForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item:any,index:number)=>{returnindex+'__'+JSON.stringify(item);}。
组件创建规则
在确定键值生成规则后,ForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况:ForEach首次渲染和ForEach非首次渲染。
首次渲染
在ForEach首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。
当不同数组项按照键值生成规则生成的键值相同时,框架的行为是未定义的。例如,在以下代码中,ForEach渲染相同的数据项two时,只创建了一个ChildItem组件,而没有创建多个具有相同键值的组件。
非首次渲染
在ForEach组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件。例如,在以下的代码示例中,通过点击事件修改了数组的第三项值为"newthree",这将触发ForEach组件进行非首次渲染。
在数据源数组项发生变化的场景下,例如进行数组插入、删除操作或者数组项索引位置发生交换时,数据源应为对象数组类型,并使用对象的唯一ID作为最终键值。例如,当在页面上通过手势上滑加载下一页数据时,会在数据源数组尾部新增新获取的数据项,从而使得数据源数组长度增大。
使用建议
LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
LazyForEach(dataSource:IDataSource,//需要进行数据迭代的数据源itemGenerator:(item:any,index:number)=>void,//子组件生成函数keyGenerator:(item:any,index:number)=>string//键值生成函数):void参数:
IDataSource类型说明
在LazyForEach循环渲染过程中,系统会为每个item生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。
LazyForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item:any,index:number)=>{returnviewId+'-'+index.toString();},viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId是一致的。
在确定键值生成规则后,LazyForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况:LazyForEach首次渲染和LazyForEach非首次渲染。
在LazyForEach首次渲染时,会根据上述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。
如何选择布局
布局位置
position、offset等属性影响了布局容器相对于自身或其他组件的位置。
对子元素的约束
Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。
在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。
Column({space:20}){...}.width('100%')在布局容器内,可以通过alignItems属性设置子元素在交叉轴(排列方向的垂直方向)上的对齐方式。且在各类尺寸屏幕中,表现一致。其中,交叉轴为垂直方向时,取值为VerticalAlign类型,水平方向取值为HorizontalAlign。
alignSelf属性用于控制单个子元素在容器交叉轴上的对齐方式,其优先级高于alignItems属性,如果设置了alignSelf属性,则在单个子元素上会覆盖alignItems属性。
Row({}){Column(){}.width('20%').height(30).backgroundColor(0xF5DEB3)Column(){}.width('20%').height(30).backgroundColor(0xD2B48C)Column(){}.width('20%').height(30).backgroundColor(0xF5DEB3)}.width('100%').height(200).alignItems(VerticalAlign.Bottom).backgroundColor('rgb(242,242,242)')在布局容器内,可以通过justifyContent属性设置子元素在容器主轴上的排列方式。
Row({}){Column(){}.width('20%').height(30).backgroundColor(0xF5DEB3)Column(){}.width('20%').height(30).backgroundColor(0xD2B48C)Column(){}.width('20%').height(30).backgroundColor(0xF5DEB3)}.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceBetween)自适应拉伸
在线性布局下,常用空白填充组件Blank,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。Row和Column作为容器,只需要添加宽高为百分比,当屏幕宽高发生变化时,会产生自适应效果。
自适应缩放
自适应缩放是指子元素随容器尺寸的变化而按照预设的比例自动调整尺寸,适应各种不同大小的设备。在线性布局中,可以使用以下两种方法实现自适应缩放。
父容器尺寸确定时,使用layoutWeight属性设置子元素和兄弟元素在主轴上的权重,忽略元素本身尺寸设置,使它们在任意尺寸的设备下自适应占满剩余空间。
父容器尺寸确定时,使用百分比设置子元素和兄弟元素的宽度,使他们在任意尺寸的设备下保持固定的自适应占比。
自适应延伸
自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示。这种方法适用于线性布局中内容无法一屏展示的场景。通常有以下两种实现方式。
在List中添加滚动条:当List子项过多一屏放不下时,可以将每一项子元素放置在不同的组件中,通过滚动条进行拖动展示。可以通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到内容最末端的回弹效果。
使用Scroll组件:在线性布局中,开发者可以进行垂直方向或者水平方向的布局。当一屏无法完全显示时,可以在Column或Row组件的外层包裹一个可滚动的容器组件Scroll来实现可滑动的线性布局。
垂直方向布局中使用Scroll组件:
层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠,容器中的子元素依次入栈,后一个子元素覆盖前一个子元素,子元素可以叠加,也可以设置位置。
如图1,Stack作为容器,容器内的子元素的顺序为Item1->Item2->Item3。
Stack组件为容器组件,容器内可包含各种子元素。其中子元素默认进行居中堆叠。子元素被约束在Stack下,进行自己的样式定义以及排列。
对齐方式
Stack组件通过alignContent参数实现位置的相对移动。如图2所示,支持九种对齐方式。
//xxx.ets@Entry@ComponentstructStackExample{build(){Stack({alignContent:Alignment.TopStart}){Text('Stack').width('90%').height('100%').backgroundColor('#e1dede').align(Alignment.BottomEnd)Text('Item1').width('70%').height('80%').backgroundColor(0xd2cab3).align(Alignment.BottomEnd)Text('Item2').width('50%').height('60%').backgroundColor(0xc1cbac).align(Alignment.BottomEnd)}.width('100%').height(150).margin({top:5})}}Z序控制
Stack容器中兄弟组件显示层级关系可以通过Z序控制的zIndex属性改变。zIndex值越大,显示层级越高,即zIndex值大的组件会覆盖在zIndex值小的组件上方。
在层叠布局中,如果后面子元素尺寸大于前面子元素尺寸,则前面子元素完全隐藏。
布局方向
在弹性布局中,容器的子元素可以按照任意方向排列。通过设置参数direction,可以决定主轴的方向,从而控制子元素的排列方向。
布局换行
弹性布局分为单行布局和多行布局。默认情况下,Flex容器中的子元素都排在一条线(又称“轴线”)上。wrap属性控制当子元素主轴尺寸之和大于容器主轴尺寸时,Flex是单行布局还是多行布局。在多行布局时,通过交叉轴方向,确认新行排列方向。
主轴对齐方式
通过justifyContent参数设置子元素在主轴方向的对齐方式。
交叉轴对齐方式
容器和子元素都可以设置交叉轴对齐方式,且子元素设置的对齐方式优先级较高。
可以通过Flex组件的alignItems参数设置子元素在交叉轴的对齐方式。
ItemAlign.Auto:使用Flex容器中默认配置。
ItemAlign.Start:交叉轴方向首部对齐。
ItemAlign.Center:交叉轴方向居中对齐。
ItemAlign.End:交叉轴方向底部对齐。
ItemAlign.Stretch:交叉轴方向拉伸填充,在未设置尺寸时,拉伸到容器尺寸。
ItemAlign.Baseline:交叉轴方向文本基线对齐。
子元素设置交叉轴对齐
子元素的alignSelf属性也可以设置子元素在父容器交叉轴的对齐格式,且会覆盖Flex布局容器中alignItems配置。
内容对齐
可以通过alignContent参数设置子元素各行在交叉轴剩余空间内的对齐方式,只在多行的Flex布局中生效,可选值有:
自适应拉伸
在弹性布局父组件尺寸过小时,通过子元素的以下属性设置其在父容器的占比,达到自适应布局。
flexBasis:设置子元素在父容器主轴方向上的基准尺寸。如果设置了该属性,则子项占用的空间为该属性所设置的值;如果没设置该属性,那子项的空间为width/height的值。
flexGrow:设置父容器的剩余空间分配给此属性所在组件的比例。用于分配父组件的剩余空间。
父容器宽度420vp,三个子元素原始宽度为100vp,左右padding为20vp,总和320vp,剩余空间100vp根据flexGrow值的占比分配给子元素,未设置flexGrow的子元素不参与“瓜分”。
flexShrink:当父容器空间不足时,子元素的压缩比例。
RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。
子元素并不完全是上图中的依赖关系。比如,Item4可以以Item2为依赖锚点,也可以以RelativeContainer父容器为依赖锚点。
锚点设置
锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。为了明确定义锚点,必须为RelativeContainer及其子元素设置ID,用于指定锚点信息。ID默认为“__container__”,其余子元素的ID通过id属性设置。未设置ID的子元素在RelativeContainer中不会显示。互相依赖,环形依赖时容器内子组件全部不绘制。同方向上两个以上位置设置锚点,但锚点位置逆序时此子组件大小为0,即不绘制。
在使用锚点时要注意子元素的相对位置关系,避免出现错位或遮挡的情况。
RelativeContainer父组件为锚点,__container__代表父容器的ID。
以兄弟元素为锚点。
子组件锚点可以任意选择,但需注意不要相互依赖。
设置相对于锚点的对齐位置
设置了锚点之后,可以通过align设置相对于锚点的对齐位置。
在水平方向上,对齐位置可以设置为HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End。
在竖直方向上,对齐位置可以设置为VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom。
子组件位置偏移
子组件经过相对位置对齐后,位置可能还不是目标位置,开发者可根据需要进行额外偏移设置offset。
Row().backgroundColor("#FF9966").alignRules({top:{anchor:"row3",align:VerticalAlign.Bottom},bottom:{anchor:"__container__",align:VerticalAlign.Bottom},left:{anchor:"__container__",align:HorizontalAlign.Start},right:{anchor:"row1",align:HorizontalAlign.End}}).offset({x:-10,y:-30}).id("row4")Row、Column、Flex、Stack等多种布局组件,可按照RelativeContainer组件规则进行对其排布。
子组件尺寸大小不会受到相对布局规则的影响。若子组件某个方向上设置两个或以上alignRules时最好不设置此方向尺寸大小,否则对齐规则确定的组件尺寸与开发者设置的尺寸可能产生冲突。
栅格布局是一种通用的辅助定位工具,对移动设备的界面设计有较好的借鉴作用。
自动换行和自适应:栅格布局可以完成一对多布局的自动换行和自适应。
GridRow为栅格容器组件,需与栅格子组件GridCol在栅格布局场景中联合使用。
栅格系统断点
栅格系统默认断点将设备宽度分为xs、sm、md、lg四类,尺寸范围如下:
在GridRow栅格组件中,允许开发者使用breakpoints自定义修改断点的取值范围,最多支持6个断点,除了默认的四个断点外,还可以启用xl,xxl两个断点,支持六种不同尺寸(xs,sm,md,lg,xl,xxl)设备的布局设置。
针对断点位置,开发者根据实际使用场景,通过一个单调递增数组设置。由于breakpoints最多支持六个断点,单调递增数组长度最大为5。
breakpoints:{value:['100vp','200vp']}表示启用xs、sm、md共3个断点,小于100vp为xs,100vp-200vp为sm,大于200vp为md。
breakpoints:{value:['320vp','520vp','840vp','1080vp']}表示启用xs、sm、md、lg、xl共5个断点,小于320vp为xs,320vp-520vp为sm,520vp-840vp为md,840vp-1080vp为lg,大于1080vp为xl。
栅格系统通过监听窗口或容器的尺寸变化进行断点,通过reference设置断点切换参考物。考虑到应用可能以非全屏窗口的形式显示,以应用窗口宽度为参照物更为通用。
例如,使用栅格的默认列数12列,通过断点设置将应用宽度分成六个区间,在各区间中,每个栅格子元素占用的列数均不同。
@StatebgColors:Color[]=[Color.Red,Color.Orange,Color.Yellow,Color.Green,Color.Pink,Color.Grey,Color.Blue,Color.Brown];...GridRow({breakpoints:{value:['200vp','300vp','400vp','500vp','600vp'],reference:BreakpointsReference.WindowSize}}){ForEach(this.bgColors,(color:Color,index:number|undefined)=>{GridCol({span:{xs:2,//在最小宽度类型设备上,栅格子组件占据的栅格容器2列。sm:3,//在小宽度类型设备上,栅格子组件占据的栅格容器3列。md:4,//在中等宽度类型设备上,栅格子组件占据的栅格容器4列。lg:6,//在大宽度类型设备上,栅格子组件占据的栅格容器6列。xl:8,//在特大宽度类型设备上,栅格子组件占据的栅格容器8列。xxl:12//在超大宽度类型设备上,栅格子组件占据的栅格容器12列。}}){Row(){Text(`${index}`)}.width("100%").height('50vp')}.backgroundColor(color)})}布局的总列数
GridRow中通过columns设置栅格布局的总列数。
@StatebgColors:Color[]=[Color.Red,Color.Orange,Color.Yellow,Color.Green,Color.Pink,Color.Grey,Color.Blue,Color.Brown]GridRow({columns:{sm:4,md:8},breakpoints:{value:['200vp','300vp','400vp','500vp','600vp']}}){ForEach(this.bgColors,(item:Color,index:number|undefined)=>{GridCol(){Row(){Text(`${index}`)}.width('100%').height('50')}.backgroundColor(item)})}若只设置sm,md的栅格总列数,则较小的尺寸使用默认columns值12,较大的尺寸使用前一个尺寸的columns。这里只设置sm:4,md:8,则较小尺寸的xs:12,较大尺寸的参照md的设置,lg:8,xl:8,xxl:8
排列方向
栅格布局中,可以通过设置GridRow的direction属性来指定栅格子组件在栅格容器中的排列方向。该属性可以设置为GridRowDirection.Row(从左往右排列)或GridRowDirection.RowReverse(从右往左排列),以满足不同的布局需求。
子组件间距
GridRow中通过gutter属性设置子元素在水平和垂直方向的间距。
当gutter类型为number时,同时设置栅格子组件间水平和垂直方向边距且相等。
当gutter类型为GutterOption时,单独设置栅格子组件水平垂直边距,x属性为水平方向间距,y为垂直方向间距。
GridRow({gutter:{x:20,y:50}}){}子组件GridCol
GridCol组件作为GridRow组件的子组件,通过给GridCol传参或者设置属性两种方式,设置span(占用列数),offset(偏移列数),order(元素序号)的值。
设置span。
子组件占栅格布局的列数,决定了子组件的宽度,默认为1。当类型为number时,子组件在所有尺寸设备下占用的列数相同。当类型为GridColColumnOption时,支持六种不同尺寸(xs,sm,md,lg,xl,xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
栅格子组件相对于前一个子组件的偏移列数,默认为0。当类型为number时,子组件偏移相同列数。当类型为GridColColumnOption时,支持六种不同尺寸(xs,sm,md,lg,xl,xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
设置order。
栅格子组件的序号,决定子组件排列次序。当子组件不设置order或者设置相同的order,子组件按照代码顺序展示。当子组件设置不同的order时,order较小的组件在前,较大的在后。
当子组件部分设置order,部分不设置order时,未设置order的子组件依次排序靠前,设置了order的子组件按照数值从小到大排列。
当类型为number时,子组件在任何尺寸下排序次序一致。当类型为GridColColumnOption时,支持六种不同尺寸(xs,sm,md,lg,xl,xxl)设备中子组件排序次序设置。
以下示例中,栅格把整个空间分为12份。第一层GridRow嵌套GridCol,分为中间大区域以及“footer”区域。第二层GridRow嵌套GridCol,分为“left”和“right”区域。子组件空间按照上一层父组件的空间划分,粉色的区域是屏幕空间的12列,绿色和蓝色的区域是父组件GridCol的12列,依次进行空间的划分。
引入与使用流程
媒体查询通过mediaquery模块接口,设置查询条件并绑定回调函数,在对应的条件的回调函数里更改页面布局或者实现业务逻辑,实现页面的响应式设计。具体步骤如下:
首先导入媒体查询模块。
importmediaqueryfrom'@ohos.mediaquery';通过matchMediaSync接口设置媒体查询条件,保存返回的条件监听句柄listener。例如监听横屏事件:
//监听横屏事件letlistener:mediaquery.MediaQueryListener=mediaquery.matchMediaSync('(orientation:landscape)');给条件监听句柄listener绑定回调函数onPortrait,当listener检测设备状态变化时执行回调函数。在回调函数内,根据不同设备状态更改页面布局或者实现业务逻辑。
onPortrait(mediaQueryResult:mediaquery.MediaQueryResult){if(mediaQueryResult.matchesasboolean){//dosomethinghere}else{//dosomethinghere}}listener.on('change',onPortrait);媒体查询条件
媒体查询条件由媒体类型、逻辑操作符、媒体特征组成,其中媒体类型可省略,逻辑操作符用于连接不同媒体类型与媒体特征,其中,媒体特征要使用“()”包裹且可以有多个。
语法规则包括媒体类型(media-type)、媒体逻辑操作(media-logic-operations)和媒体特征(media-feature)。
[media-type][media-logic-operations][(media-feature)]例如:
媒体类型(media-type)
媒体逻辑操作(media-logic-operations)
媒体逻辑操作符:and、or、not、only用于构成复杂媒体查询,也可以通过comma(,)将其组合起来,详细解释说明如下表。
媒体特征(media-feature)
媒体特征包括应用显示区域的宽高、设备分辨率以及设备的宽高等属性,详细说明如下表。
//省略
布局与约束
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。
图1List、ListItemGroup和ListItem组件关系
List的子组件必须是ListItemGroup或ListItem,ListItem和ListItemGroup必须配合List来使用。
布局
List除了提供垂直和水平布局能力、超出屏幕时可以滚动的自适应延伸能力之外,还提供了自适应交叉轴方向上排列个数的布局能力。
利用垂直布局能力可以构建单列或者多列垂直滚动列表。
利用水平布局能力可以是构建单行或多行水平滚动列表。
约束
列表的主轴方向是指子组件列的排列方向,也是列表的滚动方向。垂直于主轴的轴称为交叉轴,其方向与主轴方向相互垂直。
如下图所示,垂直列表的主轴是垂直方向,交叉轴是水平方向;水平列表的主轴是水平方向,交叉轴是垂直方向。
如果List组件主轴或交叉轴方向设置了尺寸,则其对应方向上的尺寸为设置值。
如果List组件主轴方向没有设置尺寸,当List子组件主轴方向总尺寸小于List的父组件尺寸时,List主轴方向尺寸自动适应子组件的总尺寸。
如果子组件主轴方向总尺寸超过List父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。
List组件交叉轴方向在没有设置尺寸时,其尺寸默认自适应父组件尺寸。
开发布局-设置主轴方向
List组件主轴默认是垂直方向,即默认情况下不需要手动设置List方向,就可以构建一个垂直滚动列表。
若是水平滚动列表场景,将List的listDirection属性设置为Axis.Horizontal即可实现。listDirection默认为Axis.Vertical,即主轴默认是垂直方向。
List(){//...}.listDirection(Axis.Horizontal)开发布局-设置交叉轴布局
List组件的交叉轴布局可以通过lanes和alignListItem属性进行设置,lanes属性用于确定交叉轴排列的列表项数量,alignListItem用于设置子组件在交叉轴方向的对齐方式。
List(){//...}.lanes(2)当其取值为LengthConstrain类型时,表示会根据LengthConstrain与List组件的尺寸自适应决定行或列数。
@Entry@ComponentstructEgLanes{@StateegLanes:LengthConstrain={minLength:200,maxLength:300}build(){List(){//...}.lanes(this.egLanes)}}例如,假设在垂直列表中设置了lanes的值为{minLength:200,maxLength:300}。此时,
同样以垂直列表为例,当alignListItem属性设置为ListItemAlign.Center表示列表项在水平方向上居中对齐。alignListItem的默认值是ListItemAlign.Start,即列表项在列表交叉轴方向上默认按首部对齐。
List(){//...}.alignListItem(ListItemAlign.Center)在列表中显示数据
在最简单的列表形式中,List静态地创建其列表项ListItem的内容。在List组件中,ForEach除了可以用来循环渲染ListItem,也可以用来循环渲染ListItemGroup。
自定义列表样式
在初始化列表时,如需在列表项之间添加间距,可以使用space参数。
List提供了divider属性用于给列表项之间添加分隔线。在设置divider属性时,可以通过strokeWidth和color属性设置分隔线的粗细和颜色。startMargin和endMargin属性分别用于设置分隔线距离列表侧边起始端的距离和距离列表侧边结束端的距离。
在使用List组件时,可通过scrollBar属性控制列表滚动条的显示。scrollBar的取值类型为BarState,当取值为BarState.Auto表示按需显示滚动条。此时,当触摸到滚动条区域时显示控件,可上下拖拽滚动条快速浏览内容,拖拽时会变粗。若不进行任何操作,2秒后滚动条自动消失。
scrollBar属性APIversion9及以下版本默认值为BarState.Off,从APIversion10版本开始默认值为BarState.Auto。
支持分组列表
图11联系人分组列表
在List组件中可以直接使用一个或者多个ListItemGroup组件,ListItemGroup的宽度默认充满List组件。在初始化ListItemGroup时,可通过header参数设置列表分组的头部组件。
@Entry@ComponentstructContactsList{@BuilderitemHead(text:string){//列表分组的头部组件,对应联系人分组A、B等位置的组件Text(text).fontSize(20).backgroundColor('#fff1f3f5').width('100%').padding(5)}build(){List(){ListItemGroup({header:this.itemHead('A')}){//循环渲染分组A的ListItem}ListItemGroup({header:this.itemHead('B')}){//循环渲染分组B的ListItem}}}}添加粘性标题
List组件的sticky属性配合ListItemGroup组件使用,用于设置ListItemGroup中的头部组件是否呈现吸顶效果或者尾部组件是否呈现吸底效果。
通过给List组件设置sticky属性为StickyStyle.Header,即可实现列表的粘性标题效果。如果需要支持吸底效果,可以通过footer参数初始化ListItemGroup的底部组件,并将sticky属性设置为StickyStyle.Footer。
控制滚动位置
控制滚动位置在实际应用中十分常见,例如当新闻页列表项数量庞大,用户滚动列表到一定位置时,希望快速滚动到列表底部或返回列表顶部。此时,可以通过控制滚动位置来实现列表的快速定位。
首先,需要创建一个Scroller的对象listScroller。
privatelistScroller:Scroller=newScroller();然后,通过将listScroller用于初始化List组件的scroller参数,完成listScroller与列表的绑定。在需要跳转的位置指定scrollToIndex的参数为0,表示返回列表顶部。
响应滚动位置
许多应用需要监听列表的滚动位置变化并作出响应。例如,在联系人列表滚动时,如果跨越了不同字母开头的分组,则侧边字母索引栏也需要更新到对应的字母位置。
响应列表项侧滑
在消息列表中,end参数表示设置ListItem左滑时尾端划出自定义组件,即删除按钮。在初始化end方法时,将滑动列表项的索引传入删除按钮组件,当用户点击删除按钮时,可以根据索引值来删除列表项对应的数据,从而实现侧滑删除功能。
给列表项添加标记
下拉刷新与上拉加载
以下拉刷新为例,其实现主要分成三步:
长列表的处理
当使用懒加载方式渲染列表时,为了更好的列表滚动体验,减少列表滑动时出现白块,List组件提供了cachedCount参数用于设置列表项缓存数,只在懒加载LazyForEach中生效。
Grid组件为网格容器,其中容器内各条目对应一个GridItem组件,如下图所示。
Grid的子组件必须是GridItem组件。
网格布局是一种二维布局。Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。当网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,从而实现网格布局的自适应能力。根据Grid的这些布局能力,可以构建出不同样式的网格布局,如下图所示。
如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。
Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:
设置排列方式
通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。
rowsTemplate和columnsTemplate属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列宽度。
例如计算器的按键布局就是常见的不均匀网格布局场景。使用Grid构建的网格布局,其行列标号从0开始,依次编号。
图5计算器
在单个网格单元中,rowStart和rowEnd属性表示指定当前元素起始行号和终点行号,columnStart和columnEnd属性表示指定当前元素的起始列号和终点列号。
“0”按键横跨第一列和第二列
GridItem(){Text(key)...}.columnStart(0).columnEnd(1).rowStart(5).rowEnd(5)设置主轴方向使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。
图6主轴方向示意图
当前layoutDirection设置为Row时,先从左到右排列,排满一行再排下一行。当前layoutDirection设置为Column时,先从上到下排列,排满一列再排下一列,如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。
Grid(){...}.maxCount(3).layoutDirection(GridDirection.Row)layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效,此时元素在layoutDirection方向上排列。
在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距。
通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。在图5所示的计算器中,行间距为15vp,列间距为10vp。
Grid(){...}.columnsGap(10).rowsGap(15)构建可滚动的网格布局
在设置Grid的行列数量与占比时,如果仅设置行、列数量与占比中的一个,即仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。
privatescroller:Scroller=newScroller()在日历页面中,用户在点击“下一页”按钮时,应用响应点击事件,通过指定scrollPage方法的参数next为true,滚动到下一页。
Column({space:5}){Grid(this.scroller){}.columnsTemplate('1fr1fr1fr1fr1fr1fr1fr')Row({space:20}){Button('上一页').onClick(()=>{this.scroller.scrollPage({next:false})})Button('下一页').onClick(()=>{this.scroller.scrollPage({next:true})})}}性能优化
与长列表的处理类似,循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载方式实现按需迭代加载数据,从而提升列表性能。
当使用懒加载方式渲染网格时,为了更好的滚动体验,减少滑动时出现白块,Grid组件中也可通过cachedCount属性设置GridItem的预加载数量,只在懒加载LazyForEach中生效。
设置预加载数量后,会在Grid显示区域前后各缓存cachedCount*列数个GridItem,超出显示和缓存范围的GridItem会被释放。
Swiper作为一个容器组件,如果设置了自身尺寸属性,则在轮播显示过程中均以该尺寸生效。如果自身尺寸属性未被设置,则分两种情况:如果设置了prevMargin或者nextMargin属性,则Swiper自身尺寸会跟随其父组件;如果未设置prevMargin或者nextMargin属性,则会自动根据子组件的大小设置自身的尺寸。
通过loop属性控制是否循环播放,该属性默认值为true。
Swiper通过设置autoPlay属性,控制是否自动轮播子组件。该属性默认值为false。
Swiper提供了默认的导航点样式,导航点默认显示在Swiper下方居中位置,开发者也可以通过indicatorStyle属性自定义导航点的位置和样式。
通过indicatorStyle属性,开发者可以设置导航点相对于Swiper组件上下左右四个方位的位置,同时也可以设置每个导航点的尺寸、颜色、蒙层和被选中导航点的颜色。
Swiper支持手指滑动、点击导航点和通过控制器三种方式切换页面。
Swiper支持水平和垂直方向上进行轮播,主要通过vertical属性控制。
当vertical为true时,表示在垂直方向上进行轮播;为false时,表示在水平方向上进行轮播。vertical默认值为false。
Swiper支持在一个页面内同时显示多个子组件,通过displayCount属性设置。
Button通过调用接口来创建,接口调用有以下两种形式:
创建不包含子组件的按钮。
Button(label:ResourceStr,options:{type:ButtonType,stateEffect:boolean})其中,label用来设置按钮文字,type用于设置Button类型,stateEffect属性设置Button是否开启点击效果。
创建包含子组件的按钮。
Button(options:{type:ButtonType,stateEffect:boolean})只支持包含一个子组件,子组件可以是基础组件或者容器组件。
Radio(options:{value:string,group:string})其中,value是单选框的名称,group是单选框的所属群组名称。checked属性可以设置单选框的状态,状态分别为false和true,设置为true时表示单选框被选中。
Radio支持设置选中状态和非选中状态的样式,不支持自定义形状。
Toggle(options:{type:ToggleType,isOn:boolean})其中,ToggleType为开关类型,包括Button、Checkbox和Switch,isOn为切换按钮的状态。
接口调用有以下两种形式:
创建不包含子组件的Toggle。当ToggleType为Checkbox或者Switch时,用于创建不包含子组件的Toggle:
Toggle({type:ToggleType.Checkbox,isOn:true})Toggle({type:ToggleType.Switch,isOn:false})创建包含子组件的Toggle。当ToggleType为Button时,只能包含一个子组件。
Progress(options:{value:number,total:number,type:ProgressType})其中,value用于设置初始进度值,total用于设置进度总长度,type用于设置Progress样式。
Progress有5种可选类型,通过ProgressType可以设置进度条样式,ProgressType类型包括:ProgressType.Linear(线性样式)、ProgressType.Ring(环形无刻度样式)、ProgressType.ScaleRing(环形有刻度样式)、ProgressType.Eclipse(圆形样式)和ProgressType.Capsule(胶囊样式)。
Text可通过以下两种方式来创建:
string字符串
Text('我是一段文本')引用Resource资源
资源引用类型可以通过$r创建Resource类型对象,文件位置为/resources/base/element/string.json。
Text($r('app.string.module_desc')).baselineOffset(0).fontSize(30).border({width:1}).padding(10).width(300)添加子组件
创建Span。
Span组件需要写到Text组件内,单独写Span组件不会显示信息,Text与Span同时配置文本内容时,Span内容覆盖Text内容。
Text('我是Text'){Span('我是Span')}通过decoration设置文本装饰线及颜色。
通过textCase设置文字一直保持大写或者小写状态。
添加事件。由于Span组件无尺寸信息,事件仅支持添加点击事件onClick。
自定义文本样式
通过textAlign属性设置文本对齐样式。
通过textOverflow属性控制文本超长处理,textOverflow需配合maxLines一起使用(默认情况下文本自动折行)。
Text('当文本溢出其尺寸时,文本将滚动显示。Whenthetextoverflowsitsdimensions,thetextwillscrollfordisplaying.').width(250).textOverflow({overflow:TextOverflow.MARQUEE}).maxLines(1).fontSize(12).border({width:1}).padding(10)通过lineHeight属性设置文本行高。
通过decoration属性设置文本装饰线样式及其颜色。
通过baselineOffset属性设置文本基线的偏移量。
通过letterSpacing属性设置文本字符间距。
通过minFontSize与maxFontSize自适应字体大小,minFontSize设置文本最小显示字号,maxFontSize设置文本最大显示字号,minFontSize与maxFontSize必须搭配同时使用,以及需配合maxline或布局大小限制一起使用,单独设置不生效。
通过textCase属性设置文本大小写。
通过copyOption属性设置文本是否可复制粘贴。
Text组件可以添加通用事件,可以绑定onClick、onTouch等事件来响应操作。
TextInput为单行输入框、TextArea为多行输入框。通过以下接口来创建。
TextInput().type(InputType.Password)多行输入框
TextArea()自定义样式
设置无输入时的提示文本。TextInput({placeholder:'我是提示文本'})
设置输入框当前的文本内容。
TextInput({placeholder:'我是提示文本',text:'我是当前文本内容'})添加backgroundColor改变输入框的背景颜色。
添加事件
绑定onChange事件可以获取输入框内改变的内容。用户也可以使用通用事件来进行相应的交互操作。
创建自定义弹窗
使用@CustomDialog装饰器装饰自定义弹窗。
@CustomDialog装饰器用于装饰自定义弹框,此装饰器内进行自定义内容(也就是弹框内容)。
@CustomDialogstructCustomDialogExample{controller:CustomDialogController=newCustomDialogController({builder:CustomDialogExample({}),})build(){Column(){Text('我是内容').fontSize(20).margin({top:10,bottom:10})}}}创建构造器,与装饰器呼应相连。
@Entry@ComponentstructCustomDialogUser{dialogController:CustomDialogController=newCustomDialogController({builder:CustomDialogExample(),})}点击与onClick事件绑定的组件使弹窗弹出。
@Entry@ComponentstructCustomDialogUser{dialogController:CustomDialogController=newCustomDialogController({builder:CustomDialogExample(),})build(){Column(){Button('clickme').onClick(()=>{this.dialogController.open()})}.width('100%').margin({top:5})}}弹窗的交互
弹窗可用于数据交互,完成用户一系列响应操作。
在@CustomDialog装饰器内添加按钮,同时添加数据函数。
@CustomDialogstructCustomDialogExample{cancel:()=>voidconfirm:()=>voidcontroller:CustomDialogControllerbuild(){Column(){Text('我是内容').fontSize(20).margin({top:10,bottom:10})Flex({justifyContent:FlexAlign.SpaceAround}){Button('cancel').onClick(()=>{this.controller.close()if(this.cancel){this.cancel()}}).backgroundColor(0xffffff).fontColor(Color.Black)Button('confirm').onClick(()=>{this.controller.close()if(this.confirm){this.confirm()}}).backgroundColor(0xffffff).fontColor(Color.Red)}.margin({bottom:10})}}}页面内需要在构造器内进行接收,同时创建相应的函数操作。
@Entry@ComponentstructCustomDialogUser{dialogController:CustomDialogController=newCustomDialogController({builder:CustomDialogExample({cancel:()=>{this.onCancel()},confirm:()=>{this.onAccept()},}),})onCancel(){console.info('Callbackwhenthefirstbuttonisclicked')}onAccept(){console.info('Callbackwhenthesecondbuttonisclicked')}build(){Column(){Button('clickme').onClick(()=>{this.dialogController.open()})}.width('100%').margin({top:5})}}弹窗的动画
创建视频组件
Video通过调用接口来创建,接口调用形式如下:
Video(value:VideoOptions)
VideoOptions对象包含参数src、currentProgressRate、previewUri、controller。其中,src指定视频播放源的路径,currentProgressRate用于设置视频播放倍速,previewUri指定视频未播放时的预览图片路径,controller设置视频控制器,用于自定义控制视频。
加载视频资源
Video组件支持加载本地视频和网络视频。
加载本地视频
普通本地视频。
加载本地视频时,首先在本地rawfile目录指定对应的文件,如下图所示。
再使用资源访问符$rawfile()引用视频资源。
加载沙箱路径视频
支持file:///data/storage路径前缀的字符串,用于读取应用沙箱路径内的资源,需要保证应用沙箱目录路径下的文件存在并且有可读权限。
加载网络视频
添加属性
Video组件属性主要用于设置视频的播放形式。例如设置视频播放是否静音、播放是否显示控制条等。
@ComponentexportstructVideoPlayer{privatecontroller:VideoController|undefined;build(){Column(){Video({controller:this.controller}).muted(false)//设置是否静音.controls(false)//设置是否显示默认控制条.autoPlay(false)//设置是否自动播放.loop(false)//设置是否循环播放.objectFit(ImageFit.Contain)//设置视频适配模式}}}事件调用
Video控制器使用
默认的控制器支持视频的开始、暂停、进度调整、全屏显示四项基本功能。
使用自定义的控制器,先将默认控制器关闭掉,之后可以使用button以及slider等组件进行自定义的控制与显示,适合自定义较强的场景下使用。
其可通过指定其type字段来实现不同的功能,主要有两个“surface”和“component”字段可供选择。
对于“component”类型,主要用于实现动态加载显示内容的目的。
文本提示气泡
文本提示气泡常用于只展示带有文本的信息提示,不带有任何交互的场景。Popup属性需绑定组件,当bindPopup属性中参数show为true时会弹出气泡提示。
在Button组件上绑定Popup属性,每次点击Button按钮,handlePopup会切换布尔值,当值为true时,触发bindPopup弹出气泡。
通过onStateChange参数为气泡添加状态变化的事件回调,可以判断当前气泡的显示状态。
带按钮的提示气泡
通过primaryButton、secondaryButton属性为气泡最多设置两个Button按钮,通过此按钮进行简单的交互,开发者可以通过配置action参数来设置想要触发的操作。
自定义气泡
开发者可以使用构建器CustomPopupOptions创建自定义气泡,@Builder中可以放自定义的内容。除此之外,还可以通过popupColor等参数控制气泡样式。
创建默认样式的菜单
菜单需要调用bindMenu接口来实现。bindMenu响应绑定组件的点击事件,绑定组件后手势点击对应组件后即可弹出。
Button('clickforMenu').bindMenu([{value:'Menu1',action:()=>{console.info('handleMenu1select')}}])创建自定义样式的菜单
当默认样式不满足开发需求时,可使用@Builder定义菜单内容,通过bindMenu接口进行菜单的自定义。
@Builder开发菜单内的内容
创建支持右键或长按的菜单
通过bindContextMenu接口自定义菜单,设置菜单弹出的触发方式,触发方式为右键或长按。使用bindContextMenu弹出的菜单项是在独立子窗口内的,可显示在应用窗口外部。
@Builder开发菜单内的内容与上文写法相同。
确认菜单的弹出方式,使用bindContextMenu属性绑定组件。示例中为右键弹出菜单。
沿垂直方向布局的容器组件。
垂直方向分隔布局容器组件,将子组件纵向布局,并在每个子组件之间插入一根横向的分割线。
沿水平方向布局的容器组件。
水平方向分隔布局容器组件,将子组件横向布局,并在每个子组件之间插入一根纵向的分割线。
提供侧边栏可以显示和隐藏的侧边栏容器组件,通过子组件定义侧边栏和内容区,第一个子组件表示侧边栏,第二个子组件表示内容区。
堆叠容器组件,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
以弹性方式布局子组件的容器组件。
纵向排布栅格布局容器组件,仅在栅格布局场景中使用。
栅格容器组件,仅可以和栅格子组件(GridCol)在栅格布局场景中使用。
栅格子组件,必须作为栅格容器组件(GridRow)的子组件使用。
相对布局组件,用于复杂场景中元素对齐的布局。
列表包含一系列相同宽度的列表项,适合连续、多行呈现同类数据,例如图片和文本。
用来展示具体列表项,必须配合List来使用。
用来展示分组列表项的组件,必须配合List组件来使用。
网格容器组件,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
网格容器中单项内容容器。
可滚动的容器组件,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。
滑块视图容器组件,提供子组件滑动轮播显示的能力。
瀑布流容器组件,由“行”和“列”分割的单元格所组成,通过容器自身的排列规则,将不同大小的“项目”自上而下,如瀑布般紧密布局。
瀑布流组件WaterFlow的子组件,用来展示瀑布流具体item。
路由容器组件,提供路由跳转能力。
一般作为Page页面的根容器,通过属性设置来展示页面的标题栏、工具栏、导航栏等。
导航组件,默认提供点击响应处理,不需要开发者自定义点击事件逻辑。
作为NavRouter组件的子组件,用于显示导航内容区。
步骤导航器组件,适用于引导用户按照步骤完成任务的导航场景。
Stepper组件的子组件。
通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
仅在Tabs组件中使用,对应一个切换页签的内容视图。
按钮组件,可快速创建不同样式的按钮。
组件提供勾选框样式、状态按钮样式及开关样式。
提供多选框组件,通常用于某选项的打开或关闭。
多选框群组,用于控制多选框全选或者不全选状态。
提供下拉日历弹窗,可以让用户选择日期。
选择日期的滑动选择器组件。
滑动选择文本内容的组件。
单选框,提供相应的用户交互选择项。
提供在给定范围内选择评分的组件。
提供下拉选择菜单,可以让用户在多个选项之间选择。
滑动条组件,通常用于快速调节设置值,如音量调节、亮度调节等应用场景。
计数器组件,提供相应的增加或者减少的计数操作。
显示一段文本的组件。
作为Text组件的子组件,用于显示行内文本片段的组件。
搜索框组件,适用于浏览器的搜索内容输入框等应用场景。
多行文本输入框组件,当输入的文本内容超过组件宽度时会自动换行显示。
单行文本输入框组件。
图案密码锁组件,以九宫格图案的方式输入密码,用于密码验证场景。手指在PatternLock组件区域按下时开始进入输入状态,手指离开屏幕时结束输入状态完成密码输入。
富文本组件,解析并显示HTML格式文本。
支持图文混排和文本交互式编辑的组件。
图片组件,支持本地图片和网络图片的渲染展示。
提供逐帧播放图片能力的帧动画组件,可以配置需要播放的图片列表,每张图片可以配置时长。
用于播放视频文件并控制其播放状态的组件。
提供外部应用组件嵌入式显示功能,即外部应用提供的UI可在本应用内显示。
用于EGL/OpenGLES和媒体数据写入。
数据面板组件,用于将多个数据占比情况使用占比图进行展示。
数据量规图表组件,用于将数据展示为环形图表。
用于显示加载动效的组件。
跑马灯组件,用于滚动展示一段单行文本,仅当文本内容宽度超过跑马灯组件宽度时滚动。
进度条组件,用于显示内容加载或操作处理等进度。
用于显示单个二维码的组件。
通过文本显示计时信息并控制其计时器状态的组件。
空白填充组件,在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column时生效。
分隔器组件,分隔不同内容块/内容元素。
提供画布组件,用于自定义绘制图形。
用于绘制圆形的组件。
椭圆绘制组件。
直线绘制组件。
折线绘制组件。
多边形绘制组件。
路径绘制组件,根据绘制路径生成封闭的自定义形状。
矩形绘制组件。
作为绘制组件的父组件,实现类似SVG的效果,父组件中会描述所有绘制组件均支持的通用属性。
滚动条组件,用于配合可滚动组件使用,如List、Grid、Scroll等。
可以附加在单个组件上用于信息标记的容器组件。
可以与容器组件联动用于按逻辑结构快速定位容器显示区域的索引条组件。
可滑动面板,提供一种轻量的内容展示窗口,方便在不同尺寸中切换。
可以进行页面下拉操作并显示刷新动效的容器组件。
独立显示Ability的容器组件。
远程控制窗口组件,可以通过此组件控制应用窗口,提供启动退出过程中控件动画和应用窗口联动动画的能力。
提供卡片组件,实现卡片的显示功能。
提供静态卡片事件交互功能。
超链接组件,组件宽高范围内点击实现跳转。
以垂直列表形式显示的菜单。
用来展示菜单Menu中具体的item菜单项。
用来展示菜单MenuItem的分组。
在页面中嵌入显示带UI界面的Ability扩展的容器组件。
安全控件的粘贴控件,用户通过点击该粘贴控件,可以临时获取读取剪贴板权限,而不会触发toast提示。