• 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_LIST: number = 4; // 示例List中子组件数目
20const LIST_SPACE: number = 30; // 列表默认间隔
21
22/**
23 * 实现List场景,拖拽交换子组件位置: 通过ListItem的onDragStart()方法指定拖拽开始时的行为,通过List的onTouch()指定拖拽释放时的行为。
24 */
25@Component
26export struct ListSceneView {
27  @State dataSource: DataSource = new DataSource();
28  @State dragIndex: number = 0;
29
30  aboutToAppear() {
31    for (let index = 0; index < ICON_NUM_IN_LIST; index++) {
32      this.dataSource.pushData(new AppInfo($r(`app.media.drag_and_exchange_ic_public_game${index + 1}`),
33        `Item${index + 1}`, true));
34    }
35  }
36
37  changeIndex(index1: number, index2: number) {
38    let temp: AppInfo = this.dataSource.getData(index1);
39    this.dataSource.setData(index1, this.dataSource.getData(index2));
40    this.dataSource.setData(index2, temp);
41  }
42
43  build() {
44    Column() {
45      Text($r('app.string.drag_and_exchange_list_drag_title'))
46        .fontColor(Color.White)
47        .textAlign(TextAlign.Center)
48        .fontSize($r('app.string.drag_and_exchange_opt_title_font_size'))
49      Row() { // 仅靠List实现背景框,padding调整样式后,互换时可能错位
50        List({ space: LIST_SPACE }) {
51          // TODO: 性能知识点:图标一次性完全显示,且禁用滑动,无需懒加载。LazyForEach可以适用在动态添加数据的场景中,参考资料:
52          //  https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/lazyforeach_optimization.md/
53          LazyForEach(this.dataSource, (item: AppInfo, index) => {
54            ListItem() {
55              Column() {
56                IconNoNameView({ app: item })
57              }
58            }
59            // TODO:知识点:在ListItem层,通过onDragStart实现拖拽开始时的回调行为
60            .onDragStart((event: DragEvent, extraParams: string) => {
61              item.visible = false; // 拖拽时,设置子组件原位置图标不可见
62              // 记录目标位置子组件index值
63              this.dragIndex = (JSON.parse(extraParams) as JsonObjType).selectedIndex;
64            })
65            .onDragEnd(() => {
66              item.visible = true;
67            })
68          }, (item: AppInfo) => item.name.toString())
69        }
70        .scrollBar(BarState.Off)
71        .height($r('app.string.drag_and_exchange_layout_90'))
72        .listDirection(Axis.Horizontal)
73        .alignListItem(ListItemAlign.Center)
74        .onDrop((event: DragEvent, extraParams: string) => { // TODO:知识点:在List层,通过onDrop实现拖拽结束后的回调行为
75          // 通过参数extraParams获取原位置子组件index值
76          let insertIndex: number = (JSON.parse(extraParams) as JsonObjType).insertIndex;
77          if (insertIndex >= this.dataSource.totalCount()) {
78            return;
79          }
80          this.changeIndex(this.dragIndex, insertIndex); // 互换子组件index值
81          this.dataSource.notifyDataReload();
82        })
83        .enableScrollInteraction(false) // 禁用滑动
84        .alignListItem(ListItemAlign.Center)
85        .padding({
86          top: $r('app.string.drag_and_exchange_layout_10'),
87          bottom: $r('app.string.drag_and_exchange_layout_10'),
88          left: $r('app.string.drag_and_exchange_layout_15'),
89          right: $r('app.string.drag_and_exchange_layout_15')
90        })
91      }
92      .justifyContent(FlexAlign.Center)
93      .height($r('app.string.drag_and_exchange_layout_90'))
94      .width($r('app.string.drag_and_exchange_layout_90_percent'))
95      .borderRadius($r('app.string.drag_and_exchange_layout_20'))
96      .opacity($r('app.string.drag_and_exchange_background_opacity'))
97      .backgroundColor($r('app.color.drag_and_exchange_background_color'))
98    }
99    .margin({ top: $r('app.string.drag_and_exchange_layout_20') })
100  }
101}
102
103/**
104 * 无名字App自定义组件
105 */
106@Component
107struct IconNoNameView {
108  @ObjectLink app: AppInfo;
109
110  build() {
111    Column() {
112      Image(this.app.icon)
113        .id(`${this.app.name}`)
114        .width($r('app.string.drag_and_exchange_icon_square_size'))
115        .height($r('app.string.drag_and_exchange_icon_square_size'))
116        .objectFit(ImageFit.Cover)
117        .borderRadius($r('app.string.drag_and_exchange_layout_10'))
118        .draggable(false) // TODO:知识点:保持默认值true时,图片有默认拖拽效果,会影响List子组件拖拽动效,所以修改为false
119      Text(this.app.name)
120        .width($r('app.string.drag_and_exchange_icon_square_size'))
121        .fontColor(Color.White)
122        .textAlign(TextAlign.Center)
123        .margin({ top: $r('app.string.drag_and_exchange_layout_1') })
124        .fontSize($r('app.string.drag_and_exchange_app_name_font_size'))
125    }
126    // 消失时需要占位,所以使用显隐控制而非条件渲染。(条件渲染与显隐控制区别,
127    // 参考资料:
128    // https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/proper-choice-between-if-and-visibility.md/129    .visibility(this.app.visible ? Visibility.Visible :
130    Visibility.Hidden)
131  }
132}
133
134/**
135 * 封装处理处理JSON对象的类
136 */
137class JsonObjType {
138  public insertIndex: number;
139  public selectedIndex: number;
140
141  constructor(insertIndex: number, selectedIndex: number) {
142    this.insertIndex = insertIndex;
143    this.selectedIndex = selectedIndex;
144  }
145}