• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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