鸿蒙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.mzph.cn/news/753163.shtml

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

相关文章

Web 开发模式演进过程

作为初学者&#xff0c;要了解 Web 开发模式的演进过程&#xff0c;并从这些演进过程中看到变化&#xff0c;这样有利于开发者的思路提升。 什么是 Web 开发 Web &#xff1a;网页&#xff0c;可以通过浏览器访问的资源 Web 开发&#xff1a;基于网页载体的软件开发&#xff…

mac下Appuim环境安装

参考资料 Mac安装Appium_mac电脑安装appium-CSDN博客 安卓测试工具&#xff1a;Appium 环境安装&#xff08;mac版本&#xff09;_安卓自动化测试mac环境搭建-CSDN博客 1. 基本环境依赖 1 node.js 2 JDK&#xff08;Java JDK&#xff09; 3 Android SDK 4 Appium&#x…

Verilog——综合和防真

2.1综合 Verilog 是硬件描述语言&#xff0c;顾名思义&#xff0c;就是用代码的形式描述硬件的功能&#xff0c;最终在硬件电路上实 现该功能。在Verilog描述出硬件功能后需要使用综合器对Verilog代码进行解释并将代码转化成实际 的电路来表示&#xff0c;最终产生实际的电路&a…

APP性能测试,你需要关注哪些指标?

一、Android客户端性能测试常见指标 1、内存 2、CPU 3、流量 4、电量 5、启动速度 6、滑动速度、界面切换速度 7、与服务器交互的网络速度 二、预期标准指定原则 1、分析竞争对手的产品&#xff0c;所有指标要强于竞品 2、产品经理给出的预期性能指标数据 3、符合业…

【Python使用】嘿马头条完整开发md笔记第2篇:数据库,作用【附代码文档】

嘿马头条项目从到完整开发笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;课程简介&#xff0c;ToutiaoWeb虚拟机使用说明&#xff0c;Pycharm远程开发&#xff0c;产品与开发&#xff0c;数据库1 产品介绍,2 原型图与UI图,3 技术架构,4 开发。OS…

SSL证书过期不更新会有什么影响?怎么续签?

SSL证书如果不及时更新&#xff0c;可能会带来以下问题&#xff1a; 1.影响体验和信誉&#xff1a; - 如果你的网站SSL证书过期了&#xff0c;现在大部分浏览器都会提醒用户这个网站的安全证书已经失效。这就很可能让用户觉得你的网站不太安全&#xff0c;不敢继续浏览&#x…

Python接口自动化之接口依赖

一、场景说明 在面试接口自动化时&#xff0c;经常会问&#xff0c;其他接口调用的前提条件是当前用户必须是登录状态&#xff0c;如何处理接口依赖&#xff1f; 在此之前我们介绍过session管理器保存会话状态。如果接口请求需要携带token&#xff0c;那么又如果处理呢&#…

绿色再生·安卓4G智能远程操作巡视机器人小车

一、前言 1.1 项目介绍 【1】项目功能介绍 随着物联网技术与移动通信技术的快速发展&#xff0c;远程遥控设备在日常生活及工业应用中的普及度日益提高。无论是家用扫地机器人实现自主导航清扫&#xff0c;还是目前抖音平台上展示的实景互动小车等创新应用&#xff0c;都体现…

Games101笔记-模型、视图、投影

在旋转点&#xff0c;旋转矩阵的逆等于矩阵的转置 视图变换和投影变换 三维变换 左边3*3是线性变换&#xff0c;右边一列是仿射变换(平移) 先线性再平移 缩放、旋转、平移 x叉乘y得到z&#xff0c;y叉乘z得到x&#xff0c; xyz给任何两个可以得到另一个 (循环对称) z叉乘x得…

sqllab第十一关通关笔记

