鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Grid)

网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。

说明:

该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

子组件

仅支持GridItem子组件。

说明:

Grid子组件的索引值计算规则:

按子组件的顺序依次递增。

if/else语句中,只有条件成立分支内的子组件会参与索引值计算,条件不成立分支内的子组件不计算索引值。

ForEach/LazyForEach语句中,会计算展开所有子节点索引值。

if/else、ForEach和LazyForEach发生变化以后,会更新子节点索引值。

Grid子组件的visibility属性设置为Hidden或None时依然会计算索引值。

Grid子组件的visibility属性设置为None时不显示,但依然会占用子组件对应的网格。

Grid子组件设置position属性,会占用子组件对应的网格,子组件将显示在相对Grid左上角偏移position的位置。该子组件不会随其对应网格滚动,在对应网格滑出Grid显示范围外后不显示。

当Grid子组件之间留有空隙时,会根据当前的展示区域尽可能填补空隙,因此GridItem可能会随着网格滚动而改变相对位置。

接口

Grid(scroller?: Scroller, layoutOptions?: GridLayoutOptions)

参数:

参数名参数类型必填参数描述
scrollerScroller可滚动组件的控制器,与可滚动组件绑定。
说明:
不允许和其他滚动类组件,如:List、Grid、Scroll等绑定同一个滚动控制对象。
layoutOptions10+GridLayoutOptions滚动Grid布局选项。

GridLayoutOptions10+

布局选项。其中,irregularIndexes和onGetIrregularSizeByIndex可对仅设置rowsTemplate或columnsTemplate的Grid使用,可以指定一个index数组,并为其中的index对应的GridItem设置其占据的行数与列数,使用方法参见示例3;onGetRectByIndex可对同时设置rowsTemplate和columnsTemplate的Grid使用,为指定的index对应的GridItem设置位置和大小,使用方法参见示例1。

参数:

名称类型必填描述
regularSize[number, number]大小规则的GridItem在Grid中占的行数和列数,只支持占1行1列即[1, 1]。
irregularIndexesnumber[]指定的GridItem索引在Grid中的大小是不规则的。当不设置onGetIrregularSizeByIndex时,irregularIndexes中GridItem的默认大小为垂直滚动Grid的一整行或水平滚动Grid的一整列。
onGetIrregularSizeByIndex(index: number) => [number, number]配合irregularIndexes使用,设置不规则GridItem占用的行数和列数。开发者可为irregularIndexes中指明的index对应的GridItem设置占用的行数和列数。垂直滚动Grid不支持GridItem占多行,水平滚动Grid不支持GridItem占多列。
onGetRectByIndex11+(index: number) => [number, number,number,number]设置指定索引index对应的GridItem的位置及大小[rowStart,columnStart,rowSpan,columnSpan]。
其中rowStart为行起始位置,columnStart为列起始位置,无单位。
rowSpan为GridItem占用的行数,columnSpan为GridItem占用的列数,无单位。
rowStart和columnStart取大于等于0的自然数,若取负数时,rowStart和columnStart默认为0。
rowSpan和columnSpan取大于等于1的自然数,若取小数则向下取整,若小于1则按1计算。
说明:
第一种情况:某个GridItem发现给它指定的起始位置被占据了,则从起始位置[0,0]开始按顺序从左到右,从上到下寻找起始的放置位置。
第二种情况:如果起始位置没有被占据,但其他位置被占据了,无法显示全部的GridItem大小,则只会布局一部分。

属性

除支持通用属性外,还支持以下属性:

