鸿蒙PC开发——自适应布局

鸿蒙PC开发——自适应布局

【高心星出品】

文章目录

自适应布局

针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。

自适应布局类别自适应布局能力使用场景实现方式
自适应拉伸拉伸能力容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。Flex布局的flexGrow和flexShrink属性
均分能力容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly
自适应缩放占比能力子组件的宽或高按照预设的比例,随容器组件发生变化。基于通用属性的两种实现方式:- 将子组件的宽高设置为父组件宽高的百分比- layoutWeight属性
缩放能力子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。布局约束的aspectRatio属性
自适应延伸延伸能力容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。基于容器组件的两种实现方式:- 通过List组件实现- 通过Scroll组件配合Row组件或Column组件实现
隐藏能力容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏。相同显示优先级的子组件同时显示或隐藏。布局约束的displayPriority属性
自适应折行折行能力容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,自动换行。Flex组件的wrap属性设置为FlexWrap.Wrap

下面我们依次介绍这几种自适应布局能力。

拉伸能力

拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。

拉伸能力通常通过Flex布局中的flexGrow和flexShrink属性实现,flexGrow和flexShrink属性常与flexBasis属性搭配使用,故将这三个属性放在一起介绍。

属性类型默认值描述
flexGrownumber0仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。
flexShrinknumber1仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。
flexBasis‘auto’ | Length‘auto’设置组件在Flex容器中主轴方向上基准尺寸。'auto’意味着使用组件原始的尺寸,不做修改。flexBasis属性不是必须的,通过width或height也可以达到同样的效果。当flexBasis属性与width或height发生冲突时,以flexBasis属性为准。

示例1

本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成,各区域的属性配置如下。

  • 中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。
  • 两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。

由上可知,父容器的基准尺寸是700vp(150vp+400vp+150vp)。

可以通过拖动底部的滑动条改变父容器的尺寸,查看布局变化。

  • 当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。
  • 当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。