知识点&#xff1a; 发现登录框就可以尝试注入登录框一般都是字符型注入通过注入可以获取其他表的信息绕过手段 单引号闭合联合注入也可以进行错误注入 首先看界面是一个登录框&#xff1b;通过admin admin登录进去&#xff0c;发现页面会把用户名和密码的登录信息打印出来&am…

美区PayPal绑visa卡注意事项

很多小伙伴都有绑定paypal的需求&#xff0c;但是如果你是绑定美区的paypal这里有几点建议&#xff1a; 1、建议使用US的网络环境注册 2、使用美区的账号 3、使用美区的visa卡 三者统一才可以绑定成功&#xff0c;点击获取可以绑定美区paypal的visa卡&#xff0c;办理简单

【vue elementUI】修改el-dropdown样式

实现效果如下&#xff1a; 代码如下&#xff1a; <el-dropdown trigger"click" command"handleCommand" active-text-color"#606266"><span class"product-card">{{getCategoryName(categoryId)}}</span><el-dro…

docker安装华为opengauss高斯数据库

opengauss高斯数据库 openGauss是一款企业级开源关系型数据库&#xff0c;由华为公司推出。它深度融合了华为多年的数据库领域经验&#xff0c;充分结合企业级场景需求&#xff0c;基于openGauss自研生态而打造。 在架构上&#xff0c;openGauss着重于传统数据库的企业级能力和…

Monorepo 解决方案 — 基于 Bazel 的 Xcode 性能优化实践

背景介绍 书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》&#xff0c;在头条工程切换至 Bazel 构建系统后&#xff0c;为了支持用户使用 Xcode 开发的习惯&#xff0c;我们使用了开源项目 Tulsi 作为生成工具&#xff0c;用于将 Bazel 工程转换为 Xcode 工程。但是…

sqllab第二十七关通关笔记

知识点&#xff1a; union select 关键字过滤 通过<> /**/进行截断处理 un<>ion sel<>ect 没效果uni/**/on sel/**/ect 被过滤了双写绕过 这关对select进行了多重过滤&#xff0c;无法进行双写绕过 大小写绕过 UNion SElect (这关可以用&am…

OpenvSwitch 配置 Trunk 端口实验

OpenvSwitch 配置 Trunk 端口实验 Open vSwitch(OVS)作为一款领先的软件交换机&#xff0c;为构建灵活、可扩展的虚拟网络架构提供了强大的支持。其中Trunk口(Trunk Port)功能就是OVS中一个非常实用的特性。 Trunk口允许在同一个物理端口上传输多个VLAN的数据流量。通过配置T…

西门子上位机软件WINCC的项目改造及其多元化报警功能实践:巨控GRM560智能远程控制终端

标签: #西门子WINCC #OPC通讯 #短信报警系统 #项目改造 #智能报警 西门子上位机软件WINCC的项目改造及其多元化报警功能实践 在工业自动化领域&#xff0c;有效的监控和及时的异常响应是保障生产安全和效率的关键。西门子的WINCC上位机软件升级&#xff0c;整合了巨控的OPC560…

Python 计算1~100 求和

result0 for i in range(101):print(i)result result i print(result)

Redis 内存是如何划分的?

查询内存命令 info memory 查询Redis自身使用内存的统计数据。通过这个命令&#xff0c;可以了解 Redis 实例的内存分配情况、内存碎片、键空间使用情况等 内存分配情况&#xff1a; used_memory&#xff1a;Redis 实例当前使用的内存总量&#xff08;以字节为单位&#xff0…

【初学者】Visual Studio 2019没有 C 项目,只有C++怎么办? 怎么创建第一个项目教程。

起因&#xff1a; 想要在 Visual Studio 上创建一个 C 项目&#xff0c;发现只有 C 的。 解决&#xff1a; C 是 C 的超集。只要创建 C 的项目就行了&#xff0c;将新增的 .cpp 文件改后缀为 .c 即可。不会有问题的。 C 的语法更加严格&#xff0c;而 C 的项目更宽松。虽然…