名称参数类型描述
columnsTemplatestring设置当前网格布局列的数量或最小列宽值,不设置时默认1列。
例如, '1fr 1fr 2fr' 是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。
columnsTemplate('repeat(auto-fit, track-size)')是设置最小列宽值为track-size,自动计算列数和实际列宽。
columnsTemplate('repeat(auto-fill, track-size)')是设置固定列宽值为track-size,自动计算列数。
其中repeat、auto-fit、auto-fill为关键字。track-size为列宽,支持的单位包括px、vp、%或有效数字,默认单位为vp,track-size至少包括一个有效列宽。
说明:
设置为'0fr'时,该列的列宽为0,不显示GridItem。设置为其他非法值时,GridItem显示为固定1列。
rowsTemplatestring设置当前网格布局行的数量或最小行高值,不设置时默认1行。
例如, '1fr 1fr 2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。
rowsTemplate('repeat(auto-fit, track-size)')是设置最小行高值为track-size,自动计算行数和实际行高。
rowsTemplate('repeat(auto-fill, track-size)')是设置固定行高值为track-size,自动计算行数。
其中repeat、auto-fit、auto-fill为关键字。track-size为行高,支持的单位包括px、vp、%或有效数字,默认单位为vp,track-size至少包括一个有效行高。
说明:
设置为'0fr',则这一行的行宽为0,这一行GridItem不显示。设置为其他非法值,按固定1行处理。
columnsGapLength设置列与列的间距。
默认值:0
说明:
设置为小于0的值时,按默认值显示。
rowsGapLength设置行与行的间距。
默认值:0
说明:
设置为小于0的值时,按默认值显示。
scrollBarBarState设置滚动条状态。
默认值:BarState.Off
说明:
API version 9及以下版本默认值为BarState.Off,API version 10的默认值为BarState.Auto。
scrollBarColorstring | number | Color设置滚动条的颜色。
scrollBarWidthstring | number设置滚动条的宽度。宽度设置后,滚动条正常状态和按压状态宽度均为滚动条的宽度值。
默认值:4
单位:vp
cachedCountnumber设置预加载的GridItem的数量,只在LazyForEach中生效。具体使用可参考减少应用白块说明。
默认值:1
说明:
设置缓存后会在Grid显示区域上下各缓存cachedCount*列数个GridItem。
LazyForEach超出显示和缓存范围的GridItem会被释放。
设置为小于0的值时,按默认值显示。
editMode 8+boolean设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem。
默认值:flase
layoutDirection8+GridDirection设置布局的主轴方向。
默认值:GridDirection.Row
maxCount8+number当layoutDirection是Row/RowReverse时,表示可显示的最大列数
当layoutDirection是Column/ColumnReverse时,表示可显示的最大行数。
默认值:Infinity
说明:
当maxCount小于minCount时,maxCount和minCount都按默认值处理。
设置为小于1的值时,按默认值显示。
minCount8+number当layoutDirection是Row/RowReverse时,表示可显示的最小列数。
当layoutDirection是Column/ColumnReverse时,表示可显示的最小行数。
默认值:1
说明:
设置为小于1的值时,按默认值显示。
cellLength8+number当layoutDirection是Row/RowReverse时,表示一行的高度。
当layoutDirection是Column/ColumnReverse时,表示一列的宽度。
默认值:第一个元素的大小
multiSelectable8+boolean是否开启鼠标框选。
默认值:false
- false:关闭框选。
- true:开启框选。
说明:
开启框选后,可以配合Griditem的selected属性和onSelect事件获取GridItem的选中状态,还可以设置选中态样式(无默认选中样式)。
supportAnimation8+boolean是否支持动画。当前支持GridItem拖拽动画。
默认值:false
说明:
仅在滚动模式下(只设置rowsTemplate、columnsTemplate其中一个)支持动画。
edgeEffect10+value:EdgeEffect,
options?:EdgeEffectOptions11+
设置边缘滑动效果。
- value: 设置Grid组件的边缘滑动效果,支持弹簧效果和阴影效果。
默认值:EdgeEffect.None
- options:设置组件内容大小小于组件自身时,是否开启滑动效果。
默认值:false
enableScrollInteraction10+boolean设置是否支持滚动手势,当设置为false时,无法通过手指或者鼠标滚动,但不影响控制器的滚动接口。
默认值:true
nestedScroll10+NestedScrollOptions嵌套滚动选项。设置向前向后两个方向上的嵌套滚动模式,实现与父组件的滚动联动。
friction10+number | Resource设置摩擦系数,手动划动滚动区域时生效,只对惯性滚动过程有影响,对惯性滚动过程中的链式效果有间接影响。
默认值:非可穿戴设备为0.6,可穿戴设备为0.9
说明:
设置为小于等于0的值时,按默认值处理

Grid组件根据rowsTemplate、columnsTemplate属性的设置情况,可分为以下三种布局模式:

1、rowsTemplate、columnsTemplate同时设置:

  • Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。
  • 此模式下以下属性不生效:layoutDirection、maxCount、minCount、cellLength。
  • Grid的宽高没有设置时,默认适应父组件尺寸。
  • Gird网格列大小按照Gird自身内容区域大小减去所有行列Gap后按各个行列所占比重分配。
  • GridItem默认填满网格大小。

