布局、组成部分
布局
线性布局 (Row/Column)
线性容器Row和Column构建,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。
在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。
可以通过alignItems属性设置子元素在交叉轴(排列方向的垂直方向)上的对齐方式。
1.alignItems(HorizontalAlign.Start)子元素在水平方向左对齐。
2.alignItems(HorizontalAlign.Center)子元素在水平方向居中对齐。
3.alignItems(HorizontalAlign.End)子元素在水平方向右对齐。
4.alignItems(VerticalAlign.Top)子元素在垂直方向顶部对齐。
5.alignItems(VerticalAlign.Center)子元素在垂直方向居中对齐。
6.alignItems(VerticalAlign.Bottom)子元素在垂直方向底部对齐。
可以通过justifyContent属性设置子元素在容器主轴上的排列方式。
1.justifyContent(FlexAlign.Start):元素在首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。
2.justifyContent(FlexAlign.Center):元素在中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。
3.justifyContent(FlexAlign.End):元素在尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。
4.justifyContent(FlexAlign.SpaceBetween):均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。
5.justifyContent(FlexAlign.SpaceAround):均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。
6.justifyContent(FlexAlign.SpaceEvenly):均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。
自适应拉伸
在线性布局下,常用空白填充组件Blank,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。
自适应延伸
自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示
1.在List中添加滚动条
2.使用Scroll组件
.scrollable(ScrollDirection.Vertical) // 滚动方向为垂直方向.scrollBar(BarState.On) // 滚动条常驻显示.scrollBarColor(Color.Gray) // 滚动条颜色.scrollBarWidth(10) // 滚动条宽度.edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹
层叠布局 (Stack)
层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局
Stack组件为容器组件,容器内可包含各种子元素。其中子元素默认进行居中堆叠。
Stack组件通过alignContent参数实现位置的相对移动。
Stack({alignContent:Alignment.TopStart}){//左上角Text('第一个子元素').width('80%').height(260).backgroundColor('#faf').zIndex(100)Text('第2个子元素').width('60%').height(230).backgroundColor('#fcf').zIndex(101)Text('第3个子元素').width('40%').height(200).backgroundColor('#fef').zIndex(102)}.width('90%').height(300).backgroundColor('gray')
弹性布局 (Flex)
弹性布局(Flex)提供更加有效的方式对容器中的子元素进行排列、对齐和分配剩余空间。
概念
主轴:Flex组件布局方向的轴线,子元素默认沿着主轴排列。主轴开始的位置称为主轴起始点,结束位置称为主轴结束点。
交叉轴:垂直于主轴方向的轴线。交叉轴开始的位置称为交叉轴起始点,结束位置称为交叉轴结束点。
布局方向
通过设置参数direction,可以决定主轴的方向,从而控制子元素的排列方向。
1.direction: FlexDirection.Row主轴为水平方向,子元素从起始端沿着水平方向开始排布。
2.direction: FlexDirection.RowReverse主轴为水平方向,子元素从终点端沿着FlexDirection. Row相反的方向开始排布。
3.direction: FlexDirection.Column主轴为垂直方向,子元素从起始端沿着垂直方向开始排布。
4.direction: FlexDirection.ColumnReverse 主轴为垂直方向,子元素从终点端沿着FlexDirection. Column相反的方向开始排布。
布局换行
wrap属性控制当子元素主轴尺寸之和大于容器主轴尺寸时,Flex是单行布局还是多行布局。
1.wrap: FlexWrap.NoWrap 不换行。如果子元素的宽度总和大于父元素的宽度,则子元素会被压缩宽度。
2.wrap: FlexWrap.Wrap换行,每一行子元素按照主轴方向排列。
3.wrap: FlexWrap.WrapReverse换行,每一行子元素按照主轴反方向排列。
主轴对齐方式
通过justifyContent参数设置子元素在主轴方向的对齐方式。
1.justifyContent: FlexAlign.Start子元素在主轴方向起始端对齐, 第一个子元素与父元素边沿对齐,其他元素与前一个元素对齐。
2.justifyContent: FlexAlign.Center子元素在主轴方向居中对齐。
3.justifyContent: FlexAlign.End 子元素在主轴方向终点端对齐, 最后一个子元素与父元素边沿对齐,其他元素与后一个元素对齐。
4.justifyContent: FlexAlign.SpaceBetweenFlex主轴方向均匀分配弹性元素,相邻子元素之间距离相同。第一个子元素和最后一个子元素与父元素边沿对齐。
5.justifyContent: FlexAlign.SpaceAroundFlex主轴方向均匀分配弹性元素,相邻子元素之间距离相同。第一个子元素到主轴起始端的距离和最后一个子元素到主轴终点端的距离是相邻元素之间距离的一半。
6.justifyContent: FlexAlign.SpaceEvenlyFlex主轴方向元素等间距布局,相邻子元素之间的间距、第一个子元素与主轴起始端的间距、最后一个子元素到主轴终点端的间距均相等。
交叉轴对齐
可以通过Flex组件的alignItems参数设置子元素在交叉轴的对齐方式。
1.alignItems: ItemAlign.Auto 使用Flex容器中默认配置。
2.alignItems: ItemAlign.Start交叉轴方向首部对齐。
3.alignItems: ItemAlign.Center 交叉轴方向居中对齐。
4.alignItems: ItemAlign.End交叉轴方向底部对齐。
5.alignItems: ItemAlign.Stretch 交叉轴方向拉伸填充,在未设置尺寸时,拉伸到容器尺寸。
6.alignItems: ItemAlign.Baseline 交叉轴方向文本基线对齐。
子元素的alignSelf属性也可以设置子元素在父容器交叉轴的对齐格式,且会覆盖Flex布局容器中alignItems配置。
内容对齐
可以通过alignContent参数设置子元素各行在交叉轴剩余空间内的对齐方式,只在多行的Flex布局中生效
1.alignContent: FlexAlign.Start子元素各行与交叉轴起点对齐。
2.alignContent: FlexAlign.Center子元素各行在交叉轴方向居中对齐。
3.alignContent: FlexAlign.End子元素各行与交叉轴终点对齐。
4.alignContent: FlexAlign.SpaceBetween子元素各行与交叉轴两端对齐,各行间垂直间距平均分布。
5.alignContent: FlexAlign.SpaceAround子元素各行间距相等,是元素首尾行与交叉轴两端距离的两倍。
6.alignContent: FlexAlign.SpaceEvenly 子元素各行间距,子元素首尾行与交叉轴两端距离都相等。
自适应拉伸
在弹性布局父组件尺寸过小时,通过子元素的以下属性设置其在父容器的占比,达到自适应布局。
1.flexBasis:设置子元素在父容器主轴方向上的基准尺寸。
.flexBasis('auto')
2.flexGrow:设置父容器的剩余空间分配给此属性所在组件的比例。用于分配父组件的剩余空间。
.flexGrow(2)
相对布局 (RelativeContainer)
RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。
概念
锚点:通过锚点设置当前元素基于哪个元素确定位置。
对齐方式:通过对齐方式,设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐。
锚点设置
在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。
ID默认为“container”,其余子元素的ID通过id属性设置。
//相对布局RelativeContainer(){Row(){}.height(100).width(100).backgroundColor('blue')//alignRules:定位规则.alignRules({//anchor锚点'bottom':{'anchor':'__container__',align:VerticalAlign.Bottom},'right':{'anchor':'__container__',align:HorizontalAlign.End}})Row(){}.height(100).width(100).backgroundColor('red').alignRules({'top':{'anchor':'__container__',align:VerticalAlign.Top},'left':{'anchor':'__container__',align:HorizontalAlign.Start}})Row(){}.height(100).width(100).backgroundColor('red').alignRules({//正中间'center':{'anchor':'__container__',align:VerticalAlign.Center},'middle':{'anchor':'__container__',align:HorizontalAlign.Center}})}.width('100%').height(300).backgroundColor('gray').id('__container__')//系统默认生成
以兄弟元素为锚点。
RelativeContainer(){Row().height(100).width(100).backgroundColor('red').id('r1').alignRules({'middle':{'anchor':'__container__',align:HorizontalAlign.Center}})Row().height(100).width(100).backgroundColor('blue').id('r2')//锚点.alignRules({//HorizontalAlign:水平'left':{'anchor':'r1',align:HorizontalAlign.End}})Row().height(100).width(100).backgroundColor('blue').alignRules({//VerticalAlign:垂直'top':{'anchor':'r1',align:VerticalAlign.Bottom},'left':{'anchor':'r1',align:HorizontalAlign.Start}})Row().height(100).width(100).backgroundColor('green').alignRules({//VerticalAlign:垂直'top':{'anchor':'r2',align:VerticalAlign.Bottom},'left':{'anchor':'r2',align:HorizontalAlign.Start}})}.width('100%').height(300).backgroundColor('#faf')
设置相对于锚点的对齐位置
设置了锚点之后,可以通过align设置相对于锚点的对齐位置。
在水平方向上,对齐位置可以设置为HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End。
在竖直方向上,对齐位置可以设置为VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom。
子组件位置偏移
子组件经过相对位置对齐后,位置可能还不是目标位置,开发者可根据需要进行额外偏移设置offset。
Row().height(100).width(100).backgroundColor('#ccc').alignRules({//VerticalAlign:垂直'top':{'anchor':'r2',align:VerticalAlign.Bottom},'left':{'anchor':'r2',align:HorizontalAlign.Start}}).offset({x:-50,y:-50})
栅格布局 (GridRow/GridCol)
栅格布局是一种通用的辅助定位工具,对移动设备的界面设计有较好的借鉴作用。
GridRow为栅格容器组件,需与栅格子组件GridCol在栅格布局场景中联合使用。
栅格系统断点
栅格系统以设备的水平宽度作为断点依据,定义设备的宽度类型,形成了一套断点规则。
栅格系统默认断点将设备宽度分为xs、sm、md、lg四类
xs:最小宽度类型设备。
sm:小宽度类型设备
md:中等宽度类型设备。
lg:大宽度类型设备。
//栅格布局GridRow() {GridCol({span:{xs:12,sm:6,md:3,lg:1}}){Text('11111111111111111111111111111111111111111111111111')}.backgroundColor('red')GridCol({span:{xs:12,sm:6,md:3,lg:1}}){Text('2')}.backgroundColor('blue')GridCol(){Text('3')}.backgroundColor('green')GridCol(){Text('4')}.backgroundColor('gray')}.height('30%').width('100%')
布局的总列数
GridRow中通过columns设置栅格布局的总列数。
columns默认值为12,即在未设置columns时,任何断点下,栅格布局被分成12列。
当columns为自定义值,栅格布局在任何尺寸设备下都被分为columns列。
当columns类型为GridRowColumnOption时,支持下面六种不同尺寸(xs, sm, md, lg, xl, xxl)设备的总列数设置,各个尺寸下数值可不同。
GridRow({columns:8,direction:GridRowDirection.RowReverse,gutter:{x:15,y:5}}){ForEach(this.color,(c:Color,index:number)=>{GridCol({span:{xs:8,sm:4,md:2,lg:1}}){Text(`${index}`).fontColor(Color.White)}.backgroundColor(c)})}.width('100%').border({style:BorderStyle.Solid,width:1,color:'red'})
排列方向
栅格布局中,可以通过设置GridRow的direction属性来指定栅格子组件在栅格容器中的排列方向。该属性可以设置为GridRowDirection.Row(从左往右排列)或GridRowDirection.RowReverse(从右往左排列)
1.GridRow({ direction: GridRowDirection.Row })子组件默认从左往右排列。
2.GridRow({ direction: GridRowDirection.RowReverse })子组件从右往左排列。
子组件间距
GridRow中通过gutter属性设置子元素在水平和垂直方向的间距。
- GridRow({ gutter: 10 })当gutter类型为number时,同时设置栅格子组件间水平和垂直方向边距且相等。下例中,设置子组件水平与垂直方向距离相邻元素的间距为10。
2.GridRow({ gutter: { x: 20, y: 50 } })当gutter类型为GutterOption时,单独设置栅格子组件水平垂直边距,x属性为水平方向间距,y为垂直方向间距。
子组件GridCol
GridCol组件作为GridRow组件的子组件,通过给GridCol传参或者设置属性两种方式,设置span(占用列数),offset(偏移列数),order(元素序号)的值。
1.GridCol({ span: 2 })设置span。
2.GridCol({ offset: 2 })设置offset。
3.GridCol({ order: 2 })设置order。
span
子组件占栅格布局的列数,决定了子组件的宽度,默认为1。
-
GridCol({ span: 2 })当类型为number时,子组件在所有尺寸设备下占用的列数相同
-
GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 } }) 当类型为GridColColumnOption时,支持六种不同尺寸(xs, sm, md, lg, xl, xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
offset
栅格子组件相对于前一个子组件的偏移列数,默认为0。
-
GridCol({ offset: 2 })当类型为number时,子组件偏移相同列数
-
GridCol({ offset: { xs: 1, sm: 2, md: 3, lg: 4 } })当类型为GridColColumnOption时,支持六种不同尺寸(xs, sm, md, lg, xl, xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
order
栅格子组件的序号,决定子组件排列次序。当子组件不设置order或者设置相同的order, 子组件按照代码顺序展示。当子组件设置不同的order时,order较小的组件在前,较大的在后。
- GridCol({ order: 4 })当类型为number时,子组件在任何尺寸下排序次序一致。
2.GridCol({ order: { xs:1, sm:5, md:3, lg:7}}) 当类型为GridColColumnOption时,支持六种不同尺寸(xs, sm, md, lg, xl, xxl)设备中子组件排序次序设置。在xs设备中,子组件排列顺序为1234;sm为2341,md为3412,lg为2431。
嵌套使用
栅格组件也可以嵌套使用,完成一些复杂的布局。
GridRow() {GridCol({ span: { sm: 12 } }) {GridRow() {GridCol({ span: { sm: 2 } }) {Row() {Text('left').fontSize(24)}.justifyContent(FlexAlign.Center).height('90%')}.backgroundColor('#ff41dbaa')GridCol({ span: { sm: 10 } }) {Row() {Text('right').fontSize(24)}.justifyContent(FlexAlign.Center).height('90%')}.backgroundColor('#ff4168db')}.backgroundColor('#19000000')}GridCol({ span: { sm: 12 } }) {Row() {Text('footer').width('100%').textAlign(TextAlign.Center)}.width('100%').height('10%').backgroundColor(Color.Pink)}}.width('100%').height(300)
媒体查询 (@ohos.mediaquery)
-
针对设备和应用的属性信息(比如显示区域、深浅色、分辨率),设计出相匹配的布局。
2.当屏幕发生动态改变时(比如分屏、横竖屏切换),同步更新应用的页面布局。
引入与使用流程
首先导入媒体查询模块
import { mediaquery } from '@kit.ArkUI';
通过matchMediaSync接口设置媒体查询条件,保存返回的条件监听句柄listener。例如监听横屏事件:
listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('screen and (orientation: landscape)');//'(orientation: landscape)':横屏条件 screen and (orientation: landscape):屏幕效果//回调函数:当屏幕发生变化时,触发的函数 //mediaquery.MediaQueryResult:媒体查询的结果
给条件监听句柄listener绑定回调函数onPortrait,当listener检测设备状态变化时执行回调函数。在回调函数内,根据不同设备状态更改页面布局或者实现业务逻辑。
onPortrait(mr:mediaquery.MediaQueryResult){//mediaquery:返回值 onPortrait:函数if(mr.matches){//如果满足条件this.c=Color.Red}else {//不满足this.c=Color.Blue}}aboutToAppear(): void {//第一次调用函数this.listener.on('change',(mr:mediaquery.MediaQueryResult)=>{//this.onPortrait(mr)})//调用listener on()启动监听}
示例:
import { mediaquery } from '@kit.ArkUI';@Entry
@Component
struct Media3Page {@State message: string = 'Hello World';@State isSm:boolean=true //小屏true@State nrWidth:string='100%'//具体内容的宽度l1:mediaquery.MediaQueryListener=this.getUIContext().getMediaQuery().matchMediaSync('(width>1080px)')//屏幕宽度 折叠屏aboutToAppear(): void {this.l1.on('change',(mr)=>{if(mr.matches){//如果大于1080this.isSm=false//变大屏this.nrWidth='80%'//具体内容的宽度变80%}else{//如果小于1080this.isSm=true//变小屏this.nrWidth='100%'//具体内容的宽度变100%}})}build() {Column(){if(this.isSm){//小屏显示Row(){Text('横向的导航')}.width('100%').backgroundColor('#ccc').height(60)}Row(){if(!this.isSm){//小屏不显示Column(){Text('左侧导航')}.width('20%').backgroundColor('#ddd').height('100%')}Column(){Text('具体内容')}.backgroundColor('#eee').height('100%').width(this.nrWidth)}.width('100%')}.height('100%').width('100%')}
}
创建列表 (List)
列表是一种复杂的容器,当列表项达到一定数量,内容超过屏幕大小时,可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集,例如图片和文本。
使用列表可以轻松高效地显示结构化、可滚动的信息。通过在List组件中按垂直或者水平方向线性排列子组件ListItemGroup或ListItem,为列表中的行或列提供单个视图,或使用循环渲染迭代一组行或列,或混合任意数量的单个视图和ForEach结构,构建一个列表。
布局与约束
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
在垂直列表中,List按垂直方向自动排列ListItemGroup或ListItem。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。
布局
List除了提供垂直和水平布局能力、超出屏幕时可以滚动的自适应延伸能力之外,还提供了自适应交叉轴方向上排列个数的布局能力。
利用垂直布局能力可以构建单列或者多列垂直滚动列表
利用水平布局能力可以是构建单行或多行水平滚动列表
约束
列表的主轴方向是指子组件列的排列方向,也是列表的滚动方向。垂直于主轴的轴称为交叉轴,其方向与主轴方向相互垂直。
垂直列表的主轴是垂直方向,交叉轴是水平方向;水平列表的主轴是水平方向,交叉轴是垂直方向。
1.如果List组件主轴或交叉轴方向设置了尺寸,则其对应方向上的尺寸为设置值。
2.如果List组件主轴方向没有设置尺寸,当List子组件主轴方向总尺寸小于List的父组件尺寸时,List主轴方向尺寸自动适应子组件的总尺寸。
3.如果子组件主轴方向总尺寸超过List父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。
设置主轴方向
List组件主轴默认是垂直方向,即默认情况下不需要手动设置List方向,就可以构建一个垂直滚动列表。
若是水平滚动列表场景,将List的listDirection属性设置为Axis.Horizontal即可实现。
listDirection默认为Axis.Vertical,即主轴默认是垂直方向。
//主轴方向
@Builder test1(){List({space:5}){ForEach(this.nums,(n:number,index)=>{ListItem(){Text(n.toString()).width(150).height(150).backgroundColor('#abc')}})}.listDirection(Axis.Horizontal)//水平方向
}
设置交叉轴布局
List组件的交叉轴布局可以通过lanes和alignListItem属性进行设置,lanes属性用于确定交叉轴排列的列表项数量,alignListItem用于设置子组件在交叉轴方向的对齐方式。
List组件的lanes属性通常用于在不同尺寸的设备自适应构建不同行数或列数的列表,即一次开发、多端部署的场景
lanes属性的取值类型是"number | LengthConstrain",即整数或者LengthConstrain类型。
//交叉轴方向@Builder test2(){List({space:5}){ForEach(this.nums,(n:number,index)=>{ListItem(){Text(n.toString()).width(150).height(150).backgroundColor('#abc')}})}.listDirection(Axis.Vertical).lanes(2).alignListItem(ListItemAlign.Center)}
当其取值为LengthConstrain类型时,表示会根据LengthConstrain与List组件的尺寸自适应决定行或列数
autoList:LengthConstrain={maxLength:350,minLength:180}//最大max 最小min 主要用最小量行数//自适应行数@Builder test3(){List({space:5}){ForEach(this.nums,(n:number,index)=>{ListItem(){Text(n.toString()).width(150).height(150).backgroundColor('#abc')}})}// .listDirection(Axis.Horizontal)//水平.lanes(this.autoList).alignListItem(ListItemAlign.Center)// .height(400).width(400)}
由于在ListItem中只能有一个根节点组件,不支持以平铺形式使用多个组件。因此,若列表项是由多个组件元素组成的,则需要将这多个元素组合到一个容器组件内或组成一个自定义组件。
List() {ListItem() {Row() {Image($r('app.media.iconE')).width(40).height(40).margin(10)Text('小明').fontSize(20)}}ListItem() {Row() {Image($r('app.media.iconF')).width(40).height(40).margin(10)Text('小红').fontSize(20)}}
}
迭代列表内容
使用循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件,降低代码复杂度。
ArkTS通过ForEach提供了组件的循环渲染能力。
class Lxr{touimg:ResourceStrname:stringconstructor(touimg: ResourceStr, name: string) {this.touimg = touimg;this.name = name;}
}
@Entry
@Component
struct ListPage {@State lxr:Lxr[]=[new Lxr($r('app.media.th'),'张三'),new Lxr($r('app.media.nai'),'王五'),new Lxr($r('app.media.pj'),'李四'),new Lxr($r('app.media.shoji'),'赵六'),new Lxr($r('app.media.5'),'琪琪'),new Lxr($r('app.media.6'),'十八'),new Lxr($r('app.media.1'),'久久'),new Lxr($r('app.media.7'),'试试'),new Lxr($r('app.media.8'),'一一'),new Lxr($r('app.media.9'),'呃呃'),new Lxr($r('app.media.10'),'三三'),new Lxr($r('app.media.12'),'四三'),new Lxr($r('app.media.13'),'五三'),]build() {Column(){this.txl()}.height('100%').width('100%')}@Builder txl(){List({space:10,scroller:this.sc}){ForEach(this.lxr,(l:Lxr,index)=>{ListItem(){Row(){Image(l.touimg).borderRadius(100).width(50).height(50)Text(l.name).fontSize(30)}.width('100%').backgroundColor('#aaa')}})}}
}
自定义列表样式
设置内容间距
在初始化列表时,如需在列表项之间添加间距,可以使用space参数。
List({space:10}){//...}
添加分隔线
分隔线用来将界面元素隔开,使单个元素更加容易识别。
List提供了divider属性用于给列表项之间添加分隔线。在设置divider属性时,可以通过strokeWidth和color属性设置分隔线的粗细和颜色。
startMargin和endMargin属性分别用于设置分隔线距离列表侧边起始端的距离和距离列表侧边结束端的距离。
class DividerTem{//分隔符color:ResourceColorstrokeWidth:numberstartMargin:numberendMargin:numberconstructor(color: ResourceColor, strokeWidth: number, startMargin: number, endMargin: number) {this.color = color;this.strokeWidth = strokeWidth;this.startMargin = startMargin;this.endMargin = endMargin;}
}
@Entry
@Component
struct ListPage {
List(){//...}.divider(this.dTem).divider({//分隔符color:'red',strokeWidth:2,//宽度startMargin:10,endMargin:50})
}
添加滚动条
当列表项高度(宽度)超出屏幕高度(宽度)时,列表可以沿垂直(水平)方向滚动。
在使用List组件时,可通过scrollBar属性控制列表滚动条的显示。scrollBar的取值类型为BarState,当取值为BarState.Auto表示按需显示滚动条。
scrollBar属性API version 9及以下版本默认值为BarState.Off,从API version 10版本开始默认值为BarState.Auto。
List({space:10,scroller:this.sc}){//...}.scrollBar(BarState.Off)//滚动条
支持分组列表
在列表中支持数据的分组展示,可以使列表显示结构清晰,查找方便,从而提高使用效率。
在List组件中使用ListItemGroup对项目进行分组,可以构建二维列表。
在List组件中可以直接使用一个或者多个ListItemGroup组件,ListItemGroup的宽度默认充满List组件。在初始化ListItemGroup时,可通过header参数设置列表分组的头部组件。
@Builder group(str:string){Text(str).fontSize(30).width('100%').backgroundColor('gray').height(50)}
List(){ListItemGroup({space:20,header:this.group('A')}){//header头部ForEach(this.lxrA,(l:Lxr,i)=>{ListItem(){Row(){Image(l.touimg).borderRadius(100).height(50).width(50)Text(l.name).fontSize(30)}.width('100%')}})}.divider(this.dTem1)ListItemGroup({space:20,header:this.group('B')}){//header头部ForEach(this.lxrB,(l:Lxr,i)=>{ListItem(){Row(){Image(l.touimg).borderRadius(100).height(50).width(50)Text(l.name).fontSize(30)}.width('100%')}})}.divider(this.dTem1)ListItemGroup({space:20,header:this.group('C')}){//header头部ForEach(this.lxrC,(l:Lxr,i)=>{ListItem(){Row(){Image(l.touimg).borderRadius(100).height(50).width(50)Text(l.name).fontSize(30)}.width('100%')}})}.divider(this.dTem1)}
添加粘性标题
粘性标题是一种常见的标题模式,常用于定位字母列表的头部元素。
粘性标题不仅有助于阐明列表中数据的表示形式和用途,还可以帮助用户在大量信息中进行数据定位,从而避免用户在标题所在的表的顶部与感兴趣区域之间反复滚动。
List组件的sticky属性配合ListItemGroup组件使用,用于设置ListItemGroup中的头部组件是否呈现吸顶效果或者尾部组件是否呈现吸底效果。
通过给List组件设置sticky属性为StickyStyle.Header,即可实现列表的粘性标题效果。
@Builder txl3(){List(){ForEach(this.txls,(txl:Txl,index)=>{ListItemGroup({header:this.group(txl.group)}){ForEach(txl.lxr,(lxr:Lxr,i)=>{ListItem(){Row(){Image(lxr.touimg).borderRadius(100).height(50).width(50)Text(lxr.name).fontSize(30)}.width('100%')}})}.divider(this.dTem1)})}.sticky(StickyStyle.Header)//标题不滚动
}
控制滚动位置
控制滚动位置在实际应用中十分常见,例如当新闻页列表项数量庞大,用户滚动列表到一定位置时,希望快速滚动到列表底部或返回列表顶部。
List组件初始化时,可以通过scroller参数绑定一个Scroller对象,进行列表的滚动控制。
sc:Scroller=new Scroller()//返回顶部Stack({alignContent:Alignment.End}){List({scroller:this.sc}){ForEach(this.txls,(txl:Txl,index)=>{ListItemGroup({header:this.group(txl.group)}){ForEach(txl.lxr,(lxr:Lxr,i)=>{ListItem(){Row(){Image(lxr.touimg).borderRadius(100).height(50).width(50)Text(lxr.name).fontSize(30)}.width('100%')}})} .divider(this.dTem1)})}.sticky(StickyStyle.Header)}
响应滚动位置
许多应用需要监听列表的滚动位置变化并作出响应。
除了字母索引之外,滚动列表结合多级分类索引在应用开发过程中也很常见,例如购物应用的商品分类页面,多级分类也需要监听列表的滚动位置。
字母索引响应联系人列表滚动
@Builder txl4(){Stack({alignContent:Alignment.End}){List({scroller:this.sc}){ForEach(this.txls,(txl:Txl,index)=>{ListItemGroup({header:this.group(txl.group)}){ForEach(txl.lxr,(lxr:Lxr,i)=>{ListItem(){Row(){Image(lxr.touimg).borderRadius(100).height(50).width(50)Text(lxr.name).fontSize(30)}.width('100%')}})} .divider(this.dTem1)})}.sticky(StickyStyle.Header)// Button('^').onClick(()=>{// this.sc.scrollToIndex(0)// }).onScrollIndex((fristIndex:number)=>{this.selected=fristIndex})AlphabetIndexer({arrayValue:this.xh,selected:0}).selected(this.selected).selectedFont({size:40}).font({size:30}).itemSize(60)}}
通过监听List组件的onScrollIndex事件来实现,右侧索引栏需要使用字母表索引组件AlphabetIndexer。
在列表滚动时,根据列表此时所在的索引值位置firstIndex,重新计算字母索引栏对应字母的位置selectedIndex。
响应列表项侧滑
侧滑菜单在许多应用中都很常见。
ListItem的swipeAction属性可用于实现列表项的左右滑动功能。swipeAction属性方法初始化时有必填参数SwipeActionOptions,其中,start参数表示设置列表项右滑时起始端滑出的组件,end参数表示设置列表项左滑时尾端滑出的组件。
build() {Column(){List(){ForEach(this.diab,(d:dianhua,i)=>{ListItem(){Row({space:5}){Column({space:5}){Text(d.names).fontSize(20).alignSelf(ItemAlign.Start)Row({space:5}){Text(`${d.ka}`).backgroundColor(Color.Gray).fontColor(Color.White).padding(1).fontSize(12).fontWeight(600)Image($r('app.media.hd')).height(20)Text(d.dizhi)}.width('100%').justifyContent(FlexAlign.Start)}.width('70%')Row({space:5}){Text(d.shijian)Image(d.xq).width(25)}}.padding({left:15,right:15,top:10,bottom:10}).width('100%').justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end:this.shan(i)})})}.height(581).divider({//分隔符color:'#eee',strokeWidth:1,//宽度startMargin:10,endMargin:50})}.height('100%').width('100%')}@Builder shan(index:number){Button({type:ButtonType.Normal}){SymbolGlyph($r('sys.symbol.trash')).fontSize(30)}.width(50).height(50).backgroundColor('#fff')}
创建网格 (Grid/GridItem)
网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
Grid组件为网格容器,其中容器内各条目对应一个GridItem组件
设置行列数量与占比
通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。
rowsTemplate和columnsTemplate属性值是一个由多个空格和’数字+fr’间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列宽度。
@Builder test1(){Grid(){ForEach([1,2,3,4,5,6,7,8,9],(n:number)=>{GridItem(){Text(n.toString())}.backgroundColor('blue')})}.width('100%').height(300).rowsTemplate('1fr 1fr 1fr')//行的占比.columnsTemplate('1fr 1fr 2fr')//列的占比.rowsGap(5)//行间距.columnsGap(5)//列间距}
只要将rowsTemplate的值为’1fr 1fr 1fr’,同时将columnsTemplate的值为’1fr 2fr 1fr’,即可实现上述网格布局。
设置子组件所占行列数
通过创建Grid时传入合适的GridLayoutOptions实现如图所示的单个网格横跨多行或多列的场景
不均匀网格布局
在网格中,可以通过onGetRectByIndex返回的[rowStart,columnStart,rowSpan,columnSpan]来实现跨行跨列布局,其中rowStart和columnStart属性表示指定当前元素起始行号和起始列号,rowSpan和columnSpan属性表示指定当前元素的占用行数和占用列数。
ly:GridLayoutOptions={regularSize:[1,1],//一个单元格所占的大小onGetRectByIndex:(index)=>{if(index==0){//下标是0时//[行,列,行数,列数]return [0,0,1,1]//0,0,坐标从第几行第几列开始 1,1,占行和列的数量}else if(index==1){return [0,1,1,1]}else if(index==2){return [0,2,1,2]}else if(index==3){return [1,0,2,1]}else if(index==7){return [1,1,1,3]}//只需要写需要改的部分return[0,0,1,1]//返回4个值}}
@Builder test2(){Grid(undefined,this.ly){ForEach([0,1,2,3,4,5,6,7],(n:number)=>{GridItem(){Text(n.toString())}.backgroundColor('blue')})}.width('100%').height(300).rowsTemplate('1fr 1fr 1fr')//行的占比.columnsTemplate('1fr 1fr 1fr 1fr')//列的占比.rowsGap(5)//行间距.columnsGap(5)//列间距}
设置主轴方向
使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection设置网格布局的主轴方向,决定子组件的排列方式。
当前layoutDirection设置为Row时,先从左到右排列,排满一行再排下一行。
Grid() {...
}
.maxCount(3)
.layoutDirection(GridDirection.Row)
在网格布局中显示数据
网格布局采用二维布局的方式组织其内部元素,如下图所示
Grid组件可以通过二维布局的方式显示一组GridItem子组件。
Grid() {GridItem() {Text('会议')...}GridItem() {Text('签到')...}GridItem() {Text('投票')...}GridItem() {Text('打印')...}
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr')
对于内容结构相似的多个GridItem,通常更推荐使用ForEach语句中嵌套GridItem的形式,来减少重复代码。
@Builder test2(){Grid(undefined,this.ly){ForEach([0,1,2,3,4,5,6,7],(n:number)=>{GridItem(){Text(n.toString())}.backgroundColor('blue')})}.width('100%').height(300).rowsTemplate('1fr 1fr 1fr')//行的占比.columnsTemplate('1fr 1fr 1fr 1fr')//列的占比.rowsGap(5)//行间距.columnsGap(5)//列间距}
设置行列间距
在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距
通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。在图5所示的计算器中,行间距为15vp,列间距为10vp。
Grid() {...
}
.columnsGap(10)
.rowsGap(15)
构建可滚动的网格布局
可滚动的网格布局常用在文件管理、购物或视频列表等页面中
控制滚动位置
与新闻列表的返回顶部场景类似,控制滚动位置功能在网格布局中也很常用,例如下图所示日历的翻页功能。
Grid组件初始化时,可以绑定一个Scroller对象,用于进行滚动控制,例如通过Scroller对象的scrollPage方法进行翻页。
在日历页面中,用户在点击“下一页”按钮时,应用响应点击事件,通过指定scrollPage方法的参数next为true,滚动到下一页。
private s1:Scroller=new Scroller()//滚动器@State dates:number[]=[25,26,27,28,29,30,31,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,1,2,3,4,5,30,31,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,1,2,3,4,5,6,7,8,9]
@Builder test4(){Grid(this.s1){ForEach(this.dates,(day:number)=>{GridItem(){Text(day.toString())}.backgroundColor('#ccc').height(50)})}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr').width('100%').height(330).rowsGap(5).columnsGap(5).maxCount(3)Row(){Button('上一页').onClick(()=>{this.s1.scrollPage({next:false})//滚动到下一页或者上一页。})Button('下一页').onClick(()=>{this.s1.scrollPage({next:true})//滚动到下一页或者上一页。})}
}
创建轮播 (Swiper)
Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。
布局与约束
Swiper作为一个容器组件,如果设置了自身尺寸属性,则在轮播显示过程中均以该尺寸生效。
如果设置了prevMargin或者nextMargin属性,则Swiper自身尺寸会跟随其父组件;如果未设置prevMargin或者nextMargin属性,则会自动根据子组件的大小设置自身的尺寸。
循环播放
通过loop属性控制是否循环播放,该属性默认值为true
当loop为true时,在显示第一页或最后一页时,可以继续往前切换到前一页或者往后切换到后一页。如果loop为false,则在第一页或最后一页时,无法继续向前或者向后切换页面。
自动轮播
Swiper通过设置autoPlay属性,控制是否自动轮播子组件。该属性默认值为false。
Swiper() {// ...
}
.loop(true)
.autoPlay(true)
.interval(1000)
导航点样式
Swiper提供了默认的导航点样式和导航点箭头样式,导航点默认显示在Swiper下方居中位置,开发者也可以通过indicator属性自定义导航点的位置和样式,导航点箭头默认不显示。
导航点使用默认样式
Swiper(this.sc){//轮播Text('1').height(300).width('100%').backgroundColor('red')Text('2').height(300).width('100%').backgroundColor('blue')Text('3').height(300).width('100%').backgroundColor('green')Text('4').height(300).width('100%').backgroundColor('gray')Text('5').height(300).width('100%').backgroundColor('#faf')}.autoPlay(true)//自动播放.interval(1000)//使用自动播放时播放的时间间隔.indicator(//设置圆点Indicator.dot().left(10).itemWidth(10).selectedItemWidth(20).itemHeight(10).selectedItemHeight(20).color('black').selectedColor('white'))
自定义箭头样式
箭头显示在组件两侧,大小为18vp,导航点箭头颜色设为蓝色。
Swiper(this.sc){//轮播Text('1').height(300).width('100%').backgroundColor('red')Text('2').height(300).width('100%').backgroundColor('blue')Text('3').height(300).width('100%').backgroundColor('green')Text('4').height(300).width('100%').backgroundColor('gray')Text('5').height(300).width('100%').backgroundColor('#faf')}.autoPlay(true)//自动播放.interval(1000)//使用自动播放时播放的时间间隔.indicator(//设置圆点Indicator.dot().left(10).itemWidth(10).selectedItemWidth(20).itemHeight(10).selectedItemHeight(20).color('black').selectedColor('white'))// .displayArrow(true,false)//箭头.displayArrow({//左右箭头showBackground:true,//背景颜色isSidebarMiddle:true,//位置backgroundSize:50,//整体大小backgroundColor:'#abcdef',//背景颜色arrowSize:30,//箭头大小arrowColor:Color.White//箭头颜色},false)
页面切换方式
Swiper支持手指滑动、点击导航点和通过控制器三种方式切换页面,以下示例展示通过控制器切换页面的方法。
Swiper(this.sc){//轮播Text('1').height(300).width('100%').backgroundColor('red')Text('2').height(300).width('100%').backgroundColor('blue')Text('3').height(300).width('100%').backgroundColor('green')Text('4').height(300).width('100%').backgroundColor('gray')Text('5').height(300).width('100%').backgroundColor('#faf')}.autoPlay(true)//自动播放.interval(1000)//使用自动播放时播放的时间间隔.indicator(//设置圆点Indicator.dot().left(10).itemWidth(10).selectedItemWidth(20).itemHeight(10).selectedItemHeight(20).color('black').selectedColor('white'))// .displayArrow(true,false)//箭头.displayArrow({//左右箭头showBackground:true,//背景颜色isSidebarMiddle:true,//位置backgroundSize:50,//整体大小backgroundColor:'#abcdef',//背景颜色arrowSize:30,//箭头大小arrowColor:Color.White//箭头颜色},false).displayCount(2)//设置显示个数Row(){Button('上一页').onClick(()=>this.sc.showPrevious())Button('下一页').onClick(()=>this.sc.showNext())}
轮播方向
Swiper支持水平和垂直方向上进行轮播,主要通过vertical属性控制。
当vertical为true时,表示在垂直方向上进行轮播;为false时,表示在水平方向上进行轮播。vertical默认值为false。
1.设置水平方向上轮播。
Swiper() {// ...
}
.indicator(true)
.vertical(false)
2.设置垂直方向轮播。
Swiper() {// ...
}
.indicator(true)
.vertical(true)
每页显示多个子页面
Swiper支持在一个页面内同时显示多个子组件,通过displayCount属性设置。
Swiper(this.sc){//轮播Text('1').height(300).width('100%').backgroundColor('red')Text('2').height(300).width('100%').backgroundColor('blue')Text('3').height(300).width('100%').backgroundColor('green')Text('4').height(300).width('100%').backgroundColor('gray')Text('5').height(300).width('100%').backgroundColor('#faf')}.autoPlay(true)//自动播放.interval(1000)//使用自动播放时播放的时间间隔.indicator(//设置圆点Indicator.dot().left(10).itemWidth(10).selectedItemWidth(20).itemHeight(10).selectedItemHeight(20).color('black').selectedColor('white'))// .displayArrow(true,false)//箭头.displayArrow({//左右箭头showBackground:true,//背景颜色isSidebarMiddle:true,//位置backgroundSize:50,//整体大小backgroundColor:'#abcdef',//背景颜色arrowSize:30,//箭头大小arrowColor:Color.White//箭头颜色},false).displayCount(2)//设置显示个数
自定义切换动画
Swiper支持通过customContentTransition设置自定义切换动画,可以在回调中对视窗内所有页面逐帧设置透明度、缩放比例、位移、渲染层级等属性实现自定义切换动画。
Swiper(this.sc){//轮播Text('1').height(300).width('100%').backgroundColor('red')Text('2').height(300).width('100%').backgroundColor('blue')Text('3').height(300).width('100%').backgroundColor('green')Text('4').height(300).width('100%').backgroundColor('gray')Text('5').height(300).width('100%').backgroundColor('#faf')}.autoPlay(true)//自动播放
选项卡 (Tabs)
当页面信息较多时,为了让用户能够聚焦于当前显示的内容,需要对页面内容进行分类,提高页面空间利用率。Tabs组件可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量。
基本布局
Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。TabContent是内容页,TabBar是导航页签栏
Tabs使用花括号包裹TabContent
每一个TabContent对应的内容需要有一个页签,可以通过TabContent的tabBar属性进行配置。
TabContent组件上设置tabBar属性,可以设置其对应页签中的内容,tabBar作为内容的页签。
TabContent() {Text('首页的内容').fontSize(30)}
.tabBar('首页')
设置多个内容时,需在Tabs内按照顺序放置。
Tabs() {TabContent() {Text('首页的内容').fontSize(30)}.tabBar('首页')TabContent() {Text('推荐的内容').fontSize(30)}.tabBar('推荐')TabContent() {Text('发现的内容').fontSize(30)}.tabBar('发现')TabContent() {Text('我的内容').fontSize(30)}.tabBar("我的")
}
底部导航
底部导航是应用中最常见的一种导航方式。
导航栏位置使用Tabs的barPosition参数进行设置。默认情况下,导航栏位于顶部,此时,barPosition为BarPosition.Start。设置为底部导航时,需要将barPosition设置为BarPosition.End。
Tabs({ barPosition: BarPosition.End }) {// TabContent的内容:首页、发现、推荐、我的...
}
顶部导航
Tabs({ barPosition: BarPosition.Start }) {// TabContent的内容:关注、视频、游戏、数码、科技、体育、影视...
}
侧边导航
侧边导航是应用较为少见的一种导航模式,更多适用于横屏界面,用于对应用进行导航操作,由于用户的视觉习惯是从左到右,侧边导航栏默认为左侧侧边栏。
实现侧边导航栏需要将Tabs的vertical属性设置为true,vertical默认值为false,表明内容页和导航栏垂直方向排列。
Tabs({ barPosition: BarPosition.Start }) {// TabContent的内容:首页、发现、推荐、我的...
}
.vertical(true)
.barWidth(100)
.barHeight(200)
限制导航栏的滑动切换
默认情况下,导航栏都支持滑动切换,在一些内容信息量需要进行多级分类的页面
限制底部导航栏滑动
控制滑动切换的属性为scrollable,默认值为true,表示可以滑动,若要限制滑动切换页签则需要设置为false。
Tabs({ barPosition: BarPosition.End }) {TabContent(){Column(){Tabs(){// 顶部导航栏内容...}}.backgroundColor('#ff08a8f1').width('100%')}.tabBar('首页')// 其他TabContent内容:发现、推荐、我的...
}
.scrollable(false)
固定导航栏
当内容分类较为固定且不具有拓展性时,例如底部导航内容分类一般固定,分类数量一般在3-5个,此时使用固定导航栏
Tabs的barMode属性用于控制导航栏是否可以滚动,默认值为BarMode.Fixed。
Tabs({ barPosition: BarPosition.End }) {// TabContent的内容:首页、发现、推荐、我的...
}
.barMode(BarMode.Fixed)
滚动导航栏
滚动导航栏可以用于顶部导航栏或者侧边导航栏的设置,内容分类较多,屏幕宽度无法容纳所有分类页签的情况下,需要使用可滚动的导航栏,支持用户点击和滑动来加载隐藏的页签内容。
滚动导航栏需要设置Tabs组件的barMode属性,默认值为BarMode.Fixed表示为固定导航栏,BarMode.Scrollable表示可滚动导航栏。
Tabs({ barPosition: BarPosition.Start }) {// TabContent的内容:关注、视频、游戏、数码、科技、体育、影视、人文、艺术、自然、军事...
}
.barMode(BarMode.Scrollable)
自定义导航栏
对于底部导航栏,一般作为应用主页面功能区分,为了更好的用户体验,会组合文字以及对应语义图标表示页签内容,这种情况下,需要自定义导航页签的样式。
设置自定义导航栏需要使用tabBar的参数,以其支持的CustomBuilder的方式传入自定义的函数组件样式。
@Builder tabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {Column() {Image(this.currentIndex === targetIndex ? selectedImg : normalImg).size({ width: 25, height: 25 })Text(title).fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B')}.width('100%').height(50).justifyContent(FlexAlign.Center)
}
在TabContent对应tabBar属性中传入自定义函数组件,并传递相应的参数。
TabContent() {Column(){Text('我的内容') }.width('100%').height('100%').backgroundColor('#007DFF')
}
.tabBar(this.tabBuilder('我的', 0, $r('app.media.mine_selected'), $r('app.media.mine_normal')))
切换至指定页签
此时需要使用Tabs提供的onChange事件方法,监听索引index的变化,并将当前活跃的index值传递给currentIndex,实现页签的切换。
@Builder tabBuilder(title: string, targetIndex: number) {Column() {Text(title).fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B')}}
build() {Column() {Tabs({ barPosition: BarPosition.End }) {TabContent() {...}.tabBar(this.tabBuilder('首页', 0))TabContent() {...}.tabBar(this.tabBuilder('发现', 1))TabContent() {...}.tabBar(this.tabBuilder('推荐', 2))TabContent() {...}.tabBar(this.tabBuilder('我的', 3))}.animationDuration(0).backgroundColor('#F1F3F5').onChange((index: number) => {this.currentIndex = index})}.width('100%')}
组成部分
onRequestPopupData
选中字母索引后,请求索引提示弹窗显示内容回调。
class Lxr{tImg:ResourceStrnames:stringconstructor(tImg: ResourceStr, names: string) {this.tImg = tImg;this.names = names;}
}
class Txl{key:stringlxr:Lxr[]constructor(key: string, lxr: Lxr[]) {this.key = key;this.lxr = lxr;}
}@State strs:string[]=['A','B','C']@State txlS:Txl[]=[new Txl('A',[new Lxr($r('app.media.a1'),'张三'),new Lxr($r('app.media.a2'),'阿萨德'),new Lxr($r('app.media.a3'),'阿是'),new Lxr($r('app.media.a4'),'发的'),new Lxr($r('app.media.a5'),'还不如'),new Lxr($r('app.media.a6'),'功能'),]),new Txl('B',[new Lxr($r('app.media.a1'),'各一件'),new Lxr($r('app.media.a2'),'同意'),new Lxr($r('app.media.a3'),'德芙'),new Lxr($r('app.media.a4'),'他已经'),new Lxr($r('app.media.a5'),'个人'),new Lxr($r('app.media.a6'),'得到'),]),new Txl('C',[new Lxr($r('app.media.a1'),'登革热'),new Lxr($r('app.media.a2'),'恩格尔'),new Lxr($r('app.media.a3'),'导入'),new Lxr($r('app.media.a4'),'股份'),new Lxr($r('app.media.a5'),'各位'),new Lxr($r('app.media.a6'),'不是'),new Lxr($r('app.media.a1'),'登革热'),new Lxr($r('app.media.a2'),'恩格尔'),new Lxr($r('app.media.a3'),'导入'),new Lxr($r('app.media.a4'),'股份'),new Lxr($r('app.media.a5'),'各位'),new Lxr($r('app.media.a6'),'不是'),new Lxr($r('app.media.a1'),'登革热'),new Lxr($r('app.media.a2'),'恩格尔'),new Lxr($r('app.media.a3'),'导入'),new Lxr($r('app.media.a4'),'股份'),new Lxr($r('app.media.a5'),'各位'),new Lxr($r('app.media.a6'),'不是'),new Lxr($r('app.media.a1'),'登革热'),new Lxr($r('app.media.a2'),'恩格尔'),new Lxr($r('app.media.a3'),'导入'),new Lxr($r('app.media.a4'),'股份'),new Lxr($r('app.media.a5'),'各位'),new Lxr($r('app.media.a6'),'不是'),]),]@Builder tou(str:string){Text(str).width('100%').backgroundColor('gray')}@State selectIndex:number=0@State strs2:string[]=[]//显示提示框的具体内容@Builder test1(){Stack(){List(){ForEach(this.txlS,(txl:Txl,index)=>{ListItemGroup({header:this.tou(txl.key)}){ForEach(txl.lxr,(lxr:Lxr,i)=>{ListItem(){Row(){Image(lxr.tImg).height(30).width(30).borderRadius(100)Text(lxr.names).fontSize(18)}.width('100%').backgroundColor(i%2==0?'#abc':'white')}})}})}.sticky(StickyStyle.Header).onScrollIndex((first)=>{this.selectIndex=first})AlphabetIndexer({arrayValue:this.strs,selected:0}).font({size:25}).selectedFont({size:30}).itemSize(60).selected(this.selectIndex).usingPopup(true)//提示框.onRequestPopupData((index:number)=>{//选中字母索引后,请求索引提示弹窗显示内容回调。//1.清空数组this.strs2=[]for(let i=0;i<this.txlS[index].lxr.length;i++){//添加数组this.strs2.push(this.txlS[index].lxr[i].names)}return this.strs2})}.height('100%').width('100%')}
Blank
空白填充组件,在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column/Flex时生效。
@Builder test2(){Row(){Text('左边')Blank().color('red')//空白填充组件Text('右边')}.backgroundColor('#abcdef').width('100%')Column(){Text('上边')Blank().color('red')//空白填充组件Text('下边')}.height(100).width('100%').backgroundColor('#abc')}
CalendarPicker
日历选择器组件,提供下拉日历弹窗,可以让用户选择日期。
now:Date=new Date('2023-08-09')@State selectDate:Date=new Date('2023-08-09')@Builder CalendarTest(){Text('日期文本')CalendarPicker({hintRadius:10,//底板的圆角0~16selected:this.now,//默认选中的日期})// .edgeAlign(CalendarAlign.START,{dx:100,dy:200}) //设置选择器与入口组件的对齐方式 dx:100,dy:200偏移量.textStyle({//入口区的文本颜色、字号、字体粗细。color:'red',font:{size:30,weight:700}}).onChange((val)=>{this.selectDate=val})Text('选中的日期:'+this.selectDate)}
Checkbox
提供多选框组件,通常用于某选项的打开或关闭。
@Builder conStyle(){SymbolGlyph($r('sys.symbol.star_fill')).fontColor(['red'])}@Builder conStyle1(num:number){Text(num<=99?num.toString():'99+').fontSize(num<=99?16:10)}@Builder checkBoxTest(){Row(){Text('爱好:')Checkbox({name:'ah',group:'hobby'})//提供多选框组件,通常用于某选项的打开或关闭。.select(true)//默认选中.selectedColor('red')//选中框的颜色.unselectedColor('blue')//未选中的颜色.mark({strokeColor:'#eee',size:20,strokeWidth:10})//设置多选框内部图标样式。对号样式.shape(CheckBoxShape.ROUNDED_SQUARE)//设置CheckBox组件形状, 包括圆形和圆角方形。Checkbox({name:'ah',group:'hobby',indicatorBuilder:()=>{this.conStyle()}})Checkbox({name:'ah',group:'hobby',indicatorBuilder:()=>{this.conStyle1(100)}})}Column(){Row(){Text('全选')CheckboxGroup({group:'ah'})}Row(){Checkbox({group:'ah',name:'c'})Text('唱')Checkbox({group:'ah',name:'c'})Text('跳')Checkbox({group:'ah',name:'c'})Text('rap')}}}
相关文章:

布局、组成部分
布局 线性布局 (Row/Column) 线性容器Row和Column构建,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。 在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效…...

Go, Jocko, Kafka
本篇内容是根据2016年8月份# 31. Go, Jocko, Kafka 音频录制内容的整理与翻译 Travis Jeffery 参加了节目,谈论 Go、Jocko、Kafka、Kafka 的存储内部结构如何工作,以及有趣的 Go 项目和新闻。 Erik St. Martin: 大家好,欢迎回到《GoTime》的另…...

CANoe 报文仿真
文章目录 一、单个/少数报文仿真1、Canoe 发送报文2、可以自定义该报文发送节点3、添加报文4、触发方式 二、ECU节点仿真1、导入DBC,添加节点2. 选择节点中的哪些报文可以发送3. 更新ECU 节点发送的报文数据 三、开始仿真激活/失效该 ECU节点 一、单个/少数报文仿真…...

升级thinkphp8最新版本,升级后发现版本不变
升级thinkphp8.0.3最新版本8.1.1,升级后发现版本不变, 更新TP有两个方法 1 全部更新(所有插件都一起更新) composer update 2 只更新TP框架核心 composer update topthink/framework 造成可能有两个原因,一是缓存问题,二是更新…...

工业大数据分析算法实战-day07
文章目录 day07概率图模型朴素贝叶斯(Naive Bayes)贝叶斯网络(Bayesian Network)一般图模型生成式和判别式模型图模型结构与模型推理 集成学习Boosting算法Stacking算法 day07 今天是第七天,昨日主要针对是第三章节中…...

六、nginx负载均衡
负载均衡:将四层或者七层的请求分配到多台后端的服务器上。 从而分担整个业务的负载。提高系统的稳定性,也可以提高高可用(备灾,其中一台后端服务器如果发生故障不影响整体业务). 负载均衡的算法 round robin 轮询 r…...

鸿蒙项目云捐助第十一讲鸿蒙App应用的捐助成功自定义对话框组件实现
在生活中,用户做了一个好事后,很多场合都会收到一份感谢。在捐助的行业也是一样的,用户捐出了一片爱心,就会收获一份温情。这里的温情是通过自定义对话框实现的。 一、通过自定义对话框组件实现捐款成功的信息页 这里用户捐款成…...

华为云联合中国信通院发布首个云计算智能化可观测性能力成熟度模型标准
2024年12月3日,由全球数字经济大会组委会主办,中国信息通信研究院(以下简称“中国信通院”)、中国通信企业协会承办的2024全球数字经济大会云AI计算国际合作论坛在北京成功召开。本次会议中,华为云联合中国信通院等单位…...

如何评估呼叫中心大模型呼出机器人的使用效果?
如何评估呼叫中心大模型呼出机器人的使用效果? 原作者:开源呼叫中心FreeIPCC,其Github:https://github.com/lihaiya/freeipcc 评估呼叫中心大模型呼出机器人的使用效果是一个复杂而多维的过程,需要综合考虑多个方面&…...

ARM/Linux嵌入式面经(六一):联合汽车电子
1、自我介绍 2、介绍一下 ARM与RISCV的差异 在嵌入式系统领域,ARM与RISC-V是两种重要的指令集架构(ISA),它们各自具有独特的特点和优势。以下是对两者差异的详细介绍: ARM与RISC-V的差异 开源性与专有性: ARM:ARM架构是商业化的,任何想要使用ARM指令集或相关技术的设…...

unity 雷达
unity 雷达 首先去商店下载TouchScript插件 导入的时候勾选Enable TUIO 然后把预制体Cursors和TouchManager拖上 最后把TuioInput这个脚本挂上 脚本上的端口号尽量不改...

单元测试知识总结
我们希望每段代码都是自测试的,每次改动之后,都能自动发现对现有功能的影响。 1 测试要求 在对软件单元进行动态测试之前,应对软件单元的源代码进行静态测试; 应建立测试软件单元的环境,如数据准备、桩模块、模拟器…...

Android:使用Service处理息屏后的WebSocket的服务端推送消息并传递给前端
前言 之前我们在使 RESTful 访问服务端时,一般都是客户端请求服务端应答的方式,这种通讯方式,对于需要持续获取数据的情形都是采用轮询的方式,但是这种方式对两边的性能消耗很大,特别是服务端的压力很大。现在当我们使…...

Git Bash Here 中文显示乱码的处理方法
在使用"open Git Bash Here"时,遇到中文显示乱码问题。 原因:通常是由于编码设置不正确导致的。 open Git Bash Here —>鼠标右击空白处,点击「选项」|或「Options」 在「文本」或 「Text」选项卡中,找到"local…...

FreeBSD安装教程
FreeBSD 是一个功能强大且可靠的开源 UNIX 操作系统,适合服务器和桌面环境。本文将介绍如何安装 FreeBSD,从系统准备到基础设置,为你快速上手提供帮助。 一、准备工作 1. 硬件要求 CPU:支持 x86 或 AMD64 架构的处理器。 内存&a…...

Loki 各模式简介
目录 Loki 部署模式 单片模式 简单可扩展 微服务模式 Loki 部署模式 Loki 是一个由许多微服务组成的分布式系统。它还具有独特的构建模型,其中所有这些微服务都存在于同一个二进制文件中。 您可以使用命令行标志配置单个二进制文件的行为-target,以指…...

MySQL八股-全局锁,表级锁,表锁,元数据锁,意向锁,行级锁,行锁,间隙锁,临键
文章目录 全局锁表级锁表锁(表级锁)元数据锁(MDL,Meta Data Lock,表级锁)元数据锁演示元数据锁兼容的情况元数据锁互相阻塞的情况 意向锁(Intention lock,表级锁)意向锁分类意向锁演示:意向共享锁(**IS**)与…...

(四)Spring Cloud Alibaba 2023.x:高效构建 Gateway 网关服务
目录 前言 准备 项目集成 pom.xml引入依赖 启动类 yml文件添加网关配置 修改消费者FeignService类 结果验证 前言 Spring cloud alibaba 体系中构建微服务,我们使用Spring Cloud Gateway 作为服务网关, Gateway是Spring 官方推出的一款基于 Web…...

Android XR 是什么?解释它的功能、设备、开发工具等
什么是“Android XR”? Android XR是最新配备AI的OS(操作系统),兼容耳机和眼镜(AR眼镜)。 沉浸式剧场 从视频列表中选择... 您可以体验完全身临其境的视频观看体验。 无限工作空间 您的现实世界将成为您…...

【算法】实体关系抽取
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...

Codeforces Round 993 (Div. 4)题解
A. Easy Problem 思路:经过看了一眼,我们发现,ab的和一定是n,且两个都是正整数, 所以a的范围就是从1~n-1 所以输出n-1即可 #include<bits/stdc.h> using namespace std; #define int long long int t; int n…...

【计算机网络】期末考试预习复习|中
作业讲解 转发器、网桥、路由器和网关(4-6) 作为中间设备,转发器、网桥、路由器和网关有何区别? (1) 物理层使用的中间设备叫做转发器(repeater)。 (2) 数据链路层使用的中间设备叫做网桥或桥接器(bridge)。 (3) 网络层使用的中间设备叫做路…...

从零用java实现 小红书 springboot vue uniapp (4)个人主页优化
前言 移动端演示 http://8.146.211.120:8081/#/ 前面的文章我们基本完成了详情页开发 今天我们具体的去进行实现个人中心 并且分享我开发时遇到的问题 首先先看效果 我们对布局整体规划一下 个人名片 半透明背景 刚开始我用的是 <view style"background-image: ur…...

为“行车大脑”降温:Simdroid-EC助力汽车ECU设计研发
ECU(Electronic Control Unit,电子控制单元)被誉为汽车的行车大脑,在工作时会产生大量的热量,而其散热存在以下难题:一是工作环境恶劣,ECU常处于高温环境中;二是ECU所处的空间较为狭…...

视频汇聚平台:Liveweb视频流媒体平台视频监控系统解决方案
数字化技术在安防领域的广泛应用已经成为公安等重要执法部门的重要趋势,主要得益于无线网络通信技术和计算机技术的快速进步。传统的视频监控系统存在诸多局限,例如只能进行现场监视,报警信息传输简单,无法远距离传输视频信号&…...

通过解调使用正则化相位跟踪技术进行相位解包裹
1. 绪论 光学计量学通常使用光学干涉仪来测量各种物理量。1,2 根据应用的不同,可以使用多种类型的干涉仪,但它们的共同目标是产生一个由被测物理量调制的条纹图案。使用这种光束编码程序可以检测到的物理量范围非常广:深度测量、应变分析、温…...

VMware替代 | 双一流大学采用ZStack ZSphere虚拟化平台加速医学应用算法分析
某双一流大学医学部在面对日益增长的医学应用算法分析需求时,选择采用ZStack ZSphere虚拟化平台,以满足其高性能计算和GPU业务应用的迫切需求。该平台凭借其轻量化、卓越性能及易用性,成功解决了医学部在虚拟化及GPU应用场景中的挑战。随着平…...

UNIAPP框架uView初步集成与开发设计
uView UI,是uni-app生态最优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。本文章分享UNIAPP集成使用uView页面动态开发设计。 一、使用HBuilder X 直接导入插件,下载后重启 uView - DCloud 插件市场 二、配置样…...

C05S08-LVS负载均衡
一、LVS 1. LVS概述 LVS(Linux Virtual Server、Linux虚拟服务)是一种基于Linux系统集群的负载均衡方案,属于四层的负载均衡。 集群:将相同组件部署在不同的服务器上,提供统一的服务,以及同样的功能&…...

C 语言代码诗韵:数字功能的雅集华章
函数基本操作练习 主要内容: 本任务主要练习函数的申请、定义、调用等,主要包含以下功能: 1)编写函数,输入一个整数,求各个数字之和; 2)编写函数,计算1!2&…...