README.md
1# 标题下拉缩放案例
2
3### 介绍
4
5本文以备忘录应用为示例,介绍如何在实现标题跟随手势移动并放缩的动效。
6
7### 效果图预览
8
9
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```