2、rowsTemplate、columnsTemplate仅设置其中的一个:

  • 元素按照设置的方向进行排布,超出Grid显示区域后,Grid可通过滚动的方式展示。
  • 如果设置了columnsTemplate,Gird滚动方向为垂直方向,主轴方向为垂直方向,交叉轴方向为水平方向。
  • 如果设置了rowsTemplate,Gird滚动方向为水平方向,主轴方向为水平方向,交叉轴方向为垂直方向。
  • 此模式下以下属性不生效:layoutDirection、maxCount、minCount、cellLength。
  • 网格交叉轴方向尺寸根据Gird自身内容区域交叉轴尺寸减去交叉轴方向所有Gap后按所占比重分配。
  • 网格主轴方向尺寸取当前网格交叉轴方向所有GridItem高度最大值。

3、rowsTemplate、columnsTemplate都不设置:

  • 元素在layoutDirection方向上排布,列数由Grid的宽度、首个元素的宽度、minCount、maxCount、columnsGap共同决定。
  • 行数由Grid高度、首个元素高度、cellLength、rowsGap共同决定。超出行列容纳范围的元素不显示,也不能通过滚动进行展示。
  • 此模式下仅生效以下属性:layoutDirection、maxCount、minCount、cellLength、editMode、columnsGap、rowsGap。
  • 当前layoutDirection设置为Row时,先从左到右排列,排满一行再排下一行。剩余高度不足时不再布局,整体内容顶部居中。
  • 当前layoutDirection设置为Column时,先从上到下排列,排满一列再排下一列,剩余宽度不足时不再布局。整体内容顶部居中。

GridDirection8+枚举说明

名称枚举值描述
Row0主轴布局方向沿水平方向布局,即自左往右先填满一行,再去填下一行。
Column1主轴布局方向沿垂直方向布局,即自上往下先填满一列,再去填下一列。
RowReverse2主轴布局方向沿水平方向反向布局,即自右往左先填满一行,再去填下一行。
ColumnReverse3主轴布局方向沿垂直方向反向布局,即自下往上先填满一列,再去填下一列。

说明:

Grid组件通用属性clip的默认值为true。

事件

除支持通用事件外,还支持以下事件:

