问题现象
如下图所示,需求是现在有A、B两个组,A、B两组中的元素可以拖动,并且A组中的元素可以拖动到B组,B组的元素同样可以拖动到A组,请问如何实现这种多组之间相互拖拽的效果?
点击放大
背景知识
使用Grid组件构建网格元素布局,启动editMode编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem。
onItemDragStart和onItemDrop事件分别在开始拖拽网格元素时触发和停止拖拽时触发,通过事件的组合完成交换数组位置的逻辑。
解决方案
使用Grid布局构建界面。其中,columnsTemplate可设置当前网格布局列的数量、固定列宽或最小列宽值;columnsGap可设置列与列的间距;rowsGap可设置行与行的间距。
Grid(this.scroller) {
GridItem() {
Text('标题' + this.numbers.length)
.fontSize(16)
.width('100%')
.height(30)
.padding({ left: 10 })
.textAlign(TextAlign.Start);
}
.onClick(() => {
this.isShowGroup1 = !this.isShowGroup1;
});
if (this.isShowGroup1) {
ForEach(this.numbers, (day: string) => {
GridItem() {
Text(day)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('100%')
.height(30)
.textAlign(TextAlign.Center);
};
});
}
GridItem() {
Text('标题' + this.numbers2.length)
.fontSize(16)
.width('100%')
.height(30)
.padding({ left: 10 })
.textAlign(TextAlign.Start);
}
.onClick(() => {
this.isShowGroup2 = !this.isShowGroup2;
});
if (this.isShowGroup2) {
ForEach(this.numbers2, (day: string) => {
GridItem() {
Text(day)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('100%')
.height(30)
.textAlign(TextAlign.Center);
};
});
}
}
.columnsTemplate('1fr')
.columnsGap(2)
.rowsGap(2)
.scrollBar(BarState.Off)
给Grid组件设置editMode为true,即Grid进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem。设置supportAnimation为true,即Grid拖拽元素时支持动画。
.supportAnimation(true)
.editMode(true) // 设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem
定义GridItem被拖拽时元素的样式,元素被拖拽时展示浮动内容。
@Builder
pixelMapBuilder() { // 拖拽过程样式
Column() {
Text('浮动内容' + this.text)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('90%')
.height(30)
.textAlign(TextAlign.Center);
};
}
判断当前移动的是不是标题,如果是标题禁止拖动。
// 判断是否是标题
isTitle(index: number) {
if (index === 0) {
return true;
}
if (!this.isShowGroup1 && index === 1) {
return true;
}
if (this.isShowGroup1 && index === this.numbers.length + 1) {
return true;
}
return false;
}
定义拖拽过程中的数组交换逻辑。
moveToIndex(index1: number, index2: number) { // 将index1位置的元素移动至 index2位置
let temp = '';
let num1Length = 1 + (this.numbers.length - 1) * Number(this.isShowGroup1);
if (index1 <= num1Length) {
temp = this.numbers.splice(index1 - 1, 1)[0];
} else {
index1 = index1 - this.numbers.length - 1;
temp = this.numbers2.splice(index1 - 1, 1)[0];
}
if (index2 <= num1Length) {
this.numbers.splice(index2 - 1, 0, temp);
} else {
index2 = index2 - this.numbers.length - 1;
this.numbers2.splice(index2 - 1, 0, temp);
}
}
给Grid组件绑定onItemDragStart和onItemDrop事件,在onItemDragStart回调中设置拖拽过程中显示的图片,并在onItemDrop中完成交换数组位置的逻辑。
.onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // 第一次拖拽此事件绑定的组件时,触发回调。
if (this.isTitle(itemIndex)) {
return;
}
if (itemIndex > this.numbers.length) {
itemIndex = itemIndex - this.numbers.length - 1;
this.text = this.numbers2[itemIndex - 1];
} else {
this.text = this.numbers[itemIndex - 1];
}
return this.pixelMapBuilder(); // 设置拖拽过程中显示的图片。
})
.onItemDrop((event: ItemDragInfo, itemIndex: number,
insertIndex: number) => { // 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。
console.info(eventX: ${event.x});
this.moveToIndex(itemIndex, insertIndex);
});
完整示例如下:
@Entry
@Component
struct GridDemo {
@State numbers: string[] = [];
@State numbers2: string[] = [];
@State isShowGroup1: boolean = true;
@State isShowGroup2: boolean = true;
@State text: string = 'drag';
scroller: Scroller = new Scroller();
@Builder
pixelMapBuilder() { // 拖拽过程样式
Column() {
Text('浮动内容' + this.text)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('90%')
.height(30)
.textAlign(TextAlign.Center);
};
}
aboutToAppear() {
for (let i = 1; i <= 15; i++) {
this.numbers.push('组' + i);
this.numbers2.push('组' + i);
}
}
moveToIndex(index1: number, index2: number) { // 将index1位置的元素移动至 index2位置
let temp = '';
let num1Length = 1 + (this.numbers.length - 1) * Number(this.isShowGroup1);
if (index1 <= num1Length) {
temp = this.numbers.splice(index1 - 1, 1)[0];
} else {
index1 = index1 - this.numbers.length - 1;
temp = this.numbers2.splice(index1 - 1, 1)[0];
}
if (index2 <= num1Length) {
this.numbers.splice(index2 - 1, 0, temp);
} else {
index2 = index2 - this.numbers.length - 1;
this.numbers2.splice(index2 - 1, 0, temp);
}
}
// 判断是否是标题
isTitle(index: number) {
if (index === 0) {
return true;
}
if (!this.isShowGroup1 && index === 1) {
return true;
}
if (this.isShowGroup1 && index === this.numbers.length + 1) {
return true;
}
return false;
}
build() {
Column({ space: 5 }) {
Column() {
Grid(this.scroller) {
GridItem() {
Text('标题' + this.numbers.length)
.fontSize(16)
.width('100%')
.height(30)
.padding({ left: 10 })
.textAlign(TextAlign.Start);
}
.onClick(() => {
this.isShowGroup1 = !this.isShowGroup1;
});
if (this.isShowGroup1) {
ForEach(this.numbers, (day: string) => {
GridItem() {
Text(day)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('100%')
.height(30)
.textAlign(TextAlign.Center);
};
});
}
GridItem() {
Text('标题' + this.numbers2.length)
.fontSize(16)
.width('100%')
.height(30)
.padding({ left: 10 })
.textAlign(TextAlign.Start);
}
.onClick(() => {
this.isShowGroup2 = !this.isShowGroup2;
});
if (this.isShowGroup2) {
ForEach(this.numbers2, (day: string) => {
GridItem() {
Text(day)
.fontSize(16)
.backgroundColor('#f1f3f5')
.width('100%')
.height(30)
.textAlign(TextAlign.Center);
};
});
}
}
.columnsTemplate('1fr')
.columnsGap(2)
.rowsGap(2)
.scrollBar(BarState.Off)
.onScrollIndex((first: number) => {
console.info(first.toString());
})
.width('90%')
.supportAnimation(true)
.editMode(true) // 设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem
.onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // 第一次拖拽此事件绑定的组件时,触发回调。
if (this.isTitle(itemIndex)) {
return;
}
if (itemIndex > this.numbers.length) {
itemIndex = itemIndex - this.numbers.length - 1;
this.text = this.numbers2[itemIndex - 1];
} else {
this.text = this.numbers[itemIndex - 1];
}
return this.pixelMapBuilder(); // 设置拖拽过程中显示的图片。
})
.onItemDrop((event: ItemDragInfo, itemIndex: number,
insertIndex: number) => { // 绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。
console.info(`eventX: ${event.x}`);
this.moveToIndex(itemIndex, insertIndex);
});
};
}.width('100%').margin({ top: 5 });
}
}
https://coub.com/view/hpeos2cjco
https://coub.com/view/7igvxlyk6k
https://coub.com/view/v3em5tf57u
https://coub.com/view/8mi8d648mw
https://coub.com/view/leakn1vzqf
https://coub.com/view/3jxmalipc1
https://coub.com/view/w6siog4nag
https://coub.com/view/k0ai6nid83
https://coub.com/view/998gorf5jb
https://coub.com/view/4y53dqndpd
https://coub.com/view/lyvdvy48ps
https://coub.com/view/0qf23iha6o
https://coub.com/view/4dgp0on1ye
https://coub.com/view/j2rrril3mg
https://coub.com/view/rw882iwkqo
https://coub.com/view/uu84w0i80u
https://coub.com/view/rpeg3vyknl
https://coub.com/view/ixfcofjfaf
https://coub.com/view/7mrjn0w5ds
https://coub.com/view/h1ygirc5b0
https://coub.com/view/zpwggrn62g
https://coub.com/view/qhs76g68gv
https://coub.com/view/46h11r7n7d
https://coub.com/view/lsk39c0i5z
https://coub.com/view/wcysvcon91
https://coub.com/view/j523euk308
https://coub.com/view/k6rm420r2l
https://coub.com/view/wmy209rg5j
https://coub.com/view/rv6l42cdkw
https://coub.com/view/22c6gs61id
https://coub.com/view/1da24s85eq
https://coub.com/view/nazf050i0g
https://coub.com/view/78aphnqocg
https://coub.com/view/5ohpazlhiz
https://coub.com/view/ezgralxchk
https://coub.com/view/2dpfvophcl
https://coub.com/view/5zapfjqyuy
https://coub.com/view/lgtduungra
https://coub.com/view/ja54xtl7sy
https://coub.com/view/yirpolzkyz
https://coub.com/view/hvpkopoavb
https://coub.com/view/f5wzrhutsh
https://coub.com/view/o4wle4i399
https://coub.com/view/sm52z4ybxe
https://coub.com/view/hwplplcqsh
https://coub.com/view/e89xnzc9db
https://coub.com/view/4udhxv4nt6
https://coub.com/view/phtyb76dod
https://coub.com/view/001y5gzuwu
https://coub.com/view/df0k59ssay
https://coub.com/view/0wyumo0qqf
https://coub.com/view/setxpegrxa
https://coub.com/view/bluey6fzje
https://coub.com/view/0hq3c9qt9v
https://coub.com/view/cmctmenb7p
https://coub.com/view/h5dvi13z6w
https://coub.com/view/001ydtfj5v
https://coub.com/view/4yt0m13wx3
https://coub.com/view/ybpq8ojuee
https://coub.com/view/xhz40awse8
https://coub.com/view/0tn5rq62ve
https://coub.com/view/ldd0wk1gvi
https://coub.com/view/jd8f5u4d5g
https://coub.com/view/adt57adxue
https://coub.com/view/5rwldp8che
https://coub.com/view/2g1ilga64d
https://coub.com/view/7bty4v8kpn
https://coub.com/view/add58pix5b
https://coub.com/view/7v4wcuvm77
https://coub.com/view/ujt2e5rx43
https://coub.com/view/txn1v1nx2q
https://coub.com/view/t9yakrks7n
https://coub.com/view/x6ruue309r
https://coub.com/view/yaufpi7tm8
https://coub.com/view/ky2r8pi3ux
https://coub.com/view/6gjzm0u6va
https://coub.com/view/0faq60gzvw
https://coub.com/view/3kydvkch96
https://coub.com/view/ouyriwirt4
https://coub.com/view/9hb1mwh3l4
https://coub.com/view/z3egmcwb8m
https://coub.com/view/5us8i1a10z
https://coub.com/view/bc0x4d9pgz
https://coub.com/view/we5cwz25vl
https://coub.com/view/4hy0ao7g1y
https://coub.com/view/1379ix4lsl
https://coub.com/view/l63at1m18m
https://coub.com/view/b3k1c4en06
https://coub.com/view/gifsv4vvpo
https://coub.com/view/3wfofokyjt
https://coub.com/view/refp6mtu17
https://coub.com/view/c379233qs0
https://coub.com/view/nnh1j6krk0
https://coub.com/view/3q3rnulo8l
https://coub.com/view/3u2jsoeo0s
https://coub.com/view/fo2nd8q9vx
https://coub.com/view/ktt1ud4lh2
https://coub.com/view/z875ct6kal
https://coub.com/view/0f21fd3rjt
https://coub.com/view/lecljlrozs
https://coub.com/view/tcztecn16r
https://coub.com/view/mddedu6140
https://coub.com/view/21wwa26yxr
https://coub.com/view/ui1n26qzsl
https://coub.com/view/xwj7lym9zx
https://coub.com/view/ispmksdf9r
https://coub.com/view/4r01so2hxv
https://coub.com/view/2tfo49pj7z
https://coub.com/view/jsw3hl36z7
https://coub.com/view/miejr0mebn
https://coub.com/view/u7ewshzk6z
https://coub.com/view/wy56dyjb3v
https://coub.com/view/w00vpcwrk5
https://coub.com/view/l2ktr59x60
https://coub.com/view/ocl6xh4krj
https://coub.com/view/liyqka3nn7
https://coub.com/view/sfjtifb133
https://coub.com/view/0bm7wbbtqs
https://coub.com/view/h8o4p4dq0f
https://coub.com/view/s510tiyxnw
https://coub.com/view/mfdmpabngf
https://coub.com/view/33p3o3di05
https://coub.com/view/ogamelniq2
https://coub.com/view/klmnjq7c0x
https://coub.com/view/l253a38fnt
https://coub.com/view/cfjpzvvy2f
https://coub.com/view/1lzc2y5xaw
https://coub.com/view/vhk304txou
https://coub.com/view/mmpnqr1qc7
https://coub.com/view/wbclu2q0c7
https://coub.com/view/rzvltna6ka
https://coub.com/view/nee6912hv3
https://coub.com/view/9e8yc406i7
https://coub.com/view/qncl1kqxjz
https://coub.com/view/uv52ht6oq6
https://coub.com/view/1uo8iwga9u
https://coub.com/view/c4vm02n6s4
https://coub.com/view/vz60m6paex
https://coub.com/view/cciyv8t9ef
https://coub.com/view/uk911bu9nl
https://coub.com/view/7m1ht4lc2j
https://coub.com/view/tyn4vfe0h8
https://coub.com/view/c8ob6w41hd
https://coub.com/view/i2al9cv5y3
https://coub.com/view/84s33yu6zr
https://coub.com/view/8ubsm8cna2
https://coub.com/view/v5vlbacn0l
https://coub.com/view/uq8oy3pbvy
0 个评论
要回复文章请先登录或注册