1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { AppInfo } from '../model/AppInfo'; 17import { DataSource } from '../model/DateSource'; 18 19const ICON_NUM_IN_GRID: number = 15; // 示例Grid中子组件数目 20 21/** 22 * 实现Grid场景,拖拽交换子组件位置: 通过editMode()打开编辑模式、通过onItemDragStart() 23 * 指定拖拽时样式、通过onItemDrop()指定拖拽释放时的行为 24 */ 25@Component 26export struct GridSceneView { 27 @State movedItem: AppInfo = new AppInfo(); 28 @State dataSource: DataSource = new DataSource(); 29 30 aboutToAppear() { 31 for (let index = 1; index <= ICON_NUM_IN_GRID; index++) { 32 this.dataSource.pushData(new AppInfo($r(`app.media.drag_and_exchange_ic_public_app${index}`), `App${index}`)); 33 } 34 } 35 36 build() { 37 Column() { 38 Text($r('app.string.drag_and_exchange_grid_drag_title')) 39 .fontColor(Color.White) 40 .textAlign(TextAlign.Center) 41 .fontSize($r('app.string.drag_and_exchange_opt_title_font_size')) 42 Row() { 43 Grid() { 44 // TODO: 性能知识点:图标一次性完全显示,且禁用滑动,无需懒加载。LazyForEach可以适用在动态添加数据的场景中,参考资料: 45 // https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/lazyforeach_optimization.md/ 46 LazyForEach(this.dataSource, (item: AppInfo) => { 47 GridItem() { 48 IconWithNameView({ app: item }); 49 } 50 .width($r('app.string.drag_and_exchange_icon_square_size')) 51 .height($r('app.string.drag_and_exchange_layout_70')) 52 }, (item: AppInfo) => item.name.toString()) 53 } 54 .columnsTemplate('1fr 1fr 1fr 1fr 1fr') 55 .rowsTemplate('1fr 1fr 1fr') 56 .columnsGap($r('app.string.drag_and_exchange_layout_10')) 57 .rowsGap($r('app.string.drag_and_exchange_layout_10')) 58 .editMode(true) // TODO:知识点:设置Grid进入编辑模式,方可拖拽Grid组件内部GridItem 59 // TODO:知识点:在Grid层,通过onItemDragStart实现拖拽开始时的回调行为 60 .onItemDragStart((event: ItemDragInfo, itemIndex: number) => { 61 this.movedItem = this.dataSource.getData(itemIndex); 62 return this.itemWhileDrag(); //设置拖拽过程中显示的图形 63 }) 64 .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, 65 isSuccess: boolean) => { // TODO:知识点:在Grid层,通过onItemDrop实现拖拽结束后的回调行为 66 // isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生 67 if (isSuccess && insertIndex < this.dataSource.totalCount()) { 68 let temp: AppInfo = this.dataSource.getData(itemIndex); 69 this.dataSource.setData(itemIndex, this.dataSource.getData(insertIndex)); 70 this.dataSource.setData(insertIndex, temp); 71 this.dataSource.notifyDataReload(); 72 } 73 }) 74 .padding({ 75 top: $r('app.string.drag_and_exchange_layout_10'), 76 bottom: $r('app.string.drag_and_exchange_layout_10'), 77 left: $r('app.string.drag_and_exchange_layout_5'), 78 right: $r('app.string.drag_and_exchange_layout_5') 79 }) 80 } 81 .width($r('app.string.drag_and_exchange_layout_90_percent')) 82 .height($r('app.string.drag_and_exchange_layout_250')) 83 .borderRadius($r('app.string.drag_and_exchange_layout_20')) 84 .opacity($r('app.string.drag_and_exchange_background_opacity')) 85 .backgroundColor($r('app.color.drag_and_exchange_background_color')) 86 } 87 } 88 89 /** 90 * 设置GridItem拖拽过程中显示的图形 91 */ 92 @Builder 93 itemWhileDrag() { 94 IconWithNameView({ app: this.movedItem }) 95 .width($r('app.string.drag_and_exchange_icon_square_size')) 96 .height($r('app.string.drag_and_exchange_icon_square_size')) 97 } 98} 99 100/** 101 * App自定义组件 102 */ 103@Component 104struct IconWithNameView { 105 @ObjectLink app: AppInfo 106 107 build() { 108 Column() { 109 Image(this.app.icon) 110 .id(`${this.app.name}`) 111 .width($r('app.string.drag_and_exchange_icon_square_size')) 112 .height($r('app.string.drag_and_exchange_icon_square_size')) 113 .objectFit(ImageFit.Cover) 114 .borderRadius($r('app.string.drag_and_exchange_layout_10')) 115 .draggable(false) // TODO:知识点:保持默认值true时,图片有默认拖拽效果,会影响Grid子组件拖拽判断,所以修改为false 116 Text(this.app.name) 117 .width($r('app.string.drag_and_exchange_icon_square_size')) 118 .fontColor(Color.White) 119 .textAlign(TextAlign.Center) 120 .margin({ top: $r('app.string.drag_and_exchange_layout_1') }) 121 .fontSize($r('app.string.drag_and_exchange_app_name_font_size')) 122 } 123 } 124} 125