名称功能描述
onScrollIndex(event: (first: number, last10+: number) => void)当前网格显示的起始位置/终止位置的item发生变化时触发。网格初始化时会触发一次。
- first: 当前显示的网格起始位置的索引值。
- last: 当前显示的网格终止位置的索引值。
Grid显示区域上第一个子组件/最后一个组件的索引值有变化就会触发。
onItemDragStart8+(event: (event: ItemDragInfo, itemIndex: number) => (() => any) | void)开始拖拽网格元素时触发。
- event: 见ItemDragInfo对象说明。
- itemIndex: 被拖拽网格元素索引值。
说明:
返回void表示不能拖拽。
手指长按GridItem时触发该事件。
由于拖拽检测也需要长按,且事件处理机制优先触发子组件事件,GridItem上绑定LongPressGesture时无法触发拖拽;如有长按和拖拽同时使用的需求可以使用通用拖拽事件。
onItemDragEnter8+(event: (event: ItemDragInfo) => void)拖拽进入网格元素范围内时触发。
- event: 见ItemDragInfo对象说明。
onItemDragMove8+(event: (event: ItemDragInfo, itemIndex: number, insertIndex: number) => void)拖拽在网格元素范围内移动时触发。
- event: 见ItemDragInfo对象说明。
- itemIndex: 拖拽起始位置。
- insertIndex: 拖拽插入位置。
onItemDragLeave8+(event: (event: ItemDragInfo, itemIndex: number) => void)拖拽离开网格元素时触发。
- event: 见ItemDragInfo对象说明。
- itemIndex: 拖拽离开的网格元素索引值。
onItemDrop8+(event: (event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => void)绑定该事件的网格元素可作为拖拽释放目标,当在网格元素内停止拖拽时触发。
- event: 见ItemDragInfo对象说明。
- itemIndex: 拖拽起始位置。
- insertIndex: 拖拽插入位置。
- isSuccess: 是否成功释放。
onScrollBarUpdate10+(event: (index: number, offset: number) => ComputedBarAttribute)当前网格显示的起始位置item发生变化时触发,可通过该回调设置滚动条的位置及长度。
- index: 当前显示的网格起始位置的索引值。
- offset: 当前显示的网格起始位置元素相对网格显示起始位置的偏移,单位vp。
- ComputedBarAttribute: 见ComputedBarAttribute对象说明。
onScroll10+(event: (scrollOffset: number, scrollState: ScrollState) => void)网格滑动时触发。
- scrollOffset: 每帧滚动的偏移量,Grid的内容向上滚动时偏移量为正,向下滚动时偏移量为负,单位vp。
- scrollState: 当前滑动状态。
onReachStart10+(event: () => void)网格到达起始位置时触发。
说明:
Grid初始化时会触发一次,Grid滚动到起始位置时触发一次。Grid边缘效果为弹簧效果时,划动经过起始位置时触发一次,回弹回起始位置时再触发一次。
onReachEnd10+(event: () => void)网格到达末尾位置时触发。
说明:
Grid边缘效果为弹簧效果时,划动经过末尾位置时触发一次,回弹回末尾位置时再触发一次。
onScrollFrameBegin10+(event: (offset: number, state: ScrollState) => { offsetRemain: number })网格开始滑动时触发,事件参数传入即将发生的滑动量,事件处理函数中可根据应用场景计算实际需要的滑动量并作为事件处理函数的返回值返回,网格将按照返回值的实际滑动量进行滑动。
- offset:即将发生的滑动量,单位vp。
- state:当前滑动状态。
- offsetRemain:实际滑动量,单位vp。
触发该事件的条件:手指拖动Grid、Grid惯性划动时每帧开始时触发;Grid超出边缘回弹、使用滚动控制器和拖动滚动条的滚动不会触发。
说明:
当gridDirection的值为Axis.Vertical时,返回垂直方向滑动量,当gridDirection的值为Axis.Horizontal时,返回水平方向滑动量。
onScrollStart10+(event: () => void)网格滑动开始时触发。手指拖动网格或网格的滚动条触发的滑动开始时,会触发该事件。使用Scroller滑动控制器触发的带动画的滑动,动画开始时会触发该事件。
onScrollStop10+(event: () => void)网格滑动停止时触发。手指拖动网格或网格的滚动条触发的滑动,手指离开屏幕并且滑动停止时会触发该事件;使用Scroller滑动控制器触发的带动画的滑动,动画停止会触发该事件。

ItemDragInfo对象说明

名称类型描述
xnumber当前拖拽点的x坐标,单位vp。
ynumber当前拖拽点的y坐标,单位vp。

ComputedBarAttribute对象说明

名称类型描述
totalOffsetnumberGrid内容相对显示区域的总偏移,单位px。
totalLengthnumberGrid内容总长度,单位px。

示例

示例1

固定行列的Grid,可以使用GridLayoutOptions中的onGetRectByIndex指定GridItem的位置和大小。

// xxx.ets
@Entry
@Component
struct GridExample {@State numbers1: String[] = ['0', '1', '2', '3', '4']@State numbers2: String[] = ['0', '1','2','3','4','5']layoutOptions3: GridLayoutOptions = {regularSize: [1, 1],onGetRectByIndex: (index: number) => {if (index == 0)return [0, 0, 1, 1]else if(index==1)return [0, 1, 2, 2]else if(index==2)return [0 ,3 ,3 ,3]else if(index==3)return [3, 0, 3, 3]else if(index==4)return [4, 3, 2, 2]elsereturn [5, 5, 1, 1]}}build() {Column({ space: 5 }) {Grid() {ForEach(this.numbers1, (day: string) => {ForEach(this.numbers1, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width('100%').height('100%').textAlign(TextAlign.Center)}}, (day: string) => day)}, (day: string) => day)}.columnsTemplate('1fr 1fr 1fr 1fr 1fr').rowsTemplate('1fr 1fr 1fr 1fr 1fr').columnsGap(10).rowsGap(10).width('90%').backgroundColor(0xFAEEE0).height(300)Text('GridLayoutOptions的使用:onGetRectByIndex。').fontColor(0xCCCCCC).fontSize(9).width('90%')Grid(undefined, this.layoutOptions3) {ForEach(this.numbers2, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width('100%').height("100%").textAlign(TextAlign.Center)}.height("100%").width('100%')}, (day: string) => day)}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr').rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr').columnsGap(10).rowsGap(10).width('90%').backgroundColor(0xFAEEE0).height(300)}.width('100%').margin({ top: 5 })}
}

zh-cn_image_0000001219744183

示例2

可滚动Grid,包括所有滚动属性和事件。

