##HarmonyOS Next实战##HarmonyOS SDK应用服务##教育##
目标:拖拽网格元素时,实现网格元素的交换
知识点:
Grid网格元素拖拽交换功能在应用中经常会被使用,如当编辑九宫格图片需要拖拽图片改变排序时,就会使用到该功能。当网格中图片进行拖拽交换时,元素排列会跟随图片拖拽的位置而发生变化,并且会有对应的动画效果,以达到良好的用户体验。
Grid网格布局一般由Grid容器组件和子组件GridItem构建生成,Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。网格布局中含有网格元素,当给Grid容器组件设置editMode属性为true时,可开启Grid组件的编辑模式。开启编辑模式后,还需要给GridItem组件绑定长按、拖拽等手势。最后,需要添加显式动画,并设置相应的动画效果。最终,呈现出网格元素拖拽交换的动效过程。
Grid网格元素拖拽交换功能实现是通过Grid容器组件、组合手势、显式动画结合来实现的。
- Grid组件可以构建网格元素布局。
- 组合手势可以实现元素拖拽交换的效果。
- 显式动画可以给元素拖拽交换的过程中,添加动画效果。
注意
Grid组件当前支持GridItem拖拽动画,通过给Grid容器组件设置supportAnimation为true,即可开启动画效果。但仅支持在滚动模式下(设置rowsTemplate、columnsTemplate其中一个)支持动画。且仅在大小规则的Grid中支持拖拽动画,跨行或跨列场景不支持。因此,在跨行或跨列场景下,需要通过自定义Gird布局、自定义手势和显式动画来实现拖拽交换的效果。
在需要拖拽交换的场景中,开发流程:
- 实现Grid布局,启动editMode编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem。
- 给网络元素GridItem绑定相关手势,实现可拖拽操作。
- 使用显式动画animateTo,实现GridItem拖拽过程中的动画效果。
实战:GridItemDragExchangeDemoPage
@Entry
@Component
struct GridItemDragExchangeDemoPage {
numbers: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
@State imageNum: number = 1
build() {
Column() {
Text('网格元素拖拽交换Demo')
Grid() {
ForEach(this.numbers, (item: number) => {
GridItem() {
Row() {
Text(item.toString())
}
.width(116)
.aspectRatio(1)
.draggable(false)
.animation({ curve: Curve.Sharp, duration: 300 })
.backgroundColor(Color.Gray)
.justifyContent(FlexAlign.Center)
}
}, (item: number) => item.toString())
}
.width('100%')
.scrollBar(BarState.Off)
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(4)
.rowsGap(4)
.editMode(true)
.supportAnimation(true)
.onItemDragStart((_, itemIndex: number) => {
this.imageNum = this.numbers[itemIndex];
return this.pixelMapBuilder();
})
.onItemDrop((_, itemIndex: number, insertIndex: number,
isSuccess: boolean) => {
if (!isSuccess || insertIndex >= this.numbers.length) {
return;
}
this.changeIndex(itemIndex, insertIndex);
})
}
.height('100%')
.width('100%')
}
changeIndex(index1: number, index2: number): void {
let tmp = this.numbers.splice(index1, 1);
this.numbers.splice(index2, 0, tmp[0]);
}
@Builder
pixelMapBuilder() {
Column() {
Row() {
Text(this.imageNum.toString())
}
.width(116)
.aspectRatio(1)
.draggable(false)
.animation({ curve: Curve.Sharp, duration: 300 })
.backgroundColor(Color.Gray)
.justifyContent(FlexAlign.Center)
}
.zIndex(1)
.scale({ x: 1.05, y: 1.05 })
.translate({ x: 0, y: 0 })
}
}