• Home
Name Date Size #Lines LOC

..--

AppScope/22-Oct-2025-3532

entry/22-Oct-2025-1,5441,427

hvigor/22-Oct-2025-2322

.gitignoreD22-Oct-2025133 1212

README.mdD22-Oct-20257 KiB185154

build-profile.json5D22-Oct-20251.3 KiB5756

code-linter.json5D22-Oct-2025958 3534

hvigorfile.tsD22-Oct-2025843 225

oh-package-lock.json5D22-Oct-20251.5 KiB4241

oh-package.json5D22-Oct-2025809 2624

ohosTest.mdD22-Oct-20251.6 KiB119

README.md

1# 标题下拉缩放案例
2
3### 介绍
4
5本文以备忘录应用为示例,介绍如何在实现标题跟随手势移动并放缩的动效。
6
7### 效果图预览
8
9![](./entry/src/main/resources/base/media/expand_title.gif)
10
11**使用说明**:
12
131. 进入页面,起初标题并没有展开,与增加/分享的菜单在同一行。
142. 进行第一次下拉操作,此时标题跟随手势慢慢放大,并渐渐显示笔记数目信息。
153. 继续下拉,标题与菜单都下拉一段距离,并放大,达到阈值距离后标题大小不再发生变化;松手后回弹至第一次下拉后的状态。
164. 向上滑动,标题随手势折叠,回到初始时的状态。
17
18### 实现思路
19
201. 标题高度变化,通过状态变量heightValue控制,通过onScrollFrameBegin获取list偏移,并将其分配给标题高度变化和实际list偏移。源码参考[TitleExpansion.ets](./entry/src/main/ets/utils/TitleExpansion.ets)。
21
22   ```ts
23   List({ space: Constants.SEARCH_MEMO_SPACE, scroller: this.scroller }) {
24     ListItem() {
25       // 内容
26       this.content();
27     }
28   }
29   .onScrollFrameBegin((offset: number, state: ScrollState) => {
30     let listOffset: number = 0;
31     console.log(`offset: ${offset}`)
32     // 保证list没有在顶部时以list滑动为主
33     if (offset < 0) {
34       listOffset = Math.max(offset, -this.scroller.currentOffset().yOffset);
35       offset -= listOffset;
36     }
37     // 标题高度变化
38     let titleHeightChange = this.getTitleHeightChangeOptions(-offset);
39     this.heightValue += titleHeightChange;
40     // list滑动距离
41     offset += titleHeightChange;
42     offset += listOffset;
43     return {offsetRemain: offset};
44   })
45   ```
46
472. 标题展开继续下拉偏移,通过状态变量curOffset控制,通过onDidScroll获取标题展开后,标题继续下拉的偏移。 源码参考[TitleExpansion.ets](./entry/src/main/ets/utils/TitleExpansion.ets)。
48
49   ```ts
50   List({ space: Constants.SEARCH_MEMO_SPACE, scroller: this.scroller }) {
51     ListItem() {
52       // 内容
53       this.content();
54     }
55   }
56   // 获取标题展开后,标题继续下拉偏移
57   .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
58     this.curOffset = this.scroller.currentOffset().yOffset;
59   })
60   ```
61
623. 滚动停止动画,通过onScrollStop获取滚动停止时的标题高度。当标题高度大于阈值时,产生展开标题动画;相反,则产生收缩标题动画。源码参考[TitleExpansion.est](./entry/src/main/ets/utils/TitleExpansion.ets)
63
64```typescript
65List({ space: Constants.SEARCH_MEMO_SPACE, scroller: this.scroller }) {
66  ListItem() {
67    // 内容
68    this.content();
69  }
70}
71// TODO: 知识点: 在滚动停止时判断是否需要展开或者收缩标题
72.onScrollStop(() => {
73  if (this.heightValue >= this.thresholdValue) {
74    this.animateToThrottle(() => {
75      this.heightValue = Constants.EXPAND_TITLE_HEIGHT;
76    }, this.delay)
77  } else {
78    this.animateToThrottle(() => {
79      this.heightValue = Constants.NORMAL_TITLE_HEIGHT;
80    }, this.delay)
81  }
82})
83```
84
854. 响应状态变量,标题和菜单的tranlate和scale参数以及笔记数量的opacity参数在下拉过程中会更新。源码参考[TitleExpansion.ets](./entry/src/main/ets/utils/TitleExpansion.ets)。
86
87  ```ts
88  /**
89   * 获取标题展开时,继续下拉的菜单栏Translate参数
90   * @returns {TranslateOptions} 标题展开后继续下拉的菜单栏Translate参数
91   */
92  getMenuTranslateOptions(): TranslateOptions {
93    return { y: Math.max(-this.curOffset, 0) };
94  }
95
96  /**
97   * 获取标题展开时,继续下拉的标题栏Translate参数
98   * @returns {TranslateOptions} 标题展开后继续下拉的标题栏Translate参数
99   */
100  getTitleTranslateOptions(): TranslateOptions {
101    return {y: Math.max(-this.curOffset, 0)};
102  }
103
104  /**
105   * 获取标题栏高度变化参数
106   * @param offset: 当前产生的偏移
107   * @returns {number} 标题栏高度变化值
108   */
109  getTitleHeightChangeOptions(offset: number): number {
110    return Math.max(Math.min(offset, this.animationAttribute.expandTitleHeight - this.heightValue), this.animationAttribute.normalTitleHeight - this.heightValue);
111  }
112
113  /**
114   * 获取主标题缩放的Scale参数
115   * @returns {ScaleOptions} 主标题缩放系数
116   */
117  getTitleScaleOptions(): ScaleOptions {
118    let scaleRatio = 1 + (this.animationAttribute.titleScale - 1) *
119      Math.min((this.heightValue - this.animationAttribute.normalTitleHeight + Math.max(-this.curOffset, 0)) / this.animationAttribute.continuePullThreshold, 1);
120    return {
121      x: scaleRatio,
122      y: scaleRatio,
123      centerX: Constants.INIT_COORDINATE,
124      centerY: Constants.INIT_COORDINATE
125    };
126  }
127
128  /**
129   * 获取子标题显隐参数
130   * @returns {number} 子标题显隐系数
131   */
132  getTitleOpacityOptions(): number {
133    return (this.heightValue - this.animationAttribute.normalTitleHeight) /
134      (this.animationAttribute.expandTitleHeight - this.animationAttribute.normalTitleHeight)
135  }
136  ```
137
138### 高性能知识点
139
140本示例使用了[LazyForEach](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/application-dev/quick-start/arkts-rendering-control-lazyforeach.md)进行数据懒加载以及[显式动画animateTo](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-explicit-animation.md)实现文本偏移。
141
142### 工程结构&模块类型
143
144```
145expandtitle                                     // har类型
146|---constants
147|   |---Constants.ets                           // 常量池
148|---model
149|   |---AnimationAttribute.ets                  // 动效属性
150|   |---TitleAttribute.ets                      // 标题属性
151|---pages
152|   |---Configure.ets                           // 样例配置文件
153|   |---DataSource.ets                          // 懒加载数据源
154|   |---MemoInfo.ets                            // 数据类型
155|   |---MemoItem.ets                            // 笔记视图
156|   |---MockData.ets                            // 模拟数据
157|   |---TitleContent.ets                        // 内容界面
158|   |---Index.ets                               // 标题扩展组件UI样例
159|   |---TitleMenu.ets                           // 菜单栏
160|---utils
161|   |---TitleExpansion.ets                      // 标题扩展组件
162```
163
164### 参考资料
165
166[显式动画animateTo](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-explicit-animation.md)
167
168[数据懒加载LazyForEach](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/application-dev/quick-start/arkts-rendering-control-lazyforeach.md)
169
170### 约束与限制
171
1721.本示例仅支持在标准系统上运行。
173
1742.本示例需要使用DevEco Studio 5.0.0 Release 才可编译运行。
175
176### 下载
177
178如需单独下载本工程,执行如下命令:
179```javascript
180git init
181git config core.sparsecheckout true
182echo /code/UI/ExpandTitle/ > .git/info/sparse-checkout
183git remote add origin https://gitee.com/openharmony/applications_app_samples.git
184git pull origin master
185```