// xxx.ets
@Entry
@Component
struct GridExample {@State numbers: String[] = ['0', '1', '2', '3', '4']scroller: Scroller = new Scroller()@State Position: number = 0 //0代表滚动到grid顶部,1代表中间值,2代表滚动到grid底部。build() {Column({ space: 5 }) {Text('scroll').fontColor(0xCCCCCC).fontSize(9).width('90%')Grid(this.scroller) {ForEach(this.numbers, (day: string) => {ForEach(this.numbers, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width('100%').height(80).textAlign(TextAlign.Center)}}, (day: string) => day)}, (day: string) => day)}.columnsTemplate('1fr 1fr 1fr 1fr 1fr').columnsGap(10).rowsGap(10).friction(0.6).enableScrollInteraction(true).supportAnimation(false).multiSelectable(false).edgeEffect(EdgeEffect.Spring).scrollBar(BarState.On).scrollBarColor(Color.Grey).scrollBarWidth(4).width('90%').backgroundColor(0xFAEEE0).height(300).onScrollIndex((first: number) => {console.info(first.toString())}).onScrollBarUpdate((index: number, offset: number) => {console.info("XXX" + 'Grid onScrollBarUpdate,index : ' + index.toString() + ",offset" + offset.toString())return { totalOffset: (index / 5) * (80 + 10) - offset, totalLength: 80 * 5 + 10 * 4 }})  //只适用于当前示例代码数据源,如果数据源有变化,则需要修改该部分代码,或者删掉此属性.onScroll((first: number, last: number) => {console.info(first.toString())console.info(last.toString())}).onScrollStart(() => {console.info("XXX" + "Grid onScrollStart")}).onScrollStop(() => {console.info("XXX" + "Grid onScrollStop")}).onReachStart(() => {this.Position = 0console.info("XXX" + "Grid onReachStart")}).onReachEnd(() => {this.Position = 2console.info("XXX" + "Grid onReachEnd")})Button('next page').onClick(() => { // 点击后滑到下一页this.scroller.scrollPage({ next: true })})}.width('100%').margin({ top: 5 })}
}

scrollerExample2

示例3

GridLayoutOptions的使用:irregularIndexes与onGetIrregularSizeByIndex。