在这里插入图片描述
@Entry@Component struct FlexibleCapability1 {@State sliderWidth:number=1000;// Bottom slider - adjust container size by dragging the slider.@Builderslider(){Slider({ value:this.sliderWidth, min:300, max:1000}).blockColor(Color.White).width('60%').onChange((value:number)=>{this.sliderWidth = value;}).position({ x:'20%', y:'80%'})}build(){Column(){Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }){// Distribute all extra space to the image using flexGrow and allocate all insufficient space to the side margins using flexShrink.Row().width(150).height(400).backgroundColor('#FFFFFF').flexGrow(0).flexShrink(1)Image($r('app.media.illustrator')).width(300).height(400).objectFit(ImageFit.Contain).backgroundColor('#66F1CCB8').flexGrow(1).flexShrink(0)Row().width(150).height(400).backgroundColor('#FFFFFF').flexGrow(0).flexShrink(1)}.width(this.sliderWidth)this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为FlexibleCapability1的组件。
    • 初始化了一个状态变量sliderWidth,用于存储滑块的当前值,默认值为1000。
  2. 滑块构建
    • 使用@Builder装饰器定义了一个名为slider的方法,该方法构建了一个滑块。
    • 滑块的初始值为sliderWidth,范围在300到1000之间,颜色为白色,宽度为60%,位置为窗口的20%宽度和80%高度。
    • 滑块的值变化时,会更新sliderWidth的值。
  3. 主界面构建
    • build方法中,使用Column组件构建了一个垂直布局。
    • Column中,使用Flex组件创建了一个水平布局,用于放置图像和空白区域。
    • 第一个Row组件用于创建一个固定宽度的空白区域,宽度为150,高度为400,背景颜色为白色,不允许扩展也不允许收缩。
    • Image组件用于显示图像,宽度为300,高度为400,图像适应方式为Contain,背景颜色为#66F1CCB8,允许扩展但不允许收缩。
    • 第二个Row组件同样用于创建一个固定宽度的空白区域,宽度为150,高度为400,背景颜色为白色,不允许扩展也不允许收缩。
    • Flex组件的宽度设置为sliderWidth,即滑块的值,允许根据需要扩展或收缩。
  4. 容器布局设置
    • Column组件的宽度为100%,高度为100%,背景颜色为#F1F3F5,内容水平和垂直居中。
    • Column中,调用了slider方法,插入了一个滑块。

示例2

文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。

在这里插入图片描述
@Entry@Component struct FlexibleCapability2 {@State rate:number=0.8;// Bottom slider - resize container by dragging the slider control.@Builderslider(){Slider({ value:this.rate *100, min:55, max:80}).blockColor(Color.White).width('60%').onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}build(){Row(){Row(){Text($r('app.string.healthy_use_phone')).fontSize(16).width(135).height(22).fontWeight(FontWeight.Medium).lineHeight(22)// Implement stretch capability using the Blank component.Blank()Toggle({ type: ToggleType.Switch }).width(36).height(20)}.height(55).borderRadius(12).padding({ left:13, right:13}).backgroundColor('#FFFFFF').width(this.rate *100+'%')this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为FlexibleCapability2的组件。
    • 初始化了一个状态变量rate,其初始值为0.8,用于控制容器的宽度百分比。
  2. 滑块构建
    • 定义了一个名为slider的方法,用于构建一个滑块组件。
    • 滑块的初始值为rate乘以100,最小值为55,最大值为80。
    • 滑块的值变化时,会更新rate的值,并通过onChange回调函数实现。
    • 滑块的位置被设置为相对于父组件的20%水平和80%垂直位置。
  3. UI构建
    • build方法中,构建了一个Row组件,包含两个子Row组件和一个Slider组件。
    • 左侧的Row组件包含一个文本和一个空白组件(Blank),用于实现弹性能力。
    • 右侧的Row组件包含一个开关按钮(Toggle),但功能实现代码并未提供。
    • 整个Row组件的宽度设置为100%,高度设置为100%,背景颜色为#F1F3F5,并居中对齐。
  4. 样式与布局
    • 使用borderRadiuspaddingbackgroundColor等属性设置组件的样式和布局。
    • 容器的宽度通过this.rate * 100 + '%'动态计算,实现弹性调整。

均分能力

均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。

均分能力可以通过将Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly实现,即子元素在父容器主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。

说明

  • 均分能力还可以通过其它方式实现,如使用Grid组件或在每个组件间添加Blank组件等。
  • 类Web开发范式中,通过将div组件的justify-content属性设置为space-evenly来实现均分布局。

示例:

父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。

在这里插入图片描述
@Entry@Component struct EquipartitionCapability {@State rate:number=0.6;private list:number[]=[0,1,2,3];// Bottom slider - adjust container dimensions via slider drag interaction.@Builderslider(){Slider({ value:this.rate *100, min:30, max:60}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}@BuilderItem(){Column(){Image($r('app.media.icon')).width(48).height(48).margin(({ top:8}))Text($r('app.string.show_app_name')).width(64).height(30).lineHeight(15).fontSize(12).textAlign(TextAlign.Center).margin({ top:8}).padding({ bottom:15})}.width(80).height(102)}build(){Row(){Column(){// Distribute remaining space evenly along the main axis of the parent container.Flex({ justifyContent: FlexAlign.SpaceEvenly }){ForEach(this.list,(item:number)=>{this.Item();},(item:number, index:number)=>JSON.stringify(item)+ index)}// Distribute remaining space evenly along the main axis of the parent container.Flex({ justifyContent: FlexAlign.SpaceEvenly }){ForEach(this.list,(item:number)=>{this.Item();},(item:number, index:number)=>JSON.stringify(item)+ index)}}.width(this.rate *100+'%').height(222).padding({ top:16}).backgroundColor('#FFFFFF').borderRadius(16)this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为EquipartitionCapability的组件。
    • 初始化了一个状态变量rate,用于存储滑动条的当前值,默认值为0.6。
    • 定义了一个数组list,用于存储要显示的项目数。
  2. 滑动条定义
    • 使用@Builder装饰器定义了一个名为slider的方法,该方法构建了一个滑动条。
    • 滑动条的值绑定到rate状态变量,最小值为30,最大值为60。
    • 滑动条的值改变时,会更新rate的值。
  3. 项目定义
    • 使用@Builder装饰器定义了一个名为Item的方法,该方法构建了一个项目。
    • 项目包含一个图片和一个文本,样式和布局进行了定义。
  4. 构建方法
    • build方法中,构建了整个组件的布局。
    • 使用Row组件创建一个水平布局,包含两个Column组件。
    • 第一个Column组件用于显示项目,使用ForEach循环渲染list中的每个项目。
    • 第二个Column组件用于显示滑动条。
    • 整个组件的宽度和高度设置为100%,背景颜色为浅灰色,并居中显示。
  5. 布局与样式
    • 使用Flex布局,使得项目在容器中均匀分布。
    • 容器的宽度根据rate的值动态调整。
    • 组件的背景颜色为浅灰色,容器和滑动条的样式进行了定义。

占比能力

占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。

占比能力通常有两种实现方式:

  • 将子组件的宽高设置为父组件宽高的百分比,详见尺寸设置及长度类型。
  • 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重,详见尺寸设置。
    • 当父容器尺寸确定时,其子组件按照开发者配置的权重比例分配父容器中主轴方向的空间。
    • 仅当父容器是Row、Column或者Flex时,layoutWeight属性才会生效。
    • 设置layoutWeight属性后,组件本身的尺寸会失效。比如同时设置了.width(‘40%’)和.layoutWeight(1),那么只有.layoutWeight(1)会生效。

layoutWeight存在使用限制,所以实际使用过程中大多通过将子组件宽高设置为父组件的百分比来实现占比能力。

说明

  • 占比能力在实际开发中使用的非常广泛,可以通过很多不同的方式实现占比能力,如还可以通过Grid组件的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格中占据不同的列数来实现占比能力。
  • 类Web开发范式同样支持以百分比的形式设置组件的宽高,详见通用样式中关于width和height的介绍以及长度类型。
  • 与声明式开发范式中的layoutWeight属性类似,类Web开发范式提供了flex-weight样式用于配置互为兄弟关系的组件在父容器主轴方向的布局权重。

示例:

简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。

将三个按钮的.layoutWeight(1)分别替换为.width(‘33%’)、.width(‘34%’)、.width(‘33%’),也可以实现与当前同样的显示效果。

在这里插入图片描述
@Entry@Component struct ProportionCapability {@State rate:number=0.5;// Bottom slider - adjust container size through slider drag interaction.@Builderslider(){Slider({ value:100, min:25, max:50}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}build(){Row(){Row(){Column(){Image($r('app.media.down')).width(48).height(48)}.height(96)// Set the layout weight of child components along the main axis of the parent container..layoutWeight(1).justifyContent(FlexAlign.Center)Column(){Image($r("app.media.pause")).width(48).height(48)}.height(96).layoutWeight(1).backgroundColor('#66F1CCB8').justifyContent(FlexAlign.Center)Column(){Image($r("app.media.next")).width(48).height(48)}.height(96).layoutWeight(1).justifyContent(FlexAlign.Center)}.width(this.rate *100+'%').height(96).borderRadius(16).backgroundColor('#FFFFFF')this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)}}

代码核心功能: 该代码定义了一个名为ProportionCapability的组件,主要功能是通过滑块(Slider)来调整容器的大小。用户可以通过拖动滑块来改变rate的值,然后这个值会被用来动态调整容器的宽度。容器内部包含了三个垂直排列的图标(下箭头、暂停按钮、下箭头),它们的布局权重被设置为1,因此容器宽度变化时,这些图标会随着容器宽度变化而移动。

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为ProportionCapability的组件。
    • 在组件内部定义了一个状态变量rate,初始值为0.5。
  2. 滑块构建
    • 使用@Builder装饰器定义了一个名为slider的方法,用于构建滑块。
    • 滑块的初始值设为100,最小值为25,最大值为50。
    • 滑块的值变化时,会通过onChange事件更新rate的值,将其转换为百分比形式。
  3. 主构建逻辑
    • build方法中,创建了一个水平排列的Row容器。
    • 在这个Row容器内部,创建了三个垂直排列的Column容器,每个容器内放置一个图标(下箭头、暂停按钮、下箭头)。
    • 这三个Column容器的布局权重均为1,因此容器宽度变化时,它们的宽度会相应变化。
    • 最外层的Row容器包含了滑块,并且其宽度会根据rate的值动态调整。
    • 整个组件的布局会根据rate的值变化,使得容器和图标的宽度随之调整。
  4. 样式与布局
    • 使用layoutWeight属性设置子组件在父容器中的布局权重。
    • 使用justifyContent属性设置子组件在主轴上的对齐方式。
    • 使用backgroundColorborderRadius等属性设置容器的背景色和圆角。
    • 使用alignItemsjustifyContent属性设置容器在交叉轴上的对齐方式。

缩放能力

缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。

缩放能力通过使用百分比布局配合固定宽高比(aspectRatio属性)实现当容器尺寸发生变化时,内容自适应调整。

可以访问布局约束,了解aspectRatio属性的详细信息。

示例:

为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。

在这里插入图片描述
@Entry@Component struct ScaleCapability {@State sliderWidth:number=400;@State sliderHeight:number=400;// Bottom slider - adjust container size through slider drag interaction.@Builderslider(){Slider({ value:this.sliderWidth, min:100, max:400, style: SliderStyle.OutSet }).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.sliderWidth = value;}).position({ x:'20%', y:'80%'})Slider({ value:this.sliderHeight, min:100, max:400, style: SliderStyle.OutSet }).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.sliderHeight = value;}).position({ x:'20%', y:'87%'})}build(){Column(){Column(){Column(){Image($r('app.media.illustrator')).width('100%').height('100%')}// Maintain fixed aspect ratio..aspectRatio(1)// Decorative border (purely for visual demonstration purposes)..border({ width:2, color:'#66F1CCB8'})}.backgroundColor('#FFFFFF').height(this.sliderHeight).width(this.sliderWidth).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)this.slider()}.height('100%').width('100%').backgroundColor('#F1F3F5').alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为ScaleCapability的组件。
    • 初始化两个状态变量sliderWidthsliderHeight,用于存储容器宽度和高度的值,默认值为400。
  2. 滑块组件构建
    • 定义了一个名为slider的构建器方法,用于创建两个滑块。
    • 每个滑块分别控制宽度和高度的调整,滑块的范围在100到400之间。
    • 滑块的值变化时,会更新对应的sliderWidthsliderHeight状态。
  3. 主构建逻辑
    • build方法中,创建一个Column布局,包含一个嵌套的Column布局,用于显示图像。
    • 图像的宽度和高度被设置为容器的宽度和高度,保持固定的宽高比。
    • 容器的宽度和高度由sliderWidthsliderHeight状态决定,因此用户可以通过滑块动态调整容器大小。
    • 最后,调用slider方法,将滑块组件添加到布局中。
  4. 布局样式设置
    • 所有布局的背景颜色、对齐方式和边距都被设置,确保组件在界面上居中显示,并且滑块位于可视区域的特定位置。

延伸能力

延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。

延伸能力通常有两种实现方式:

  • 通过List组件实现。
  • 通过Scroll组件配合Row组件或Column组件实现。

示例:

当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。

分别通过List组件实现及通过Scroll组件配合Row组件实现。

在这里插入图片描述

(1)通过List组件实现。

@Entry@Component struct ExtensionCapability2 {@State rate:number=0.60;private appList:number[]=[0,1,2,3,4,5,6,7];@Builderslider(){Slider({ value:this.rate *100, min:8, max:60}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}build(){Row(){Row({ space:10}){// Implement extension capability through List component.List({ space:10}){ForEach(this.appList,(item:number, index:number)=>{ListItem(){Column(){Image($r('app.media.icon')).width(48).height(48).margin({ top:8})Text($r('app.string.show_app_name')).width(64).height(30).lineHeight(15).fontSize(12).textAlign(TextAlign.Center).margin({ top:8}).padding({ bottom:15})}.width(80).height(102)}.width(80).height(102)},(item:number, index:number)=>JSON.stringify(item)+ index)}.padding({ top:16, left:10}).listDirection(Axis.Horizontal).width('100%').height(118).borderRadius(16).backgroundColor(Color.White)}.width(this.rate *100+'%')this.slider()}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Center)}}
  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为ExtensionCapability2的组件。
    • 初始化了一个状态变量rate,其初始值为0.60,用于控制列表的宽度。
    • 初始化了一个数组appList,包含8个数字,用于生成列表项。
  2. 滑动条构建
    • 使用@Builder装饰器定义了一个名为slider的方法,用于构建一个滑动条。
    • 滑动条的值与rate的百分比值绑定,最小值为8,最大值为60。
    • 滑动条的改变会更新rate的值。
  3. 组件构建
    • build方法中,使用Row组件创建一个水平布局。
    • 在水平布局中,使用Row组件创建另一个水平布局,用于放置列表和滑动条。
    • 使用List组件和ForEach循环生成列表项,每个列表项包含一个图标和文本。
    • 列表的宽度与rate的百分比值绑定,实现宽度调整功能。
    • 在列表和滑动条之间放置一个Row组件,用于布局滑动条。
  4. 布局与样式
    • 使用FlexAlignVerticalAlign调整布局,使组件在屏幕中央显示。
    • 设置组件的宽度和高度为100%,确保组件充满屏幕。
    • 设置列表的背景颜色为白色,并添加圆角边框。

(2)通过Scroll组件配合Row组件实现。

@Entry@Component struct ExtensionCapability1 {@State rate:number=0.60;private appList:number[]=[0,1,2,3,4,5,6,7];@Builderslider(){Slider({ value:this.rate *100, min:8, max:60}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}build(){Row(){// Implement extension capability through Scroll and Row(or Column) components.Scroll(){Row({ space:10}){ForEach(this.appList,(item:number, index:number)=>{Column(){Image($r('app.media.icon')).width(48).height(48).margin({ top:8})Text($r('app.string.show_app_name')).width(64).height(30).lineHeight(15).fontSize(12).textAlign(TextAlign.Center).margin({ top:8}).padding({ bottom:15})}.width(80).height(102)},(item:number, index:number)=>JSON.stringify(item)+ index)}.padding({ top:16, left:10}).height(118).borderRadius(16).backgroundColor(Color.White)}.scrollable(ScrollDirection.Horizontal).width(this.rate *100+'%')this.slider()}.width('100%').height('100%').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为ExtensionCapability1的组件。
    • 初始化了一个状态变量rate,其值为0.60,用于控制滑块的默认位置。
    • 定义了一个私有数组appList,用于存储应用的索引值,以便在列表中展示。
  2. 滑块构建
    • 使用@Builder装饰器定义了一个名为slider的方法,用于构建滑块组件。
    • 滑块的初始值设置为rate乘以100,最小值为8,最大值为60。
    • 滑块的样式设置为白色背景,宽60%,高50px。
    • 滑块的值变化时,会更新rate的值,使其与滑块的当前位置同步。
    • 滑块定位在界面上的(20%, 80%)位置。
  3. 组件构建
    • build方法中,使用Row组件创建一个水平布局。
    • Row组件内部,使用Scroll组件实现水平滚动。
    • Scroll组件内部,使用ForEach循环遍历appList数组,为每个应用创建一个Column组件,包含应用图标和名称。
    • Scroll组件的宽度绑定到rate乘以100,实现根据滑块位置调整列表可见宽度的功能。
    • Row组件的右上角添加了之前定义的slider方法,用于用户调整列表可见宽度。
  4. 布局与样式
    • 整个Row组件的宽度和高度都设置为100%,以确保组件在屏幕上居中显示。
    • 使用alignItemsjustifyContent属性确保内容在垂直和水平方向上居中对齐。

隐藏能力

隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。

隐藏能力通过设置布局优先级(displayPriority属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。

可以访问布局约束,了解displayPriority属性的详细信息。

示例:

父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。

在这里插入图片描述
@Entry@Component struct HiddenCapability {@State rate:number=0.8;@Builderslider(){Slider({ value:this.rate *100, min:10, max:80}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'80%'})}build(){Column(){Row(){Row(){Image($r('app.media.favorite')).width(48).height(48).objectFit(ImageFit.Contain)}// Layout priority..displayPriority(1).padding({ left:12, right:12})Row(){Image($r('app.media.down')).width(48).height(48).objectFit(ImageFit.Contain)}// Layout priority..displayPriority(2).padding({ left:12, right:12})Row(){Image($r('app.media.pause')).width(48).height(48).objectFit(ImageFit.Contain)}// Layout priority..displayPriority(3).padding({ left:12, right:12})Row(){Image($r('app.media.next')).width(48).height(48).objectFit(ImageFit.Contain)}// Layout priority..displayPriority(2).padding({ left:12, right:12})Row(){Image($r('app.media.list')).width(48).height(48).objectFit(ImageFit.Contain)}// Layout priority..displayPriority(1).padding({ left:12, right:12})}.width(this.rate *100+'%').height(96).borderRadius(16).backgroundColor('#FFFFFF').justifyContent(FlexAlign.Center)this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为HiddenCapability的组件。
    • 初始化了一个状态变量rate,其初始值为0.8,用于控制界面宽度。
  2. 滑块构建器
    • 定义了一个名为slider的构建器方法,用于创建一个滑块组件。
    • 滑块的初始值设置为this.rate * 100,最小值为10,最大值为80。
    • 滑块的值变化时,会通过onChange事件更新rate状态。
  3. 主界面构建
    • build方法中,使用Column布局组件来组织界面。
    • 内部嵌套了多个Row组件,每个Row中包含一个Image组件,用于显示图标。
    • 每个Row的布局优先级和填充间距通过displayPrioritypadding属性设置。
    • 主界面的宽度和高度设置为100%,背景颜色为#F1F3F5,内容居中对齐。
  4. 界面布局调整
    • 主界面的宽度通过this.rate * 100 + '%'动态调整,受rate状态影响。
    • 内部的Row组件布局优先级和填充间距也根据需要设置。
  5. 滑块组件集成
    • 在主界面中调用this.slider()方法,将滑块组件嵌入到界面中。

折行能力

折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。

折行能力通过使用 Flex折行布局 (将wrap属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。

可以访问Flex组件,了解Flex组件的详细用法。

示例:

父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。

在这里插入图片描述
@Entry@Component struct WrapCapabilitySample {@State rate:number=0.7; imageList: Resource []=[$r('app.media.flexWrap1'),$r('app.media.flexWrap2'),$r('app.media.flexWrap3'),$r('app.media.flexWrap4'),$r('app.media.flexWrap5'),$r('app.media.flexWrap6')];@Builderslider(){Slider({ value:this.rate *100, min:50, max:70}).blockColor(Color.White).width('60%').height(50).onChange((value:number)=>{this.rate = value /100;}).position({ x:'20%', y:'87%'})}build(){Column(){Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, wrap: FlexWrap.Wrap }){ForEach(this.imageList,(item: Resource, index:number)=>{Image(item).width(192).height(138).padding(10)},(item: Resource, index:number)=>JSON.stringify(item)+ index)}.backgroundColor('#FFFFFF').padding(20).width(this.rate *100+'%').borderRadius(16)this.slider()}.width('100%').height('100%').backgroundColor('#F1F3F5').alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为WrapCapabilitySample的组件。
    • 初始化了一个状态变量rate,用于控制图片容器的宽度,默认值为0.7。
    • 定义了一个图片资源列表imageList,包含6个图片资源。
  2. 滑块控件定义
    • 使用@Builder装饰器定义了一个名为slider的方法,用于创建一个滑块控件。
    • 滑块控件Slider的值绑定到rate,范围从50到70,宽度为60%,高度为50。
    • 滑块的值改变时,会更新rate的值,即调整图片容器的宽度。
    • 滑块控件的位置设置为x: '20%', y: '87%'
  3. 组件构建
    • build方法中,使用Column布局组件来组织内容。
    • Column中嵌套一个Flex布局组件,用于排列图片。
    • Flex布局组件设置为支持图片的自动换行排列,即wrap: FlexWrap.Wrap
    • 使用ForEach循环遍历imageList,为每个图片创建一个Image组件,并设置图片的宽度、高度和内边距。
    • Flex布局组件的背景颜色为白色,内边距为20,宽度为rate * 100 + '%',圆角为16。
    • Flex布局组件中调用this.slider()方法,插入滑块控件。

Read more

【拥抱AI】openclaw的安装使用和部分建议

【拥抱AI】openclaw的安装使用和部分建议

一、环境准备与安全考虑 OpenClaw 具备系统级权限(Agent Mode),意味着它可以执行 Shell 命令、访问文件系统等。因此,强烈建议在以下环境中运行: * 推荐:Linux 服务器(如 Ubuntu 22.04)或 macOS。 * Windows 用户:强烈建议使用 WSL2(Linux 子系统),不要直接在原生 Windows 环境中运行(除非你非常了解风险),因为 Windows 的文件系统权限模型较为脆弱,可能导致误删系统文件。 最低硬件要求: * 内存:8GB(建议 16GB,尤其是使用本地模型时)。 * 磁盘:至少 20GB 可用空间(插件和模型缓存可能占用较多磁盘)。 * CPU:64位处理器,若运行大型语言模型(LLM)

By Ne0inhk
【AI开发】—— OpenCode双插件协同开发指南

【AI开发】—— OpenCode双插件协同开发指南

OpenCode双插件协同开发指南|Oh My OpenCode+Superpowers 兼顾效率与规范 很多同学在OpenCode中装完Superpowers后,都会有一个疑问:已经有了做代码规范的Superpowers,还有必要用Oh My OpenCode(OMOC)吗? 甚至装了两个插件后,不知道如何配合使用,导致要么只用到了其中一个的功能,要么让两者互相“冲突”,浪费了插件的核心价值。 其实答案很明确:两者是互补而非替代的关系,组合使用才是OpenCode的最优解。OMOC是「项目开发总指挥」,负责拆解任务、并行调度、自动化工具调用,主打一个提效率;Superpowers是「代码工程质检员」,负责约束AI遵循TDD、代码审查、重构等最佳实践,主打一个保规范。 这篇文章就把两者的核心区别讲透,再通过实操性拉满的协同开发教程,教你用OMOC+Superpowers开发项目,既让AI写代码又快又好,还能彻底摆脱“手动拆任务、反复改代码”的痛点,全程贴合开发实际,新手也能直接跟着做。 一、先搞懂:OMOC与Superpowers 核心区别(

By Ne0inhk
AI 时代,为什么 “人人都是产品经理” 的时代才真正到来?

AI 时代,为什么 “人人都是产品经理” 的时代才真正到来?

从“口号”到“现实”:AI 如何重构产品经理的能力边界 传统“人人都是产品经理”的矛盾 “人人都是产品经理”的提法由来已久,但在传统产品开发模式中,这更像是一种理念倡导,而非可落地的实践,核心矛盾集中在三个维度: * 能力门槛高:产品经理需要同时掌握用户调研、需求分析、原型设计、跨部门协调等多维度技能,普通员工或用户难以系统掌握。 * 资源壁垒强:产品需求的落地需要依赖开发、设计、测试等团队的资源支持,非专业产品角色无法推动资源协调。 * 试错成本高:传统产品迭代周期以月为单位,需求验证成本极高,非专业人员的创意难以快速得到市场反馈。 这些矛盾导致“人人都是产品经理”始终停留在口号层面,真正能参与产品决策的依然是专业岗位人员。 AI 对产品能力的“平民化”重构 AI 技术的成熟,尤其是大语言模型(LLM)和生成式 AI的普及,正在从根本上打破传统产品开发的能力和资源壁垒,让非专业人员也能完成从创意到落地的全流程产品设计。以下是 AI 带来的核心改变: 1.

By Ne0inhk
OpenClaw插件开发指南:30分钟学会为AI数字员工添加新技能

OpenClaw插件开发指南:30分钟学会为AI数字员工添加新技能

文章目录 * 前言 * 一、先搞懂:OpenClaw到底是啥?(小白秒懂版) * 二、开发前必看:环境准备(5分钟搞定) * 1. 系统要求 * 2. 一键安装OpenClaw * 3. 验证环境 * 三、核心原理:OpenClaw插件为啥叫“技能乐高”? * 四、实战开始:30分钟写第一个插件(查天气技能) * 第一步:创建插件文件夹 * 第二步:写插件“身份证”——SKILL.md * 第三步:写功能实现脚本(index.js) * 第四步:配置环境变量 * 第五步:加载插件并测试 * 五、进阶技巧:让你的插件更专业(新手必学) * 1. 插件安全规范(官方强制要求) * 2. 插件优化小技巧 * 3. 插件发布(

By Ne0inhk