1 /*
2 * Copyright (c) 2022 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
16 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
17
18 #include "core/animation/spring_curve.h"
19 #include "core/components_ng/pattern/image/image_layout_property.h"
20 #include "core/components_ng/pattern/image/image_render_property.h"
21 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
22 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
23 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
24 #include "core/components_ng/pattern/navigation/title_bar_node.h"
25 #include "core/components_ng/pattern/text/text_layout_property.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27
28 namespace OHOS::Ace::NG {
29
30 namespace {
31 constexpr int32_t DEFAULT_ANIMATION_DURATION = 200;
32 constexpr int32_t TITLE_RATIO = 2;
33
MountBackButton(const RefPtr<TitleBarNode> & hostNode)34 void MountBackButton(const RefPtr<TitleBarNode>& hostNode)
35 {
36 auto titleBarLayoutProperty = hostNode->GetLayoutProperty<TitleBarLayoutProperty>();
37 CHECK_NULL_VOID(titleBarLayoutProperty);
38 auto backButtonNode = AceType::DynamicCast<FrameNode>(hostNode->GetBackButton());
39 CHECK_NULL_VOID(backButtonNode);
40 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) == TitleBarParentType::NAVBAR) {
41 auto buttonNode = backButtonNode->GetChildren().front();
42 CHECK_NULL_VOID(buttonNode);
43 auto backButtonImageNode = AceType::DynamicCast<FrameNode>(buttonNode->GetChildren().front());
44 CHECK_NULL_VOID(backButtonImageNode);
45 auto backButtonImageLayoutProperty = backButtonImageNode->GetLayoutProperty<ImageLayoutProperty>();
46 CHECK_NULL_VOID(backButtonImageLayoutProperty);
47 if (titleBarLayoutProperty->HasNoPixMap() && titleBarLayoutProperty->HasImageSource()) {
48 backButtonImageLayoutProperty->UpdateImageSourceInfo(titleBarLayoutProperty->GetImageSourceValue());
49 }
50 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetParent());
51 CHECK_NULL_VOID(navBarNode);
52 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
53 CHECK_NULL_VOID(navBarLayoutProperty);
54 auto hideBackButton = navBarLayoutProperty->GetHideBackButtonValue(false);
55 backButtonImageLayoutProperty->UpdateVisibility(hideBackButton ? VisibleType::GONE : VisibleType::VISIBLE);
56 backButtonImageNode->MarkModifyDone();
57 return;
58 }
59 if (!titleBarLayoutProperty->HasNoPixMap()) {
60 backButtonNode->MarkModifyDone();
61 return;
62 }
63 RefPtr<ImageLayoutProperty> backButtonImageLayoutProperty;
64 if (PipelineContext::GetCurrentContext() && PipelineContext::GetCurrentContext()
65 ->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
66 backButtonImageLayoutProperty = backButtonNode->GetLayoutProperty<ImageLayoutProperty>();
67 } else {
68 auto buttonNode = backButtonNode->GetChildren().front();
69 CHECK_NULL_VOID(buttonNode);
70 auto backButtonImageNode = AceType::DynamicCast<FrameNode>(buttonNode->GetChildren().front());
71 CHECK_NULL_VOID(backButtonImageNode);
72 backButtonImageLayoutProperty = backButtonImageNode->GetLayoutProperty<ImageLayoutProperty>();
73 }
74 CHECK_NULL_VOID(backButtonImageLayoutProperty);
75 if (titleBarLayoutProperty->HasImageSource()) {
76 backButtonImageLayoutProperty->UpdateImageSourceInfo(titleBarLayoutProperty->GetImageSourceValue());
77 backButtonNode->MarkModifyDone();
78 return;
79 }
80
81 if (titleBarLayoutProperty->HasPixelMap()) {
82 // TODO: use pixelMap
83 backButtonNode->MarkModifyDone();
84 return;
85 }
86 }
87
MountTitle(const RefPtr<TitleBarNode> & hostNode)88 void MountTitle(const RefPtr<TitleBarNode>& hostNode)
89 {
90 auto titleBarLayoutProperty = hostNode->GetLayoutProperty<TitleBarLayoutProperty>();
91 CHECK_NULL_VOID(titleBarLayoutProperty);
92 auto titleNode = AceType::DynamicCast<FrameNode>(hostNode->GetTitle());
93 CHECK_NULL_VOID(titleNode);
94 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetParent());
95 CHECK_NULL_VOID(navBarNode);
96 // if title node is custom node markModifyDone and return
97 if (navBarNode->GetPrevTitleIsCustomValue(false)) {
98 titleNode->MarkModifyDone();
99 return;
100 }
101
102 auto titleLayoutProperty = titleNode->GetLayoutProperty<TextLayoutProperty>();
103 CHECK_NULL_VOID(titleLayoutProperty);
104
105 auto theme = NavigationGetTheme();
106 CHECK_NULL_VOID(theme);
107 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
108 if (titleBarLayoutProperty->HasHideBackButton() && titleBarLayoutProperty->GetHideBackButtonValue()) {
109 titleLayoutProperty->UpdateFontSize(theme->GetTitleFontSize());
110 titleLayoutProperty->UpdateAdaptMaxFontSize(theme->GetTitleFontSize());
111 } else {
112 titleLayoutProperty->UpdateFontSize(theme->GetTitleFontSizeMin());
113 titleLayoutProperty->UpdateAdaptMaxFontSize(theme->GetTitleFontSizeMin());
114 }
115 titleLayoutProperty->UpdateAdaptMinFontSize(MIN_ADAPT_TITLE_FONT_SIZE);
116 titleLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
117 } else {
118 titleLayoutProperty->UpdateFontSize(theme->GetTitleFontSizeBig());
119 titleLayoutProperty->UpdateAdaptMaxFontSize(theme->GetTitleFontSizeBig());
120 }
121
122 if (hostNode->GetSubtitle()) {
123 titleLayoutProperty->UpdateMaxLines(1);
124 } else {
125 titleLayoutProperty->UpdateMaxLines(TITLEBAR_MAX_LINES);
126 }
127
128 titleNode->MarkModifyDone();
129 }
130
MountSubTitle(const RefPtr<TitleBarNode> & hostNode)131 void MountSubTitle(const RefPtr<TitleBarNode>& hostNode)
132 {
133 auto titleBarLayoutProperty = hostNode->GetLayoutProperty<TitleBarLayoutProperty>();
134 CHECK_NULL_VOID(titleBarLayoutProperty);
135 auto subtitleNode = AceType::DynamicCast<FrameNode>(hostNode->GetSubtitle());
136 CHECK_NULL_VOID(subtitleNode);
137 auto titleLayoutProperty = subtitleNode->GetLayoutProperty<TextLayoutProperty>();
138 CHECK_NULL_VOID(titleLayoutProperty);
139
140 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
141 auto theme = NavigationGetTheme();
142 CHECK_NULL_VOID(theme);
143 titleLayoutProperty->UpdateAdaptMinFontSize(MIN_ADAPT_SUBTITLE_FONT_SIZE);
144 titleLayoutProperty->UpdateAdaptMaxFontSize(theme->GetSubTitleFontSize());
145 titleLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
146 }
147
148 subtitleNode->MarkModifyDone();
149 }
150
151 } // namespace
152
OnModifyDone()153 void TitleBarPattern::OnModifyDone()
154 {
155 Pattern::OnModifyDone();
156 auto hostNode = AceType::DynamicCast<TitleBarNode>(GetHost());
157 CHECK_NULL_VOID(hostNode);
158 MountBackButton(hostNode);
159 MountTitle(hostNode);
160 MountSubTitle(hostNode);
161 }
162
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)163 void TitleBarPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
164 {
165 CHECK_NULL_VOID_NOLOG(!panEvent_);
166
167 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
168 LOGI("Pan event start");
169 auto pattern = weak.Upgrade();
170 CHECK_NULL_VOID_NOLOG(pattern);
171 if (info.GetInputEventType() == InputEventType::AXIS) {
172 return;
173 }
174 pattern->HandleDragStart(info);
175 };
176
177 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
178 auto pattern = weak.Upgrade();
179 CHECK_NULL_VOID_NOLOG(pattern);
180 if (info.GetInputEventType() == InputEventType::AXIS) {
181 return;
182 }
183 pattern->HandleDragUpdate(info);
184 };
185
186 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
187 LOGI("Pan event end mainVelocity: %{public}lf", info.GetMainVelocity());
188 auto pattern = weak.Upgrade();
189 CHECK_NULL_VOID_NOLOG(pattern);
190 if (info.GetInputEventType() == InputEventType::AXIS) {
191 return;
192 }
193 pattern->HandleDragEnd(info.GetMainVelocity());
194 };
195
196 auto actionCancelTask = [weak = WeakClaim(this)]() {
197 LOGI("Pan event cancel");
198 auto pattern = weak.Upgrade();
199 CHECK_NULL_VOID_NOLOG(pattern);
200 pattern->HandleDragEnd(0.0);
201 };
202
203 if (panEvent_) {
204 gestureHub->RemovePanEvent(panEvent_);
205 }
206
207 panEvent_ = MakeRefPtr<PanEvent>(
208 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
209 PanDirection panDirection = { .type = PanDirection::VERTICAL };
210 gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
211 }
212
HandleDragStart(const GestureEvent & info)213 void TitleBarPattern::HandleDragStart(const GestureEvent& info)
214 {
215 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
216 CHECK_NULL_VOID(titleBarNode);
217 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
218 CHECK_NULL_VOID(titleBarLayoutProperty);
219 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
220 return;
221 }
222 defaultTitleBarHeight_ = titleBarNode->GetGeometryNode()->GetFrameSize().Height();
223 SetMaxTitleBarHeight();
224 SetTempTitleBarHeight(static_cast<float>(info.GetOffsetY()));
225 minTitleOffsetY_ = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - minTitleHeight_) / 2;
226 maxTitleOffsetY_ = initialTitleOffsetY_;
227 moveRatio_ = (maxTitleOffsetY_ - minTitleOffsetY_) /
228 (maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()));
229 titleMoveDistance_ = (tempTitleBarHeight_ - defaultTitleBarHeight_) * moveRatio_;
230 defaultTitleOffsetY_ = GetTitleOffsetY();
231 SetTempTitleOffsetY();
232 defaultSubtitleOffsetY_ = GetSubTitleOffsetY();
233 SetTempSubTitleOffsetY();
234 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
235
236 // title font size
237 SetDefaultTitleFontSize();
238 auto titleBarHeightDiff = maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
239 auto titleFontSizeDiff = MAX_TITLE_FONT_SIZE - MIN_TITLE_FONT_SIZE;
240 fontSizeRatio_ = titleFontSizeDiff.Value() / titleBarHeightDiff;
241 auto tempFontSize = static_cast<float>(
242 (tempTitleBarHeight_ - defaultTitleBarHeight_) * fontSizeRatio_ + defaultTitleFontSize_.Value());
243 UpdateTitleFontSize(Dimension(tempFontSize, DimensionUnit::VP));
244
245 // subTitle Opacity
246 SetDefaultSubtitleOpacity();
247 opacityRatio_ = 1.0f / titleBarHeightDiff;
248 auto tempOpacity =
249 static_cast<float>((tempTitleBarHeight_ - defaultTitleBarHeight_) * opacityRatio_ + defaultSubtitleOpacity_);
250 UpdateSubTitleOpacity(tempOpacity);
251 }
252
HandleDragUpdate(const GestureEvent & info)253 void TitleBarPattern::HandleDragUpdate(const GestureEvent& info)
254 {
255 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
256 CHECK_NULL_VOID(titleBarNode);
257 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
258 CHECK_NULL_VOID(titleBarLayoutProperty);
259 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
260 return;
261 }
262 SetTempTitleBarHeight(static_cast<float>(info.GetOffsetY()));
263 titleMoveDistance_ = (tempTitleBarHeight_ - defaultTitleBarHeight_) * moveRatio_;
264 SetTempTitleOffsetY();
265 SetTempSubTitleOffsetY();
266 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
267
268 // title font size
269 auto tempFontSize = static_cast<float>(
270 (tempTitleBarHeight_ - defaultTitleBarHeight_) * fontSizeRatio_ + defaultTitleFontSize_.Value());
271 UpdateTitleFontSize(Dimension(tempFontSize, DimensionUnit::VP));
272
273 // subTitle Opacity
274 auto tempOpacity =
275 static_cast<float>((tempTitleBarHeight_ - defaultTitleBarHeight_) * opacityRatio_ + defaultSubtitleOpacity_);
276 UpdateSubTitleOpacity(tempOpacity);
277 }
278
HandleDragEnd(double dragVelocity)279 void TitleBarPattern::HandleDragEnd(double dragVelocity)
280 {
281 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
282 CHECK_NULL_VOID(titleBarNode);
283 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
284 CHECK_NULL_VOID(titleBarLayoutProperty);
285 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
286 return;
287 }
288 }
289
ProcessTittleDragStart(float offset)290 void TitleBarPattern::ProcessTittleDragStart(float offset)
291 {
292 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
293 CHECK_NULL_VOID(titleBarNode);
294 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
295 CHECK_NULL_VOID(titleBarLayoutProperty);
296 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
297 return;
298 }
299 if (springController_ && !springController_->IsStopped()) {
300 // clear stop listener before stop
301 springController_->ClearStopListeners();
302 springController_->Stop();
303 }
304 if (animator_ && !animator_->IsStopped()) {
305 animator_->Stop();
306 }
307
308 defaultTitleBarHeight_ = titleBarNode->GetGeometryNode()->GetFrameSize().Height();
309 SetMaxTitleBarHeight();
310 SetTempTitleBarHeight(offset);
311 minTitleOffsetY_ = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - minTitleHeight_) / 2.0f;
312 maxTitleOffsetY_ = initialTitleOffsetY_;
313 moveRatio_ = (maxTitleOffsetY_ - minTitleOffsetY_) /
314 (maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()));
315 titleMoveDistance_ = (tempTitleBarHeight_ - defaultTitleBarHeight_) * moveRatio_;
316 defaultTitleOffsetY_ = GetTitleOffsetY();
317 SetTempTitleOffsetY();
318 defaultSubtitleOffsetY_ = GetSubTitleOffsetY();
319 SetTempSubTitleOffsetY();
320 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
321
322 // title font size
323 SetDefaultTitleFontSize();
324 auto mappedOffset = GetMappedOffset(offset);
325 auto tempFontSize = GetFontSize(mappedOffset);
326 UpdateTitleFontSize(Dimension(tempFontSize, DimensionUnit::VP));
327
328 // subTitle Opacity
329 SetDefaultSubtitleOpacity();
330 auto tempOpacity = GetSubtitleOpacity();
331 UpdateSubTitleOpacity(tempOpacity);
332 }
333
ProcessTittleDragUpdate(float offset)334 void TitleBarPattern::ProcessTittleDragUpdate(float offset)
335 {
336 if (NearZero(offset)) {
337 return;
338 }
339 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
340 CHECK_NULL_VOID(titleBarNode);
341 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
342 CHECK_NULL_VOID(titleBarLayoutProperty);
343 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
344 return;
345 }
346 SetTitleStyleByOffset(offset);
347 if (CanOverDrag_) {
348 overDragOffset_ = offset + defaultTitleBarHeight_ - maxTitleBarHeight_;
349 } else {
350 overDragOffset_ = 0.0f;
351 }
352
353 if (Positive(overDragOffset_)) {
354 UpdateScaleByDragOverDragOffset(overDragOffset_);
355 } else {
356 overDragOffset_ = 0.0f;
357 }
358 }
359
SetTitleStyleByOffset(float offset)360 void TitleBarPattern::SetTitleStyleByOffset(float offset)
361 {
362 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
363 SetTempTitleBarHeight(offset);
364 titleMoveDistance_ = (tempTitleBarHeight_ - defaultTitleBarHeight_) * moveRatio_;
365 SetTempTitleOffsetY();
366 SetTempSubTitleOffsetY();
367 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
368
369 // title font size
370 auto mappedOffset = GetMappedOffset(offset);
371 auto tempFontSize = GetFontSize(mappedOffset);
372 UpdateTitleFontSize(Dimension(tempFontSize, DimensionUnit::VP));
373
374 // subTitle Opacity
375 auto tempOpacity = GetSubtitleOpacity();
376 UpdateSubTitleOpacity(tempOpacity);
377 }
378
ProcessTittleDragEnd()379 void TitleBarPattern::ProcessTittleDragEnd()
380 {
381 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
382 CHECK_NULL_VOID(titleBarNode);
383 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
384 CHECK_NULL_VOID(titleBarLayoutProperty);
385 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
386 return;
387 }
388
389 if (Positive(overDragOffset_)) {
390 SpringAnimation(overDragOffset_, 0);
391 return;
392 }
393
394 auto titleMiddleValue =
395 (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) + maxTitleBarHeight_) / TITLE_RATIO;
396 if (LessNotEqual(tempTitleBarHeight_, titleMiddleValue) || NearEqual(tempTitleBarHeight_, titleMiddleValue)) {
397 AnimateTo(static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - defaultTitleBarHeight_);
398 } else if (GreatNotEqual(tempTitleBarHeight_, titleMiddleValue)) {
399 AnimateTo(maxTitleBarHeight_ - defaultTitleBarHeight_);
400 }
401 }
402
GetSubtitleOpacity()403 float TitleBarPattern::GetSubtitleOpacity()
404 {
405 auto titleBarHeightDiff = maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
406 opacityRatio_ = 1.0f / titleBarHeightDiff;
407 auto tempOpacity = static_cast<float>(
408 (tempTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx())) * opacityRatio_ + 0.0f);
409 return tempOpacity;
410 }
411
GetFontSize(float offset)412 float TitleBarPattern::GetFontSize(float offset)
413 {
414 auto titleBarHeight = defaultTitleBarHeight_ + offset;
415 if (LessNotEqual(titleBarHeight, static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()))) {
416 titleBarHeight = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
417 }
418 if (GreatNotEqual(titleBarHeight, maxTitleBarHeight_)) {
419 titleBarHeight = maxTitleBarHeight_;
420 }
421 auto titleFontSizeDiff = MAX_TITLE_FONT_SIZE - MIN_TITLE_FONT_SIZE;
422 auto titleBarHeightDiff = maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
423 fontSizeRatio_ = titleFontSizeDiff.Value() / titleBarHeightDiff;
424 auto tempFontSize = static_cast<float>(
425 (titleBarHeight - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx())) * fontSizeRatio_ +
426 MIN_TITLE_FONT_SIZE.Value());
427 return tempFontSize;
428 }
429
GetMappedOffset(float offset)430 float TitleBarPattern::GetMappedOffset(float offset)
431 {
432 auto titleOffset = offset + defaultTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
433 auto heightDiff = maxTitleBarHeight_ - static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
434 float moveRatio = Curves::SHARP->MoveInternal(std::clamp(titleOffset / heightDiff, 0.0f, 1.0f));
435 auto mappedTitleOffset = moveRatio * heightDiff;
436 auto mappedOffset =
437 mappedTitleOffset - defaultTitleBarHeight_ + static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
438 return mappedOffset;
439 }
440
SpringAnimation(float startPos,float endPos)441 void TitleBarPattern::SpringAnimation(float startPos, float endPos)
442 {
443 float mass = 1.0f; // The move animation spring curve mass is 1.0f
444 float stiffness = 228.0f; // The move animation spring curve stiffness is 228.0f
445 float damping = 30.0f; // The move animation spring curve damping is 30.0f
446 const RefPtr<SpringProperty> DEFAULT_OVER_SPRING_PROPERTY =
447 AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping);
448 if (!springMotion_) {
449 springMotion_ = AceType::MakeRefPtr<SpringMotion>(overDragOffset_, 0, 0, DEFAULT_OVER_SPRING_PROPERTY);
450 } else {
451 springMotion_->Reset(overDragOffset_, 0, 0, DEFAULT_OVER_SPRING_PROPERTY);
452 springMotion_->ClearListeners();
453 }
454 springMotion_->AddListener([weak = AceType::WeakClaim(this)](float value) {
455 auto titlebar = weak.Upgrade();
456 CHECK_NULL_VOID(titlebar);
457 titlebar->SetOverDragOffset(value);
458 titlebar->UpdateScaleByDragOverDragOffset(value);
459 auto host = titlebar->GetHost();
460 CHECK_NULL_VOID(host);
461 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
462 });
463
464 if (!springController_) {
465 springController_ = AceType::MakeRefPtr<Animator>(PipelineBase::GetCurrentContext());
466 }
467 springController_->ClearStopListeners();
468 springController_->PlayMotion(springMotion_);
469 springController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
470 auto titlebar = weak.Upgrade();
471 CHECK_NULL_VOID(titlebar);
472 titlebar->ClearDragState();
473 auto host = titlebar->GetHost();
474 CHECK_NULL_VOID(host);
475 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
476 });
477 }
478
ClearDragState()479 void TitleBarPattern::ClearDragState()
480 {
481 overDragOffset_ = 0.0f;
482 }
483
UpdateScaleByDragOverDragOffset(float overDragOffset)484 void TitleBarPattern::UpdateScaleByDragOverDragOffset(float overDragOffset)
485 {
486 if (Negative(overDragOffset)) {
487 return;
488 }
489 auto host = GetHost();
490 auto navBarNode = AceType::DynamicCast<NavBarNode>(host->GetParent());
491 CHECK_NULL_VOID(navBarNode);
492 if (navBarNode->GetPrevTitleIsCustomValue(true)) {
493 return;
494 }
495 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
496 CHECK_NULL_VOID(navBarLayoutProperty);
497 if (navBarLayoutProperty->GetHideTitleBar().value_or(false)) {
498 return;
499 }
500
501 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
502 CHECK_NULL_VOID(titleBarNode);
503 auto titleNode = titleBarNode->GetTitle();
504 CHECK_NULL_VOID(titleNode);
505 auto title = AceType::DynamicCast<FrameNode>(titleNode);
506 TransformScale(overDragOffset, title);
507 auto subtitleNode = titleBarNode->GetSubtitle();
508 if (subtitleNode) {
509 auto subtitle = AceType::DynamicCast<FrameNode>(subtitleNode);
510 TransformScale(overDragOffset, subtitle);
511 }
512
513 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
514 }
515
TransformScale(float overDragOffset,const RefPtr<FrameNode> & frameNode)516 void TitleBarPattern::TransformScale(float overDragOffset, const RefPtr<FrameNode>& frameNode)
517 {
518 CHECK_NULL_VOID(frameNode);
519 auto renderCtx = frameNode->GetRenderContext();
520 CHECK_NULL_VOID(renderCtx);
521 auto offset = std::clamp(overDragOffset, 0.0f, static_cast<float>(MAX_OVER_DRAG_OFFSET.ConvertToPx()));
522 auto scaleRatio = offset / static_cast<float>(MAX_OVER_DRAG_OFFSET.ConvertToPx());
523 VectorF scaleValue = VectorF(scaleRatio * 0.1f + 1.0f, scaleRatio * 0.1f + 1.0f);
524 renderCtx->UpdateTransformScale(scaleValue);
525 }
526
AnimateTo(float offset)527 void TitleBarPattern::AnimateTo(float offset)
528 {
529 if (!animator_) {
530 animator_ = CREATE_ANIMATOR(PipelineBase::GetCurrentContext());
531 }
532 auto animation = AceType::MakeRefPtr<CurveAnimation<float>>(GetCurrentOffset(), offset, Curves::FAST_OUT_SLOW_IN);
533 animation->AddListener([weakScroll = AceType::WeakClaim(this)](float value) {
534 auto titlebar = weakScroll.Upgrade();
535 CHECK_NULL_VOID_NOLOG(titlebar);
536 titlebar->SetTitleStyleByOffset(value);
537 auto host = titlebar->GetHost();
538 CHECK_NULL_VOID(host);
539 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
540 auto pipeline = PipelineContext::GetCurrentContext();
541 if (pipeline) {
542 pipeline->FlushUITasks();
543 }
544 });
545 animator_->ClearInterpolators();
546 animator_->AddInterpolator(animation);
547 animator_->SetDuration(DEFAULT_ANIMATION_DURATION);
548 animator_->Play();
549 }
550
SetMaxTitleBarHeight()551 void TitleBarPattern::SetMaxTitleBarHeight()
552 {
553 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
554 CHECK_NULL_VOID(titleBarNode);
555 if (titleBarNode->GetSubtitle()) {
556 maxTitleBarHeight_ = static_cast<float>(FULL_DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
557 } else {
558 maxTitleBarHeight_ = static_cast<float>(FULL_SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
559 }
560 }
561
SetTempTitleBarHeight(float offsetY)562 void TitleBarPattern::SetTempTitleBarHeight(float offsetY)
563 {
564 tempTitleBarHeight_ = defaultTitleBarHeight_ + offsetY;
565 if (tempTitleBarHeight_ < static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx())) {
566 tempTitleBarHeight_ = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
567 }
568 if (tempTitleBarHeight_ > maxTitleBarHeight_) {
569 tempTitleBarHeight_ = maxTitleBarHeight_;
570 }
571 }
572
SetTempTitleOffsetY()573 void TitleBarPattern::SetTempTitleOffsetY()
574 {
575 tempTitleOffsetY_ = defaultTitleOffsetY_ + titleMoveDistance_;
576 if (tempTitleOffsetY_ < minTitleOffsetY_) {
577 tempTitleOffsetY_ = minTitleOffsetY_;
578 }
579 if (tempTitleOffsetY_ > maxTitleOffsetY_) {
580 tempTitleOffsetY_ = maxTitleOffsetY_;
581 }
582 }
583
SetTempSubTitleOffsetY()584 void TitleBarPattern::SetTempSubTitleOffsetY()
585 {
586 tempSubTitleOffsetY_ = tempTitleOffsetY_ + GetTitleHeight();
587 if (tempTitleOffsetY_ < minTitleOffsetY_) {
588 tempSubTitleOffsetY_ = minTitleOffsetY_;
589 }
590 if (tempTitleOffsetY_ > maxTitleOffsetY_) {
591 tempSubTitleOffsetY_ = maxTitleOffsetY_;
592 }
593 }
594
SetDefaultTitleFontSize()595 void TitleBarPattern::SetDefaultTitleFontSize()
596 {
597 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
598 CHECK_NULL_VOID(titleBarNode);
599 CHECK_NULL_VOID_NOLOG(titleBarNode->GetTitle());
600 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
601 CHECK_NULL_VOID(titleNode);
602 auto textLayoutProperty = titleNode->GetLayoutProperty<TextLayoutProperty>();
603 CHECK_NULL_VOID(textLayoutProperty);
604 if (defaultTitleBarHeight_ == maxTitleBarHeight_) {
605 defaultTitleFontSize_ = textLayoutProperty->GetFontSizeValue(MAX_TITLE_FONT_SIZE);
606 } else {
607 defaultTitleFontSize_ = textLayoutProperty->GetFontSizeValue(MIN_TITLE_FONT_SIZE);
608 }
609 }
610
SetDefaultSubtitleOpacity()611 void TitleBarPattern::SetDefaultSubtitleOpacity()
612 {
613 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
614 CHECK_NULL_VOID(titleBarNode);
615 CHECK_NULL_VOID(titleBarNode->GetSubtitle());
616 auto subtitleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
617 CHECK_NULL_VOID(subtitleNode);
618 auto context = subtitleNode->GetRenderContext();
619 CHECK_NULL_VOID(context);
620 if (defaultTitleBarHeight_ == maxTitleBarHeight_) {
621 defaultSubtitleOpacity_ = context->GetOpacityValue(1.0f);
622 } else {
623 defaultSubtitleOpacity_ = context->GetOpacityValue(0.0f);
624 }
625 }
626
GetTitleHeight()627 float TitleBarPattern::GetTitleHeight()
628 {
629 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
630 CHECK_NULL_RETURN(titleBarNode, 0.0f);
631 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
632 CHECK_NULL_RETURN(titleNode, 0.0f);
633 auto geometryNode = titleNode->GetGeometryNode();
634 CHECK_NULL_RETURN(geometryNode, 0.0f);
635 return geometryNode->GetFrameSize().Height();
636 }
637
GetTitleOffsetY()638 float TitleBarPattern::GetTitleOffsetY()
639 {
640 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
641 CHECK_NULL_RETURN(titleBarNode, 0.0f);
642 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
643 CHECK_NULL_RETURN(titleNode, 0.0f);
644 auto geometryNode = titleNode->GetGeometryNode();
645 CHECK_NULL_RETURN(geometryNode, 0.0f);
646 return geometryNode->GetMarginFrameOffset().GetY();
647 }
648
GetSubTitleHeight()649 float TitleBarPattern::GetSubTitleHeight()
650 {
651 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
652 CHECK_NULL_RETURN(titleBarNode, 0.0f);
653 auto subTitleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
654 CHECK_NULL_RETURN(subTitleNode, 0.0f);
655 auto geometryNode = subTitleNode->GetGeometryNode();
656 CHECK_NULL_RETURN(geometryNode, 0.0f);
657 return geometryNode->GetFrameSize().Height();
658 }
659
GetSubTitleOffsetY()660 float TitleBarPattern::GetSubTitleOffsetY()
661 {
662 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
663 CHECK_NULL_RETURN(titleBarNode, 0.0f);
664 auto subTitleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
665 CHECK_NULL_RETURN(subTitleNode, 0.0f);
666 auto geometryNode = subTitleNode->GetGeometryNode();
667 CHECK_NULL_RETURN(geometryNode, 0.0f);
668 return geometryNode->GetMarginFrameOffset().GetY();
669 }
670
UpdateTitleFontSize(const Dimension & tempTitleFontSize)671 void TitleBarPattern::UpdateTitleFontSize(const Dimension& tempTitleFontSize)
672 {
673 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
674 CHECK_NULL_VOID(titleBarNode);
675 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
676 CHECK_NULL_VOID(titleNode);
677 auto textLayoutProperty = titleNode->GetLayoutProperty<TextLayoutProperty>();
678 CHECK_NULL_VOID(textLayoutProperty);
679 textLayoutProperty->UpdateFontSize(tempTitleFontSize);
680 titleNode->MarkModifyDone();
681 }
682
UpdateSubTitleOpacity(const double & value)683 void TitleBarPattern::UpdateSubTitleOpacity(const double& value)
684 {
685 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
686 CHECK_NULL_VOID(titleBarNode);
687 auto subTitleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
688 CHECK_NULL_VOID(subTitleNode);
689 auto context = subTitleNode->GetRenderContext();
690 CHECK_NULL_VOID(context);
691 context->UpdateOpacity(value);
692 }
693
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)694 bool TitleBarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
695 {
696 if (config.skipMeasure && config.skipLayout) {
697 return false;
698 }
699 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
700 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
701 auto titleBarLayoutAlgorithm = DynamicCast<TitleBarLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
702 CHECK_NULL_RETURN(titleBarLayoutAlgorithm, false);
703 UpdateTitleModeChange();
704
705 initialTitleOffsetY_ = titleBarLayoutAlgorithm->GetInitialTitleOffsetY();
706 isInitialTitle_ = titleBarLayoutAlgorithm->IsInitialTitle();
707 initialSubtitleOffsetY_ = titleBarLayoutAlgorithm->GetInitialSubtitleOffsetY();
708 isInitialSubtitle_ = titleBarLayoutAlgorithm->IsInitialSubtitle();
709 minTitleHeight_ = titleBarLayoutAlgorithm->GetMinTitleHeight();
710 return true;
711 }
712
UpdateTitleModeChange()713 void TitleBarPattern::UpdateTitleModeChange()
714 {
715 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
716 CHECK_NULL_VOID(titleBarNode);
717 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
718 CHECK_NULL_VOID(titleBarLayoutProperty);
719 auto geometryNode = titleBarNode->GetGeometryNode();
720 CHECK_NULL_VOID(geometryNode);
721
722 auto titleBarHeight = geometryNode->GetFrameSize().Height();
723 if ((titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) &&
724 !NearZero(maxTitleBarHeight_)) {
725 if (titleBarHeight >= maxTitleBarHeight_) {
726 titleMode_ = NavigationTitleMode::FULL;
727 } else if (NearEqual(titleBarHeight, static_cast<float>(TITLEBAR_HEIGHT_MINI.ConvertToPx()))) {
728 titleMode_ = NavigationTitleMode::MINI;
729 }
730 }
731 }
732
OnAttachToFrameNode()733 void TitleBarPattern::OnAttachToFrameNode()
734 {
735 auto host = GetHost();
736 CHECK_NULL_VOID(host);
737 host->GetRenderContext()->SetClipToFrame(true);
738 }
739
OnColorConfigurationUpdate()740 void TitleBarPattern::OnColorConfigurationUpdate()
741 {
742 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(GetHost());
743 CHECK_NULL_VOID(titleBarNode);
744 auto backButton = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
745 CHECK_NULL_VOID(backButton);
746 if (backButton->GetTag() == "Navigator") {
747 backButton = AceType::DynamicCast<FrameNode>(backButton->GetChildren().front());
748 CHECK_NULL_VOID(backButton);
749 }
750 auto backButtonImgNode = AceType::DynamicCast<FrameNode>(backButton->GetChildren().front());
751 CHECK_NULL_VOID(backButtonImgNode);
752 auto backButtonImgRender = backButtonImgNode->GetPaintProperty<ImageRenderProperty>();
753 CHECK_NULL_VOID(backButtonImgRender);
754 auto theme = NavigationGetTheme();
755 CHECK_NULL_VOID(theme);
756 backButtonImgRender->UpdateSvgFillColor(theme->GetBackButtonIconColor());
757 backButtonImgNode->MarkModifyDone();
758 }
759 } // namespace OHOS::Ace::NG
760