// xxx.ets
@Entry
@Component
struct GridExample {@State numbers: String[] = ['0', '1', '2', '3', '4']scroller: Scroller = new Scroller()layoutOptions1: GridLayoutOptions = {regularSize: [1, 1],        // 只支持[1, 1]irregularIndexes: [0, 6],   // 索引为0和6的GridItem占用一行}layoutOptions2: GridLayoutOptions = {regularSize: [1, 1],irregularIndexes: [0, 7],   // 索引为0和7的GridItem占用的列数由onGetIrregularSizeByIndex指定onGetIrregularSizeByIndex: (index: number) => {if (index === 0) {return [1, 5]}return [1, index % 6 + 1]}}build() {Column({ space: 5 }) {Grid(this.scroller, this.layoutOptions1) {ForEach(this.numbers, (day: string) => {ForEach(this.numbers, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width('100%').height(80).textAlign(TextAlign.Center)}.selectable(false)}, (day: string) => day)}, (day: string) => day)}.columnsTemplate('1fr 1fr 1fr 1fr 1fr').columnsGap(10).rowsGap(10).multiSelectable(true).scrollBar(BarState.Off).width('90%').backgroundColor(0xFAEEE0).height(300)Text('scroll').fontColor(0xCCCCCC).fontSize(9).width('90%')// 不使用scroll,需要undefined占位Grid(undefined, this.layoutOptions2) {ForEach(this.numbers, (day: string) => {ForEach(this.numbers, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width('100%').height(80).textAlign(TextAlign.Center)}}, (day: string) => day)}, (day: string) => day)}.columnsTemplate('1fr 1fr 1fr 1fr 1fr').columnsGap(10).rowsGap(10).scrollBar(BarState.Off).width('90%').backgroundColor(0xFAEEE0).height(300)}.width('100%').margin({ top: 5 })}
}

gridLayoutOptions

示例4

nestedScroll和onScrollFrameBegin的使用。

@Entry
@Component
struct GridExample {@State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]@State numbers: number[] = []@State translateY: number = 0private scroller: Scroller = new Scroller()private gridScroller: Scroller = new Scroller()private touchDown: boolean = falseprivate listTouchDown: boolean = falseprivate scrolling: boolean = falseaboutToAppear() {for (let i = 0; i < 100; i++) {this.numbers.push(i)}}build() {Stack() {Column() {Row() {Text('Head')}Column() {List({ scroller: this.scroller }) {ListItem() {Grid() {GridItem() {Text('GoodsTypeList1')}.backgroundColor(this.colors[0]).columnStart(0).columnEnd(1)GridItem() {Text('GoodsTypeList2')}.backgroundColor(this.colors[1]).columnStart(0).columnEnd(1)GridItem() {Text('GoodsTypeList3')}.backgroundColor(this.colors[2]).columnStart(0).columnEnd(1)GridItem() {Text('GoodsTypeList4')}.backgroundColor(this.colors[3]).columnStart(0).columnEnd(1)GridItem() {Text('GoodsTypeList5')}.backgroundColor(this.colors[4]).columnStart(0).columnEnd(1)}.scrollBar(BarState.Off).columnsGap(15).rowsGap(10).rowsTemplate('1fr 1fr 1fr 1fr 1fr').columnsTemplate('1fr').width('100%').height(200)}ListItem() {Grid(this.gridScroller) {ForEach(this.numbers, (item: number) => {GridItem() {Text(item + '').fontSize(16).backgroundColor(0xF9CF93).width('100%').height('100%').textAlign(TextAlign.Center)}.width('100%').height(40).shadow({ radius: 10, color: '#909399', offsetX: 1, offsetY: 1 }).borderRadius(10).translate({ x: 0, y: this.translateY })}, (item: string) => item)}.columnsTemplate('1fr 1fr').friction(0.3).columnsGap(15).rowsGap(10).scrollBar(BarState.Off).width('100%').height('100%').layoutDirection(GridDirection.Column).nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward: NestedScrollMode.SELF_FIRST}).onTouch((event: TouchEvent) => {if (event.type == TouchType.Down) {this.listTouchDown = true} else if (event.type == TouchType.Up) {this.listTouchDown = false}})}}.scrollBar(BarState.Off).edgeEffect(EdgeEffect.None).onTouch((event: TouchEvent) => {if (event.type == TouchType.Down) {this.touchDown = true} else if (event.type == TouchType.Up) {this.touchDown = false}}).onScrollFrameBegin((offset: number, state: ScrollState) => {if (this.scrolling && offset > 0) {let newOffset = this.scroller.currentOffset().yOffsetif (newOffset >= 590) {this.gridScroller.scrollBy(0, offset)return { offsetRemain: 0 }} else if (newOffset + offset > 590) {this.gridScroller.scrollBy(0, newOffset + offset - 590)return { offsetRemain: 590 - newOffset }}}return { offsetRemain: offset }}).onScrollStart(() => {if (this.touchDown && !this.listTouchDown) {this.scrolling = true}}).onScrollStop(() => {this.scrolling = false})}.width('100%').height('100%').padding({ left: 10, right: 10 })}Row() {Text('Top').width(30).height(30).borderRadius(50)}.padding(5).borderRadius(50).backgroundColor('#ffffff').shadow({ radius: 10, color: '#909399', offsetX: 1, offsetY: 1 }).margin({ right: 22, bottom: 15 }).onClick(() => {this.scroller.scrollTo({ xOffset: 0, yOffset: 0 })this.gridScroller.scrollTo({ xOffset: 0, yOffset: 0 })})}.align(Alignment.BottomEnd)}
}

nestedScrollExample4

示例5

  1. 设置属性editMode(true)设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem。
  2. 在onItemDragStart回调中设置拖拽过程中显示的图片。
  3. 在onItemDrop中获取拖拽起始位置,和拖拽插入位置,并在onItemDrop中完成交换数组位置逻辑。

说明:

预览器窗口不支持显示拖拽跟手。

@Entry
@Component
struct GridExample {@State numbers: string[] = []scroller: Scroller = new Scroller()@State text: string = 'drag'@Builder pixelMapBuilder() { //拖拽过程样式Column() {Text(this.text).fontSize(16).backgroundColor(0xF9CF93).width(80).height(80).textAlign(TextAlign.Center)}}aboutToAppear() {for (let i = 1;i <= 15; i++) {this.numbers.push(i + '')}}changeIndex(index1: number, index2: number) { //交换数组位置let temp: string;temp = this.numbers[index1];this.numbers[index1] = this.numbers[index2];this.numbers[index2] = temp;}build() {Column({ space: 5 }) {Grid(this.scroller) {ForEach(this.numbers, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93).width(80).height(80).textAlign(TextAlign.Center)}})}.columnsTemplate('1fr 1fr 1fr').columnsGap(10).rowsGap(10).onScrollIndex((first: number) => {console.info(first.toString())}).width('90%').backgroundColor(0xFAEEE0).height(300).editMode(true) //设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem.onItemDragStart((event: ItemDragInfo, itemIndex: number) => { //第一次拖拽此事件绑定的组件时,触发回调。this.text = this.numbers[itemIndex]return this.pixelMapBuilder() //设置拖拽过程中显示的图片。}).onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => { //绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。// isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生if (!isSuccess || insertIndex >= this.numbers.length) {return}console.info('beixiang' + itemIndex + '', insertIndex + '') //itemIndex拖拽起始位置,insertIndex拖拽插入位置this.changeIndex(itemIndex, insertIndex)})}.width('100%').margin({ top: 5 })}
}

示例图:

网格子组件开始拖拽:

gridDrag

网格子组件拖拽过程中:

gridDrag

网格子组件1与子组件6拖拽交换位置后:

gridDrag

示例6

layoutDirection、maxcount、minCount、cellLength的使用。

@Entry
@Component
struct GridExample {@State numbers: string[] = []aboutToAppear() {for (let i = 1; i <= 30; i++) {this.numbers.push(i + '')}}build() {Scroll() {Column({ space: 5 }) {Blank()Text('rowsTemplate、columnsTemplate都不设置layoutDirection、maxcount、minCount、cellLength才生效').fontSize(15).fontColor(0xCCCCCC).width('90%')Grid() {ForEach(this.numbers, (day: string) => {GridItem() {Text(day).fontSize(16).backgroundColor(0xF9CF93)}.width(40).height(80).borderWidth(2).borderColor(Color.Red)}, (day: string) => day)}.height(300).columnsGap(10).rowsGap(10).backgroundColor(0xFAEEE0).maxCount(6).minCount(2).cellLength(0).layoutDirection(GridDirection.Row)}.width('90%').margin({ top: 5, left: 5, right: 5 }).align(Alignment.Center)}}
}

cellLength

最后,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(Harmony NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

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

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

相关文章

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言1. 移动零&#xff0…

使用opencv进行图片分析

opencv学习 一、配置环境并打开编译器 配置opencv在你的任意一个盘里创建一个专属于opencv的文件夹便于学习与整理 打开控制台winr输入cmd&#xff0c;进入后输入conda activate opencv&#xff0c;进入环境以后进入你所设置的opencv文件的盘&#xff0c;我的是D盘&#xff0…

C++_学习String

1.标准库中的string类 1. 字符串是表示字符序列的类 2. 标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的接口&#xff0c;但添加了专门用于操作单字节字符字符串的设计特性 3. string 类是使用 char( 即作为它的字符类型&#xff0c;使用它的默…

MATLAB编译器配置:MinGW

使用 MATLAB 2022b版本&#xff0c;查询编译器时如上&#xff0c;想安装个MinGW编译器&#xff0c;自带的附加资源管理不好使&#xff0c;只能换个别的法子&#xff0c;经过一些参考&#xff0c;总结如下。 步骤1.在这里下载一个MinGW.最新版本是10.3.0.然后默认安装&#xff…

音频占用磁盘空间太多 需要把mp3音频转aac音频缩小占用空间 应该怎么操作?

一&#xff1a;什么是aac格式&#xff1f; aac是一种音频压缩格式&#xff0c;它是MPEG-2标准下的一种音频压缩方式&#xff0c;也可以作为HE-AAC&#xff0c;AAC或AAC-LC格式使用&#xff0c;是音频压缩领域中的一种重要格式。与MP3的比较&#xff0c;aac在保证音质的同时可以…

【NR 定位】3GPP NR Positioning 5G定位标准解读(十五)-UL-TDOA 定位

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

jenkin部署spring boot项目【从0到1】

写在前面&#xff0c;遇到的很多错误 本来想用docker启动Jenkins的&#xff0c;也这样做了&#xff0c;但是遇到了一个非常严重的问题&#xff0c;就是mvn命令在docker里面不生效&#xff0c;然后就修改文件&#xff0c;但是发现vi不存在&#xff0c;好的。接着用yum安装vi工具…

Windows蓝牙驱动开发之模拟HID设备(一)(把Windows电脑模拟成蓝牙鼠标和蓝牙键盘等设备)

by fanxiushu 2024-03-14 转载或引用请注明原作者 把Windows电脑模拟成蓝牙鼠标和蓝牙键盘&#xff0c;简单的说&#xff0c;就是把笨重的PC电脑当成鼠标键盘来使用。 这应该是一个挺小众的应用&#xff0c;但有时感觉也应该算比较好玩吧&#xff0c; 毕竟实现一种一般人都感觉…

Selenium 自动化 —— 使用WebDriverManager自动下载驱动

上一篇文章 入门和 Hello World 实例 中&#xff0c;我们提供了一个最简单的 Selenium 上手的例子。 但是某一天&#xff0c;突然发现相同的代码居然运行报错了。这是怎么回事呢&#xff1f; 日志排查 日志中其实提示的很明显了&#xff1a;Chrome浏览器和Chrome WebDriver的…

国产Copilot--通义灵码安装教程

文章目录 在 Visual Studio Code 中安装通义灵码步骤1步骤2步骤3步骤4 参考 在 Visual Studio Code 中安装通义灵码 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解…

Unity开发一个FPS游戏之二

在之前的文章中,我介绍了如何开发一个FPS游戏,添加一个第一人称的主角,并设置武器。现在我将继续完善这个游戏,打算添加敌人,实现其智能寻找玩家并进行对抗。完成的效果如下: fps_enemy_demo 下载资源 首先是设计敌人,我们可以在网上找到一些好的免费素材,例如在Unity…

NCV7356D1R2G接口集成芯片中文资料PDF数据手册参数引脚图规格书价格图片

产品概述&#xff1a; NCV7356 是一款用于单线数据链路的物理层器件&#xff0c;能够使用多种具碰撞分解的载波感测多重存取 (CSMA/CR) 协议运行&#xff0c;如博世控制器区域网络 (CAN) 2.0 版。此串行数据链路网络适用于不需要高速数据的应用&#xff0c;低速数据可在物理介…

nginx gzip性能优化 —— 筑梦之路

对比使用和不使用gzip static处理 1. 不使用 gzip static 时的 gzip 处理 如果你不使用 gzip_static 而只是 "gzip on"&#xff0c;它每次都会被压缩并发送。 虽然它实际上可能缓存在内存中&#xff0c;但传统观点是 "每次都会执行压缩处理&#xff0c;因此 CP…

Hello,Spider!入门第一个爬虫程序

在各大编程语言中&#xff0c;初学者要学会编写的第一个简单程序一般就是“Hello, World!”&#xff0c;即通过程序来在屏幕上输出一行“Hello, World!”这样的文字&#xff0c;在Python中&#xff0c;只需一行代码就可以做到。我们把这第一个爬虫就称之为“HelloSpider”&…

Kotlin:runBlocking导致App应用出现ANR问题实例

runBlocking简介 runBlocking 是常规函数&#xff1b; runBlocking 方法会阻塞当前线程来等待&#xff1b; runBlocking 的主线程会一直 阻塞 直到 runBlocking 内部的协程执行完毕。 runBlocking导致App应用出现ANR问题实例的效果 点击页面上的 刷新按钮 调用 refreshByrunBlo…

【云原生-kubernetes系列】--kubernetes日志收集

1、ELK架构 1.1、部署ES集群 https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/ 1、下载软件包 rootes-server1:~# wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/apt/7.x/pool/main/e/elasticsearch/elasticsearch-7.12.0-…

媒体播放器及媒体服务器软件Plex

什么是 Plex &#xff1f; Plex 是一套媒体播放器及媒体服务器软件&#xff0c;让用户整理在设备上的有声书、音乐、播客、图片和视频文件&#xff0c;并通过流式传输至移动设备、智能电视和电子媒体播放器上。Plex 可用于 Windows、Android、Linux、OS X和 FreeBSD。 在接触 N…

基于SpringBoot和Echarts的全国地震可视化分析实战

目录 前言 一、后台数据服务设计 1、数据库查询 2、模型层对象设计 3、业务层和控制层设计 二、Echarts前端配置 1、地图的展示 2、次数排名统计 三、最终结果展示 1、地图展示 2、图表展示 总结 前言 在之前的博客中基于SpringBoot和PotsGIS的各省地震震发可视化分…

Redis系列学习文章分享---第三篇(Redis快速入门之Java客户端--短信登录+session+验证码+拦截器+登录刷新)

目录 Redis的短信登录实战解析1. 短信登录-基于session实现短信登录的流程2. 短信登录-实现发送短信验证码功能3. 短信登录-实现短信验证码登录和注册功能4. 短信登录-实现登录校验拦截器5. 短信登录-隐藏用户敏感信息6. 短信登录-session共享的问题分析7. 短信登录-Redis代替s…

代码+视频,R语言使用BOOT重抽样获取cox回归方程C-index(C指数)可信区间

bootstrap自采样目前广泛应用与统计学中&#xff0c;其原理很简单就是通过自身原始数据抽取一定量的样本&#xff08;也就是取子集&#xff09;&#xff0c;通过对抽取的样本进行统计学分析&#xff0c;然后继续重新抽取样本进行分析&#xff0c;不断的重复这一过程N&#xff0…