1 /*
2 * Copyright (c) 2023 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/overlay/sheet_presentation_pattern.h"
17
18 #include "sheet_presentation_property.h"
19
20 #include "base/geometry/dimension.h"
21 #include "base/utils/utils.h"
22 #include "base/window/foldable_window.h"
23 #include "core/animation/animation_pub.h"
24 #include "core/animation/curve.h"
25 #include "core/common/container.h"
26 #include "core/components/drag_bar/drag_bar_theme.h"
27 #include "core/components_ng/event/event_hub.h"
28 #include "core/components_ng/event/gesture_event_hub.h"
29 #include "core/components_ng/pattern/image/image_pattern.h"
30 #include "core/components_ng/pattern/overlay/sheet_drag_bar_pattern.h"
31 #include "core/components_ng/pattern/overlay/sheet_style.h"
32 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
33 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
34 #include "core/components_ng/pattern/text/text_layout_property.h"
35 #include "core/components_ng/pattern/text_field/text_field_manager.h"
36 #include "core/components_ng/property/property.h"
37 #include "core/event/touch_event.h"
38 #include "core/pipeline_ng/pipeline_context.h"
39
40 namespace OHOS::Ace::NG {
41 namespace {
42 constexpr float SHEET_VISIABLE_ALPHA = 1.0f;
43 constexpr float SHEET_INVISIABLE_ALPHA = 0.0f;
44 constexpr int32_t SHEET_ENTRY_ANIMATION_DURATION = 250;
45 constexpr int32_t SHEET_EXIT_ANIMATION_DURATION = 100;
46 constexpr float SHEET_INVISIABLE_OFFSET = 8.0;
47 constexpr int32_t SHEET_HALF_HEIGHT = 2;
48 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
49 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_X = 1.5_vp;
50 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_Y = 7.32_vp;
51 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_X = 1.5_vp;
52 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_Y = 7.32_vp;
53 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
54 constexpr Dimension ARROW_RADIUS = 2.0_vp;
55 } // namespace
OnModifyDone()56 void SheetPresentationPattern::OnModifyDone()
57 {
58 auto host = GetHost();
59 CHECK_NULL_VOID(host);
60 auto renderContext = host->GetRenderContext();
61 if (renderContext) {
62 auto pipeline = PipelineContext::GetCurrentContext();
63 CHECK_NULL_VOID(pipeline);
64 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
65 CHECK_NULL_VOID(sheetTheme);
66 renderContext->UpdateBackgroundColor(sheetTheme->GetSheetBackgoundColor());
67 }
68 InitPanEvent();
69 InitPageHeight();
70 }
71
InitPageHeight()72 void SheetPresentationPattern::InitPageHeight()
73 {
74 auto context = PipelineContext::GetCurrentContext();
75 CHECK_NULL_VOID(context);
76 auto overlayManager = context->GetOverlayManager();
77 CHECK_NULL_VOID(overlayManager);
78 auto manager = context->GetSafeAreaManager();
79 CHECK_NULL_VOID(manager);
80 statusBarHeight_ = manager->GetSystemSafeArea().top_.Length();
81 auto sheetTheme = context->GetTheme<SheetTheme>();
82 CHECK_NULL_VOID(sheetTheme);
83 sheetThemeType_ = sheetTheme->GetSheetType();
84 }
85
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)86 bool SheetPresentationPattern::OnDirtyLayoutWrapperSwap(
87 const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
88 {
89 if (config.skipMeasure && config.skipLayout) {
90 return false;
91 }
92 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
93 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
94 auto sheetLayoutAlgorithm =
95 DynamicCast<SheetPresentationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
96 CHECK_NULL_RETURN(sheetLayoutAlgorithm, false);
97 InitPageHeight();
98 if (sheetLayoutAlgorithm->GetSheetMaxHeight() > 0) {
99 pageHeight_ = sheetLayoutAlgorithm->GetSheetMaxHeight();
100 sheetMaxHeight_ = sheetLayoutAlgorithm->GetSheetMaxHeight() - statusBarHeight_;
101 sheetMaxWidth_ = sheetLayoutAlgorithm->GetSheetMaxWidth();
102 centerHeight_ = sheetLayoutAlgorithm->GetCenterHeight();
103 if (!NearEqual(sheetOffsetX_, sheetLayoutAlgorithm->GetSheetOffsetX()) ||
104 !NearEqual(sheetOffsetY_, sheetLayoutAlgorithm->GetSheetOffsetY())) {
105 sheetOffsetX_ = sheetLayoutAlgorithm->GetSheetOffsetX();
106 sheetOffsetY_ = sheetLayoutAlgorithm->GetSheetOffsetY();
107 windowChanged_ = true;
108 }
109 }
110 auto sheetType = GetSheetType();
111 if ((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOMLANDSPACE)) {
112 if (windowRotate_) {
113 // When rotating the screen,
114 // first switch the sheet to the position corresponding to the proportion before rotation
115 TranslateTo(pageHeight_ - height_);
116 windowRotate_ = false;
117 } else {
118 // After rotation, if need to avoid the keyboard, trigger the avoidance behavior
119 AvoidSafeArea();
120 }
121 }
122 InitialLayoutProps();
123 UpdateDragBarStatus();
124 UpdateCloseIconStatus();
125 UpdateSheetTitle();
126 AvoidAiBar();
127 UpdateInteractive();
128 ClipSheetNode();
129 return true;
130 }
131
AvoidAiBar()132 void SheetPresentationPattern::AvoidAiBar()
133 {
134 CHECK_NULL_VOID(Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN));
135 auto host = GetHost();
136 CHECK_NULL_VOID(host);
137 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
138 CHECK_NULL_VOID(scrollNode);
139 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
140 CHECK_NULL_VOID(scrollPattern);
141 if (NonPositive(scrollPattern->GetScrollableDistance())) {
142 return;
143 }
144 auto pipeline = PipelineContext::GetCurrentContext();
145 CHECK_NULL_VOID(pipeline);
146 auto inset = pipeline->GetSafeArea();
147 auto layoutProperty = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
148 layoutProperty->UpdateScrollContentEndOffset(inset.bottom_.Length());
149 }
150
IsScrollable() const151 bool SheetPresentationPattern::IsScrollable() const
152 {
153 auto host = GetHost();
154 CHECK_NULL_RETURN(host, false);
155 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
156 CHECK_NULL_RETURN(scrollNode, false);
157 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
158 CHECK_NULL_RETURN(scrollPattern, false);
159 return Positive(scrollPattern->GetScrollableDistance());
160 }
161
OnAttachToFrameNode()162 void SheetPresentationPattern::OnAttachToFrameNode()
163 {
164 auto host = GetHost();
165 CHECK_NULL_VOID(host);
166 auto pipelineContext = PipelineContext::GetCurrentContext();
167 CHECK_NULL_VOID(pipelineContext);
168 pipelineContext->AddWindowSizeChangeCallback(host->GetId());
169 host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
170 host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
171 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetId_);
172 CHECK_NULL_VOID(targetNode);
173 pipelineContext->AddOnAreaChangeNode(targetNode->GetId());
174 OnAreaChangedFunc onAreaChangedFunc = [sheetNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
175 const OffsetF& /* oldOrigin */, const RectF& /* rect */,
176 const OffsetF& /* origin */) {
177 auto sheetNode = sheetNodeWk.Upgrade();
178 CHECK_NULL_VOID(sheetNode);
179 auto sheetPattern = sheetNode->GetPattern<SheetPresentationPattern>();
180 CHECK_NULL_VOID(sheetPattern);
181 if (sheetPattern->GetSheetType() == SheetType::SHEET_POPUP) {
182 sheetNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
183 }
184 };
185 targetNode->SetOnAreaChangeCallback(std::move(onAreaChangedFunc));
186 }
187
OnDetachFromFrameNode(FrameNode * frameNode)188 void SheetPresentationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
189 {
190 auto pipeline = PipelineContext::GetCurrentContext();
191 CHECK_NULL_VOID(pipeline);
192 pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
193 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetId_);
194 CHECK_NULL_VOID(targetNode);
195 pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
196 }
197
198 // initial drag gesture event
InitPanEvent()199 void SheetPresentationPattern::InitPanEvent()
200 {
201 auto host = GetHost();
202 CHECK_NULL_VOID(host);
203
204 auto hub = host->GetEventHub<EventHub>();
205 CHECK_NULL_VOID(hub);
206 auto gestureHub = hub->GetOrCreateGestureEventHub();
207 CHECK_NULL_VOID(gestureHub);
208 if (panEvent_) {
209 return;
210 }
211
212 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
213 auto pattern = weak.Upgrade();
214 if (pattern) {
215 pattern->HandleDragStart();
216 }
217 };
218
219 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
220 auto pattern = weak.Upgrade();
221 if (pattern) {
222 pattern->HandleDragUpdate(info);
223 }
224 };
225
226 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
227 auto pattern = weak.Upgrade();
228 if (pattern) {
229 pattern->HandleDragEnd(info.GetMainVelocity());
230 }
231 };
232 auto actionCancelTask = [weak = WeakClaim(this)]() {
233 auto pattern = weak.Upgrade();
234 if (pattern) {
235 pattern->HandleDragEnd({});
236 }
237 };
238 PanDirection panDirection;
239 panDirection.type = PanDirection::VERTICAL;
240 panEvent_ = MakeRefPtr<PanEvent>(
241 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
242 gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
243 }
244
HandleDragStart()245 void SheetPresentationPattern::HandleDragStart()
246 {
247 if (animation_ && isAnimationProcess_) {
248 AnimationUtils::StopAnimation(animation_);
249 isAnimationBreak_ = true;
250 }
251 currentOffset_ = 0.0f;
252 }
253
HandleDragUpdate(const GestureEvent & info)254 void SheetPresentationPattern::HandleDragUpdate(const GestureEvent& info)
255 {
256 auto sheetType = GetSheetType();
257 if (sheetType == SheetType::SHEET_POPUP) {
258 return;
259 }
260 auto mainDelta = static_cast<float>(info.GetMainDelta());
261 auto host = GetHost();
262 CHECK_NULL_VOID(host);
263 auto tempOffset = currentOffset_;
264 auto detentSize = sheetDetentHeight_.size();
265 if (detentSize <= 0) {
266 return;
267 }
268 auto maxDetentSize = sheetDetentHeight_[detentSize - 1];
269 if (GreatNotEqual((height_ - currentOffset_), maxDetentSize)) {
270 if (LessNotEqual(mainDelta, 0)) {
271 auto friction = CalculateFriction((height_ - currentOffset_) / sheetMaxHeight_);
272 mainDelta = mainDelta * friction;
273 }
274 }
275 currentOffset_ = currentOffset_ + mainDelta;
276 if (NearEqual(currentOffset_, tempOffset)) {
277 return;
278 }
279 auto offset = pageHeight_ - height_ + currentOffset_;
280 if (LessOrEqual(offset, (pageHeight_ - sheetMaxHeight_))) {
281 offset = pageHeight_ - sheetMaxHeight_;
282 currentOffset_ = height_ - sheetMaxHeight_;
283 }
284 ProcessColumnRect(height_ - currentOffset_);
285 auto renderContext = host->GetRenderContext();
286 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
287 }
288
HandleDragEnd(float dragVelocity)289 void SheetPresentationPattern::HandleDragEnd(float dragVelocity)
290 {
291 auto sheetDetentsSize = sheetDetentHeight_.size();
292 if ((sheetDetentsSize == 0) || (GetSheetType() == SheetType::SHEET_POPUP)) {
293 return;
294 }
295 float upHeight = 0.0f;
296 float downHeight = 0.0f;
297 auto currentSheetHeight =
298 GreatNotEqual((height_ - currentOffset_), sheetMaxHeight_) ? sheetMaxHeight_ : (height_ - currentOffset_);
299 auto lowerIter = std::lower_bound(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), currentSheetHeight);
300 auto upperIter = std::upper_bound(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), currentSheetHeight);
301 if (lowerIter == sheetDetentHeight_.end()) {
302 upHeight = sheetDetentHeight_[sheetDetentsSize - 1];
303 downHeight = sheetDetentHeight_[sheetDetentsSize - 1];
304 } else {
305 auto lowerPosition = std::distance(sheetDetentHeight_.begin(), lowerIter);
306 auto upperPosition = std::distance(sheetDetentHeight_.begin(), upperIter);
307 if (lowerPosition == 0) {
308 upHeight = sheetDetentHeight_[lowerPosition];
309 downHeight = 0;
310 } else {
311 upHeight = sheetDetentHeight_[upperPosition];
312 downHeight = sheetDetentHeight_[lowerPosition - 1];
313 }
314 }
315 // current sheet animation
316 if ((LessNotEqual(std::abs(dragVelocity), SHEET_VELOCITY_THRESHOLD)) &&
317 (!NearEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight)))) {
318 if (GreatNotEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight))) {
319 if (NearZero(downHeight)) {
320 SheetInteractiveDismiss(true, std::abs(dragVelocity));
321 } else {
322 ChangeSheetHeight(downHeight);
323 ChangeScrollHeight(height_);
324 SheetTransition(true, std::abs(dragVelocity));
325 }
326 } else if (LessNotEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight))) {
327 ChangeSheetHeight(upHeight);
328 ChangeScrollHeight(height_);
329 ProcessColumnRect(height_);
330 SheetTransition(true, std::abs(dragVelocity));
331 }
332 } else {
333 if (GreatOrEqual(dragVelocity, 0.0f)) {
334 if (NearZero(downHeight)) {
335 SheetInteractiveDismiss(true, std::abs(dragVelocity));
336 } else {
337 ChangeSheetHeight(downHeight);
338 ChangeScrollHeight(height_);
339 SheetTransition(true, std::abs(dragVelocity));
340 }
341 } else {
342 ChangeSheetHeight(upHeight);
343 if (!NearEqual(upHeight, downHeight)) {
344 ChangeScrollHeight(height_);
345 ProcessColumnRect(height_);
346 }
347 SheetTransition(true, std::abs(dragVelocity));
348 }
349 }
350 }
351
OnCoordScrollStart()352 void SheetPresentationPattern::OnCoordScrollStart()
353 {
354 if (animation_ && isAnimationProcess_) {
355 AnimationUtils::StopAnimation(animation_);
356 isAnimationBreak_ = true;
357 }
358 currentOffset_ = 0.0f;
359 }
360
OnCoordScrollUpdate(float scrollOffset)361 bool SheetPresentationPattern::OnCoordScrollUpdate(float scrollOffset)
362 {
363 if (!GetShowState() || !IsScrollable()) {
364 return false;
365 }
366
367 auto sheetType = GetSheetType();
368 auto sheetDetentsSize = sheetDetentHeight_.size();
369 if ((sheetType == SheetType::SHEET_POPUP) || (sheetDetentsSize == 0)) {
370 return false;
371 }
372
373 if ((NearZero(currentOffset_)) && (LessNotEqual(scrollOffset, 0.0f)) &&
374 (GreatOrEqual(height_, sheetDetentHeight_[sheetDetentsSize - 1]))) {
375 return false;
376 }
377 auto host = GetHost();
378 CHECK_NULL_RETURN(host, false);
379 currentOffset_ = currentOffset_ + scrollOffset;
380 auto offset = pageHeight_ - height_ + currentOffset_;
381 if (offset <= (pageHeight_ - sheetMaxHeight_)) {
382 offset = pageHeight_ - sheetMaxHeight_;
383 currentOffset_ = height_ - sheetMaxHeight_;
384 }
385 ProcessColumnRect(height_ - currentOffset_);
386 auto renderContext = host->GetRenderContext();
387 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
388 return true;
389 }
390
OnCoordScrollEnd(float dragVelocity)391 void SheetPresentationPattern::OnCoordScrollEnd(float dragVelocity)
392 {
393 HandleDragEnd(dragVelocity);
394 }
InitialLayoutProps()395 void SheetPresentationPattern::InitialLayoutProps()
396 {
397 CheckSheetHeightChange();
398 InitSheetDetents();
399 }
400
InitialSingleGearHeight(NG::SheetStyle & sheetStyle)401 float SheetPresentationPattern::InitialSingleGearHeight(NG::SheetStyle& sheetStyle)
402 {
403 auto largeHeight = sheetMaxHeight_ - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
404 float sheetHeight = largeHeight;
405 auto sheetNode = GetHost();
406 CHECK_NULL_RETURN(sheetNode, sheetHeight);
407 if (sheetStyle.sheetMode.has_value()) {
408 if (sheetStyle.sheetMode == SheetMode::MEDIUM) {
409 sheetHeight = pageHeight_ * MEDIUM_SIZE;
410 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
411 sheetHeight = pageHeight_ * MEDIUM_SIZE_PRE;
412 }
413 } else if (sheetStyle.sheetMode == SheetMode::LARGE) {
414 sheetHeight = largeHeight;
415 } else if (sheetStyle.sheetMode == SheetMode::AUTO) {
416 sheetHeight = GetFitContentHeight();
417 if (sheetHeight > largeHeight) {
418 sheetHeight = largeHeight;
419 }
420 HandleFitContontChange(sheetHeight);
421 }
422 } else {
423 float height = 0.0f;
424 if (sheetStyle.height->Unit() == DimensionUnit::PERCENT) {
425 height = sheetStyle.height->ConvertToPxWithSize(sheetMaxHeight_);
426 } else {
427 height = sheetStyle.height->ConvertToPx();
428 }
429 if (GreatNotEqual(height, largeHeight)) {
430 sheetHeight = largeHeight;
431 } else if (LessNotEqual(height, 0)) {
432 sheetHeight = largeHeight;
433 } else {
434 sheetHeight = height;
435 }
436 }
437 return sheetHeight;
438 }
439
AvoidSafeArea()440 void SheetPresentationPattern::AvoidSafeArea()
441 {
442 auto host = GetHost();
443 CHECK_NULL_VOID(host);
444 auto pipelineContext = PipelineContext::GetCurrentContext();
445 CHECK_NULL_VOID(pipelineContext);
446 auto manager = pipelineContext->GetSafeAreaManager();
447 if (keyboardHeight_ == manager->GetKeyboardInset().Length()) {
448 return;
449 }
450 keyboardHeight_ = manager->GetKeyboardInset().Length();
451 CHECK_NULL_VOID(host->GetFocusHub()->IsCurrentFocus());
452 auto heightUp = GetSheetHeightChange();
453 auto offset = pageHeight_ - height_ - heightUp;
454 auto renderContext = host->GetRenderContext();
455 if (isScrolling_) {
456 // if scrolling and keyboard will down, scroll needs to reset.
457 if (NearZero(heightUp)) {
458 ScrollTo(-scrollHeight_);
459 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
460 } else {
461 // Otherwise, sheet is necessary to raise and trigger scroll scrolling
462 // sheet is raised to the top first
463 renderContext->UpdateTransformTranslate(
464 { 0.0f, pageHeight_ - sheetHeight_ + SHEET_BLANK_MINI_HEIGHT.ConvertToPx() + statusBarHeight_, 0.0f });
465 // Then adjust the remaining height(heightUp = h - maxH) difference by scrolling
466 ScrollTo(heightUp);
467 }
468 } else {
469 // offset: translate endpoint, calculated from top
470 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
471 }
472 }
473
GetSheetHeightChange()474 float SheetPresentationPattern::GetSheetHeightChange()
475 {
476 auto pipelineContext = PipelineContext::GetCurrentContext();
477 CHECK_NULL_RETURN(pipelineContext, .0f);
478 auto manager = pipelineContext->GetSafeAreaManager();
479 auto keyboardInsert = manager->GetKeyboardInset();
480 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipelineContext->GetTextFieldManager());
481 // inputH : Distance from input component's Caret to bottom of screen
482 // = caret's offset + caret's height + 24vp
483 auto inputH = textFieldManager ? (pipelineContext->GetRootHeight() - textFieldManager->GetClickPosition().GetY() -
484 textFieldManager->GetHeight())
485 : .0;
486 // keyboardH : keyboard height + height of the bottom navigation bar
487 auto keyboardH = keyboardInsert.Length() + manager->GetSystemSafeArea().bottom_.Length();
488 // The minimum height of the input component from the bottom of the screen after popping up the soft keyboard
489 auto inputMinH = keyboardH;
490 // maxH : height that the sheet can reach the stage = the LARGE sheet - Current sheet height
491 auto sheetHeight = GetHost()->GetGeometryNode()->GetFrameSize().Height();
492 auto largeHeight = sheetHeight - SHEET_BLANK_MINI_HEIGHT.ConvertToPx() - statusBarHeight_;
493 auto maxH = largeHeight - height_;
494 if (inputH >= inputMinH) {
495 // sheet needs not up
496 return .0f;
497 }
498 // The expected height of the sheet to be lifted
499 auto h = inputMinH - inputH;
500 if (h <= maxH) {
501 // sheet is lifted up with h
502 return h;
503 }
504 // h > maxH, sheet goes up to the LARGE, then adjust the remaining height(h - maxH) difference by scrolling
505 isScrolling_ = true;
506 return h - maxH;
507 }
508
SheetTransition(bool isTransitionIn,float dragVelocity)509 void SheetPresentationPattern::SheetTransition(bool isTransitionIn, float dragVelocity)
510 {
511 auto host = GetHost();
512 CHECK_NULL_VOID(host);
513 auto context = host->GetRenderContext();
514 CHECK_NULL_VOID(context);
515 AnimationOption option;
516 const RefPtr<InterpolatingSpring> curve = AceType::MakeRefPtr<InterpolatingSpring>(
517 dragVelocity / SHEET_VELOCITY_THRESHOLD, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
518 option.SetCurve(curve);
519 option.SetFillMode(FillMode::FORWARDS);
520 auto offset = pageHeight_ - height_;
521 if (!isTransitionIn) {
522 auto pipelineContext = PipelineContext::GetCurrentContext();
523 CHECK_NULL_VOID(pipelineContext);
524 auto overlayManager = pipelineContext->GetOverlayManager();
525 CHECK_NULL_VOID(overlayManager);
526 auto maskNode = overlayManager->GetSheetMask(host);
527 if (maskNode) {
528 overlayManager->PlaySheetMaskTransition(maskNode, false);
529 }
530 }
531 option.SetOnFinishEvent([weak = AceType::WeakClaim(this), isTransitionIn]() {
532 auto pattern = weak.Upgrade();
533 CHECK_NULL_VOID(pattern);
534 if (isTransitionIn) {
535 if (!pattern->GetAnimationBreak()) {
536 pattern->SetCurrentOffset(0.0f);
537 pattern->ProcessColumnRect(pattern->height_);
538 pattern->ChangeScrollHeight(pattern->height_);
539 pattern->SetAnimationProcess(false);
540 } else {
541 pattern->isAnimationBreak_ = false;
542 }
543 } else {
544 pattern->SetAnimationProcess(false);
545 auto context = PipelineContext::GetCurrentContext();
546 CHECK_NULL_VOID(context);
547 auto overlayManager = context->GetOverlayManager();
548 CHECK_NULL_VOID(overlayManager);
549 auto host = pattern->GetHost();
550 CHECK_NULL_VOID(host);
551 overlayManager->DestroySheet(host, pattern->GetTargetId());
552 pattern->FireCallback("false");
553 }
554 });
555 StartSheetTransitionAnimation(option, isTransitionIn, offset);
556 }
557
SheetInteractiveDismiss(bool isDragClose,float dragVelocity)558 void SheetPresentationPattern::SheetInteractiveDismiss(bool isDragClose, float dragVelocity)
559 {
560 if (hasShouldDismiss()) {
561 auto pipeline = PipelineContext::GetCurrentContext();
562 CHECK_NULL_VOID(pipeline);
563 auto overlayManager = pipeline->GetOverlayManager();
564 CHECK_NULL_VOID(overlayManager);
565 overlayManager->SetDismissTargetId(targetId_);
566 if (isDragClose) {
567 ProcessColumnRect(height_);
568 SheetTransition(true);
569 }
570 CallShouldDismiss();
571 } else {
572 DismissTransition(false, dragVelocity);
573 }
574 }
575
DismissTransition(bool isTransitionIn,float dragVelocity)576 void SheetPresentationPattern::DismissTransition(bool isTransitionIn, float dragVelocity)
577 {
578 auto pipeline = PipelineContext::GetCurrentContext();
579 CHECK_NULL_VOID(pipeline);
580 auto overlayManager = pipeline->GetOverlayManager();
581 CHECK_NULL_VOID(overlayManager);
582 overlayManager->ModalPageLostFocus(GetHost());
583
584 auto sheetType = GetSheetType();
585 if (sheetType == SheetType::SHEET_POPUP) {
586 BubbleStyleSheetTransition(isTransitionIn);
587 } else {
588 SheetTransition(isTransitionIn, dragVelocity);
589 }
590 }
591
ChangeScrollHeight(float height)592 void SheetPresentationPattern::ChangeScrollHeight(float height)
593 {
594 auto host = GetHost();
595 CHECK_NULL_VOID(host);
596 auto geometryNode = host->GetGeometryNode();
597 CHECK_NULL_VOID(geometryNode);
598 auto operationNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
599 CHECK_NULL_VOID(operationNode);
600 auto perationGeometryNode = operationNode->GetGeometryNode();
601 CHECK_NULL_VOID(perationGeometryNode);
602 auto operationHeight = perationGeometryNode->GetFrameSize().Height();
603 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
604 CHECK_NULL_VOID(scrollNode);
605 auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
606 CHECK_NULL_VOID(scrollProps);
607 auto scrollHeight = height - operationHeight;
608 auto sheetType = GetSheetType();
609 if ((sheetType == SheetType::SHEET_POPUP) || (sheetType == SheetType::SHEET_CENTER)) {
610 auto sheetHeight = geometryNode->GetFrameSize().Height();
611 scrollHeight = sheetHeight - operationHeight;
612 }
613 scrollProps->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(scrollHeight)));
614 scrollNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
615 }
616
UpdateDragBarStatus()617 void SheetPresentationPattern::UpdateDragBarStatus()
618 {
619 auto host = GetHost();
620 CHECK_NULL_VOID(host);
621 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
622 CHECK_NULL_VOID(layoutProperty);
623 auto sheetStyle = layoutProperty->GetSheetStyleValue();
624 auto showDragIndicator = sheetStyle.showDragBar.value_or(true);
625
626 auto titleColumn = DynamicCast<FrameNode>(host->GetFirstChild());
627 CHECK_NULL_VOID(titleColumn);
628 auto sheetDragBar = DynamicCast<FrameNode>(titleColumn->GetFirstChild());
629 CHECK_NULL_VOID(sheetDragBar);
630 auto dragBarLayoutProperty = sheetDragBar->GetLayoutProperty();
631 CHECK_NULL_VOID(dragBarLayoutProperty);
632 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
633 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::GONE);
634 sheetDragBar->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
635 return;
636 }
637 auto sheetType = GetSheetType();
638 if (((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOM_FREE_WINDOW)) &&
639 (sheetDetentHeight_.size() > 1)) {
640 if (sheetStyle.isTitleBuilder.has_value()) {
641 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
642 } else {
643 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::GONE);
644 }
645 } else {
646 if (sheetStyle.isTitleBuilder.has_value()) {
647 dragBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
648 } else {
649 dragBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
650 }
651 }
652 sheetDragBar->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
653 }
654
UpdateCloseIconStatus()655 void SheetPresentationPattern::UpdateCloseIconStatus()
656 {
657 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
658 return;
659 }
660 auto host = GetHost();
661 CHECK_NULL_VOID(host);
662 auto pipeline = PipelineContext::GetCurrentContext();
663 CHECK_NULL_VOID(pipeline);
664 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
665 CHECK_NULL_VOID(sheetTheme);
666 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
667 CHECK_NULL_VOID(layoutProperty);
668 auto sheetStyle = layoutProperty->GetSheetStyleValue();
669 auto showCloseIcon = layoutProperty->GetSheetStyleValue().showCloseIcon.value_or(true);
670 auto sheetCloseIcon = DynamicCast<FrameNode>(host->GetChildAtIndex(2));
671 CHECK_NULL_VOID(sheetCloseIcon);
672 auto geometryNode = host->GetGeometryNode();
673 CHECK_NULL_VOID(geometryNode);
674 auto size = geometryNode->GetFrameSize();
675 auto closeIconX = size.Width() - static_cast<float>(SHEET_CLOSE_ICON_WIDTH.ConvertToPx()) -
676 static_cast<float>(sheetTheme->GetTitleTextMargin().ConvertToPx());
677 auto closeIconY = static_cast<float>(sheetTheme->GetTitleTextMargin().ConvertToPx());
678 OffsetT<Dimension> positionOffset;
679 positionOffset.SetX(Dimension(closeIconX));
680 auto sheetType = GetSheetType();
681 if (sheetType == SheetType::SHEET_POPUP) {
682 positionOffset.SetY(Dimension(closeIconY) + SHEET_ARROW_HEIGHT);
683 } else {
684 positionOffset.SetY(Dimension(closeIconY));
685 }
686 auto renderContext = sheetCloseIcon->GetRenderContext();
687 CHECK_NULL_VOID(renderContext);
688 renderContext->UpdatePosition(positionOffset);
689 auto iconLayoutProperty = sheetCloseIcon->GetLayoutProperty();
690 CHECK_NULL_VOID(iconLayoutProperty);
691 iconLayoutProperty->UpdateVisibility(showCloseIcon ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
692 sheetCloseIcon->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
693 }
694
UpdateSheetTitle()695 void SheetPresentationPattern::UpdateSheetTitle()
696 {
697 auto host = GetHost();
698 CHECK_NULL_VOID(host);
699 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
700 CHECK_NULL_VOID(layoutProperty);
701 auto sheetStyle = layoutProperty->GetSheetStyleValue();
702 if (sheetStyle.sheetTitle.has_value()) {
703 auto titleId = GetTitleId();
704 auto titleNode = DynamicCast<FrameNode>(ElementRegister::GetInstance()->GetNodeById(titleId));
705 CHECK_NULL_VOID(titleNode);
706 auto titleProp = titleNode->GetLayoutProperty<TextLayoutProperty>();
707 CHECK_NULL_VOID(titleProp);
708 titleProp->UpdateContent(sheetStyle.sheetTitle.value());
709 titleNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
710 if (sheetStyle.sheetSubtitle.has_value()) {
711 auto subtitleId = GetSubtitleId();
712 auto subtitleNode = DynamicCast<FrameNode>(ElementRegister::GetInstance()->GetNodeById(subtitleId));
713 CHECK_NULL_VOID(subtitleNode);
714 auto subtitleProp = subtitleNode->GetLayoutProperty<TextLayoutProperty>();
715 CHECK_NULL_VOID(subtitleProp);
716 subtitleProp->UpdateContent(sheetStyle.sheetSubtitle.value());
717 subtitleNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
718 }
719 }
720 }
721
UpdateInteractive()722 void SheetPresentationPattern::UpdateInteractive()
723 {
724 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
725 return;
726 }
727 auto host = GetHost();
728 CHECK_NULL_VOID(host);
729 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
730 CHECK_NULL_VOID(layoutProperty);
731 auto sheetStyle = layoutProperty->GetSheetStyleValue();
732 auto pipelineContext = PipelineContext::GetCurrentContext();
733 CHECK_NULL_VOID(pipelineContext);
734 auto overlayManager = pipelineContext->GetOverlayManager();
735 CHECK_NULL_VOID(overlayManager);
736 auto maskNode = overlayManager->GetSheetMask(host);
737 CHECK_NULL_VOID(maskNode);
738 if (!sheetStyle.interactive.has_value()) {
739 if (GetSheetType() == SheetType::SHEET_POPUP) {
740 maskNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
741 } else {
742 maskNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
743 }
744 } else {
745 if (sheetStyle.interactive == true) {
746 maskNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
747 } else {
748 maskNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
749 }
750 }
751 maskNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
752 }
753
OnColorConfigurationUpdate()754 void SheetPresentationPattern::OnColorConfigurationUpdate()
755 {
756 auto host = GetHost();
757 CHECK_NULL_VOID(host);
758 auto pipeline = PipelineContext::GetCurrentContext();
759 CHECK_NULL_VOID(pipeline);
760 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
761 CHECK_NULL_VOID(sheetTheme);
762 auto sheetCloseIcon = DynamicCast<FrameNode>(host->GetChildAtIndex(2));
763 CHECK_NULL_VOID(sheetCloseIcon);
764 auto renderContext = sheetCloseIcon->GetRenderContext();
765 CHECK_NULL_VOID(renderContext);
766 renderContext->UpdateBackgroundColor(sheetTheme->GetCloseIconColor());
767 sheetCloseIcon->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
768 auto imageNode = DynamicCast<FrameNode>(sheetCloseIcon->GetChildAtIndex(0));
769 CHECK_NULL_VOID(imageNode);
770 auto imagePaintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
771 CHECK_NULL_VOID(imagePaintProperty);
772 imagePaintProperty->UpdateSvgFillColor(sheetTheme->GetCloseIconImageColor());
773 imageNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
774 }
775
CheckSheetHeightChange()776 void SheetPresentationPattern::CheckSheetHeightChange()
777 {
778 auto host = GetHost();
779 CHECK_NULL_VOID(host);
780 auto sheetGeometryNode = host->GetGeometryNode();
781 CHECK_NULL_VOID(sheetGeometryNode);
782 if (isFirstInit_) {
783 sheetHeight_ = sheetGeometryNode->GetFrameSize().Height();
784 sheetType_ = GetSheetType();
785 isFirstInit_ = false;
786 } else {
787 if ((!NearEqual(sheetGeometryNode->GetFrameSize().Height(), sheetHeight_)) || (sheetType_ != GetSheetType()) ||
788 windowChanged_) {
789 sheetType_ = GetSheetType();
790 sheetHeight_ = sheetGeometryNode->GetFrameSize().Height();
791 auto pipelineContext = PipelineContext::GetCurrentContext();
792 CHECK_NULL_VOID(pipelineContext);
793 auto overlayManager = pipelineContext->GetOverlayManager();
794 CHECK_NULL_VOID(overlayManager);
795 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
796 CHECK_NULL_VOID(layoutProperty);
797 auto sheetStyle = layoutProperty->GetSheetStyleValue();
798 overlayManager->ComputeSheetOffset(sheetStyle, host);
799 if (sheetType_ == SheetType::SHEET_POPUP) {
800 auto renderContext = GetRenderContext();
801 CHECK_NULL_VOID(renderContext);
802 renderContext->OnTransformTranslateUpdate({ 0.0f, Dimension(sheetOffsetY_), 0.0f });
803 renderContext->UpdateOpacity(SHEET_VISIABLE_ALPHA);
804 }
805 overlayManager->PlaySheetTransition(host, true, false, true);
806 windowChanged_ = false;
807 }
808 }
809 }
810
InitSheetDetents()811 void SheetPresentationPattern::InitSheetDetents()
812 {
813 sheetDetentHeight_.clear();
814 float height = 0.0f;
815 auto sheetNode = GetHost();
816 CHECK_NULL_VOID(sheetNode);
817 auto geometryNode = sheetNode->GetGeometryNode();
818 CHECK_NULL_VOID(geometryNode);
819 auto largeHeight = sheetMaxHeight_ - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
820 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
821 CHECK_NULL_VOID(layoutProperty);
822 auto sheetStyle = layoutProperty->GetSheetStyleValue();
823 auto sheetType = GetSheetType();
824 auto sheetFrameHeight = geometryNode->GetFrameSize().Height();
825 auto mediumSize = MEDIUM_SIZE;
826 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
827 mediumSize = MEDIUM_SIZE_PRE;
828 }
829 switch (sheetType) {
830 case SheetType::SHEET_BOTTOM:
831 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
832 if (sheetStyle.detents.size() <= 0) {
833 height = InitialSingleGearHeight(sheetStyle);
834 sheetDetentHeight_.emplace_back(height);
835 break;
836 }
837 for (auto iter : sheetStyle.detents) {
838 if (iter.sheetMode.has_value()) {
839 if (iter.sheetMode == SheetMode::MEDIUM) {
840 height = pageHeight_ * mediumSize;
841 } else if (iter.sheetMode == SheetMode::LARGE) {
842 height = largeHeight;
843 } else if (iter.sheetMode == SheetMode::AUTO) {
844 height = GetFitContentHeight();
845 height = GreatNotEqual(height, largeHeight) ? largeHeight : height;
846 HandleFitContontChange(height);
847 }
848 } else {
849 if (iter.height->Unit() == DimensionUnit::PERCENT) {
850 height = iter.height->ConvertToPxWithSize(sheetMaxHeight_);
851 } else {
852 height = iter.height->ConvertToPx();
853 }
854 if (GreatNotEqual(height, largeHeight)) {
855 height = largeHeight;
856 } else if (LessNotEqual(height, 0)) {
857 height = largeHeight;
858 }
859 }
860 sheetDetentHeight_.emplace_back(height);
861 }
862 std::sort(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), std::less<float>());
863 sheetDetentHeight_.erase(std::unique(sheetDetentHeight_.begin(), sheetDetentHeight_.end()),
864 sheetDetentHeight_.end());
865 break;
866 case SheetType::SHEET_BOTTOMLANDSPACE:
867 height = sheetFrameHeight - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
868 sheetDetentHeight_.emplace_back(height);
869 break;
870 case SheetType::SHEET_CENTER:
871 height = (centerHeight_ + pageHeight_) / SHEET_HALF_HEIGHT;
872 sheetDetentHeight_.emplace_back(height);
873 break;
874 default:
875 break;
876 }
877 }
878
HandleFitContontChange(float height)879 void SheetPresentationPattern::HandleFitContontChange(float height)
880 {
881 if ((NearEqual(height_, sheetFitContentHeight_)) && (!NearEqual(height, sheetFitContentHeight_))) {
882 ChangeSheetHeight(height);
883 ProcessColumnRect(height_);
884 ChangeScrollHeight(height_);
885 SheetTransition(true);
886 }
887 sheetFitContentHeight_ = height;
888 }
889
GetSheetType()890 SheetType SheetPresentationPattern::GetSheetType()
891 {
892 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
893 return SHEET_BOTTOM;
894 }
895 SheetType sheetType = SheetType::SHEET_BOTTOM;
896 auto rootHeight = PipelineContext::GetCurrentRootHeight();
897 auto rootWidth = PipelineContext::GetCurrentRootWidth();
898 auto pipelineContext = PipelineContext::GetCurrentContext();
899 CHECK_NULL_RETURN(pipelineContext, sheetType);
900 auto windowRect = pipelineContext->GetCurrentWindowRect();
901 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
902 CHECK_NULL_RETURN(layoutProperty, sheetType);
903 auto sheetStyle = layoutProperty->GetSheetStyleValue();
904 if (sheetThemeType_ == "auto") {
905 if (IsFold()) {
906 sheetType = SheetType::SHEET_CENTER;
907 } else {
908 if (rootHeight < rootWidth) {
909 sheetType = SheetType::SHEET_BOTTOMLANDSPACE;
910 } else {
911 sheetType = SheetType::SHEET_BOTTOM;
912 }
913 }
914 } else if (sheetThemeType_ == "popup") {
915 if (windowRect.Width() >= SHEET_PC_DEVICE_WIDTH_BREAKPOINT.ConvertToPx()) {
916 if (sheetStyle.sheetType.has_value()) {
917 sheetType = sheetStyle.sheetType.value();
918 } else {
919 sheetType = SheetType::SHEET_POPUP;
920 }
921 } else if ((windowRect.Width() >= SHEET_DEVICE_WIDTH_BREAKPOINT.ConvertToPx()) &&
922 (windowRect.Width() < SHEET_PC_DEVICE_WIDTH_BREAKPOINT.ConvertToPx())) {
923 if (sheetStyle.sheetType.has_value()) {
924 sheetType = sheetStyle.sheetType.value();
925 } else {
926 sheetType = SheetType::SHEET_CENTER;
927 }
928 } else {
929 sheetType = SheetType::SHEET_BOTTOM_FREE_WINDOW;
930 }
931 }
932 return sheetType;
933 }
934
BubbleStyleSheetTransition(bool isTransitionIn)935 void SheetPresentationPattern::BubbleStyleSheetTransition(bool isTransitionIn)
936 {
937 auto host = this->GetHost();
938 CHECK_NULL_VOID(host);
939 if (!isTransitionIn) {
940 auto pipelineContext = PipelineContext::GetCurrentContext();
941 CHECK_NULL_VOID(pipelineContext);
942 auto overlayManager = pipelineContext->GetOverlayManager();
943 CHECK_NULL_VOID(overlayManager);
944 auto maskNode = overlayManager->GetSheetMask(host);
945 if (maskNode) {
946 overlayManager->PlaySheetMaskTransition(maskNode, false);
947 }
948 StartOffsetExitingAnimation();
949 StartAlphaExitingAnimation(
950 [weakNode = AceType::WeakClaim(AceType::RawPtr(host)), weakPattern = AceType::WeakClaim(this)]() {
951 auto node = weakNode.Upgrade();
952 CHECK_NULL_VOID(node);
953 auto pattern = weakPattern.Upgrade();
954 CHECK_NULL_VOID(pattern);
955 auto context = PipelineContext::GetCurrentContext();
956 CHECK_NULL_VOID(context);
957 auto overlayManager = context->GetOverlayManager();
958 CHECK_NULL_VOID(overlayManager);
959 overlayManager->DestroySheet(node, pattern->GetTargetId());
960 pattern->FireCallback("false");
961 });
962 }
963 }
964
StartOffsetEnteringAnimation()965 void SheetPresentationPattern::StartOffsetEnteringAnimation()
966 {
967 AnimationOption optionPosition;
968 optionPosition.SetDuration(SHEET_ENTRY_ANIMATION_DURATION);
969 optionPosition.SetCurve(Curves::FRICTION);
970 AnimationUtils::Animate(
971 optionPosition,
972 [weak = WeakClaim(this)]() {
973 auto pattern = weak.Upgrade();
974 CHECK_NULL_VOID(pattern);
975 auto renderContext = pattern->GetRenderContext();
976 CHECK_NULL_VOID(renderContext);
977 renderContext->OnTransformTranslateUpdate({ 0.0f, Dimension(pattern->sheetOffsetY_), 0.0f });
978 },
979 nullptr);
980 }
981
StartAlphaEnteringAnimation(std::function<void ()> finish)982 void SheetPresentationPattern::StartAlphaEnteringAnimation(std::function<void()> finish)
983 {
984 AnimationOption optionAlpha;
985 optionAlpha.SetDuration(SHEET_ENTRY_ANIMATION_DURATION);
986 optionAlpha.SetCurve(Curves::SHARP);
987 AnimationUtils::Animate(
988 optionAlpha,
989 [weak = WeakClaim(this)]() {
990 auto pattern = weak.Upgrade();
991 CHECK_NULL_VOID(pattern);
992 auto renderContext = pattern->GetRenderContext();
993 CHECK_NULL_VOID(renderContext);
994 renderContext->UpdateOpacity(SHEET_VISIABLE_ALPHA);
995 },
996 finish);
997 }
998
StartOffsetExitingAnimation()999 void SheetPresentationPattern::StartOffsetExitingAnimation()
1000 {
1001 AnimationOption optionPosition;
1002 optionPosition.SetDuration(SHEET_EXIT_ANIMATION_DURATION);
1003 optionPosition.SetCurve(Curves::FRICTION);
1004 AnimationUtils::Animate(
1005 optionPosition,
1006 [weak = WeakClaim(this)]() {
1007 auto pattern = weak.Upgrade();
1008 CHECK_NULL_VOID(pattern);
1009 auto renderContext = pattern->GetRenderContext();
1010 CHECK_NULL_VOID(renderContext);
1011 renderContext->OnTransformTranslateUpdate(
1012 { 0.0f, Dimension(pattern->sheetOffsetY_ - SHEET_INVISIABLE_OFFSET), 0.0f });
1013 },
1014 nullptr);
1015 }
1016
StartAlphaExitingAnimation(std::function<void ()> finish)1017 void SheetPresentationPattern::StartAlphaExitingAnimation(std::function<void()> finish)
1018 {
1019 AnimationOption optionAlpha;
1020 optionAlpha.SetDuration(SHEET_EXIT_ANIMATION_DURATION);
1021 optionAlpha.SetCurve(Curves::SHARP);
1022 AnimationUtils::Animate(
1023 optionAlpha,
1024 [weak = WeakClaim(this)]() {
1025 auto pattern = weak.Upgrade();
1026 CHECK_NULL_VOID(pattern);
1027 auto renderContext = pattern->GetRenderContext();
1028 CHECK_NULL_VOID(renderContext);
1029 renderContext->UpdateOpacity(SHEET_INVISIABLE_ALPHA);
1030 },
1031 finish);
1032 }
1033
GetRenderContext()1034 RefPtr<RenderContext> SheetPresentationPattern::GetRenderContext()
1035 {
1036 auto frameNode = GetHost();
1037 CHECK_NULL_RETURN(frameNode, nullptr);
1038 return frameNode->GetRenderContext();
1039 }
1040
PostTask(const TaskExecutor::Task & task)1041 bool SheetPresentationPattern::PostTask(const TaskExecutor::Task& task)
1042 {
1043 auto pipeline = PipelineBase::GetCurrentContext();
1044 CHECK_NULL_RETURN(pipeline, false);
1045 auto taskExecutor = pipeline->GetTaskExecutor();
1046 CHECK_NULL_RETURN(taskExecutor, false);
1047 return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI);
1048 }
1049
ResetToInvisible()1050 void SheetPresentationPattern::ResetToInvisible()
1051 {
1052 auto renderContext = GetRenderContext();
1053 CHECK_NULL_VOID(renderContext);
1054 renderContext->UpdateOpacity(SHEET_INVISIABLE_ALPHA);
1055 renderContext->OnTransformTranslateUpdate({ 0.0f, Dimension(sheetOffsetY_ - SHEET_INVISIABLE_OFFSET), 0.0f });
1056 }
1057
IsFold()1058 bool SheetPresentationPattern::IsFold()
1059 {
1060 auto containerId = Container::CurrentId();
1061 auto foldWindow = FoldableWindow::CreateFoldableWindow(containerId);
1062 CHECK_NULL_RETURN(foldWindow, false);
1063 if (foldWindow->IsFoldExpand()) {
1064 return true;
1065 } else {
1066 return false;
1067 }
1068 }
1069
ChangeSheetHeight(float height)1070 void SheetPresentationPattern::ChangeSheetHeight(float height)
1071 {
1072 if (!NearEqual(height_, height)) {
1073 height_ = height;
1074 SetCurrentHeightToOverlay(height_);
1075 }
1076 }
1077
StartSheetTransitionAnimation(const AnimationOption & option,bool isTransitionIn,float offset)1078 void SheetPresentationPattern::StartSheetTransitionAnimation(
1079 const AnimationOption& option, bool isTransitionIn, float offset)
1080 {
1081 auto host = GetHost();
1082 CHECK_NULL_VOID(host);
1083 auto context = host->GetRenderContext();
1084 CHECK_NULL_VOID(context);
1085 isAnimationProcess_ = true;
1086 if (isTransitionIn) {
1087 animation_ = AnimationUtils::StartAnimation(
1088 option,
1089 [context, offset]() {
1090 if (context) {
1091 context->OnTransformTranslateUpdate({ 0.0f, offset, 0.0f });
1092 }
1093 },
1094 option.GetOnFinishEvent());
1095 } else {
1096 animation_ = AnimationUtils::StartAnimation(
1097 option,
1098 [context, this]() {
1099 if (context) {
1100 context->OnTransformTranslateUpdate({ 0.0f, pageHeight_, 0.0f });
1101 }
1102 },
1103 option.GetOnFinishEvent());
1104 }
1105 }
1106
ClipSheetNode()1107 void SheetPresentationPattern::ClipSheetNode()
1108 {
1109 auto host = GetHost();
1110 CHECK_NULL_VOID(host);
1111 auto geometryNode = host->GetGeometryNode();
1112 CHECK_NULL_VOID(geometryNode);
1113 auto sheetSize = geometryNode->GetFrameSize();
1114 auto pipeline = PipelineContext::GetCurrentContext();
1115 CHECK_NULL_VOID(pipeline);
1116 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1117 CHECK_NULL_VOID(sheetTheme);
1118 auto sheetRadius = sheetTheme->GetSheetRadius();
1119 auto renderContext = host->GetRenderContext();
1120 CHECK_NULL_VOID(renderContext);
1121 auto sheetType = GetSheetType();
1122 std::string clipPath;
1123 if (sheetType == SheetType::SHEET_POPUP) {
1124 clipPath = GetPopupStyleSheetClipPath(sheetSize, sheetRadius);
1125 } else if (sheetType == SheetType::SHEET_CENTER) {
1126 clipPath = GetCenterStyleSheetClipPath(sheetSize, sheetRadius);
1127 } else {
1128 clipPath = GetBottomStyleSheetClipPath(sheetSize, sheetRadius);
1129 }
1130 auto path = AceType::MakeRefPtr<Path>();
1131 path->SetValue(clipPath);
1132 path->SetBasicShapeType(BasicShapeType::PATH);
1133 renderContext->UpdateClipShape(path);
1134 }
1135
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)1136 void SheetPresentationPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
1137 {
1138 auto sheetType = GetSheetType();
1139 if ((type == WindowSizeChangeReason::ROTATION) &&
1140 ((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOMLANDSPACE))) {
1141 windowRotate_ = true;
1142 firstMeasure_ = true;
1143 SetColumnMinSize(true);
1144 // Before rotation, reset to the initial mode sheet ratio of the current vertical or horizontal screen
1145 // It's actually a state where the soft keyboard is not pulled up
1146 if (isScrolling_) {
1147 ScrollTo(-scrollHeight_);
1148 }
1149 TranslateTo(height_);
1150 }
1151 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::UNDEFINED ||
1152 type == WindowSizeChangeReason::DRAG) {
1153 windowChanged_ = true;
1154 }
1155 }
1156
TranslateTo(float height)1157 void SheetPresentationPattern::TranslateTo(float height)
1158 {
1159 auto host = GetHost();
1160 CHECK_NULL_VOID(host);
1161 auto context = host->GetRenderContext();
1162 CHECK_NULL_VOID(context);
1163 context->OnTransformTranslateUpdate(
1164 {0.0f, height, 0.0f });
1165 }
1166
ScrollTo(float height)1167 void SheetPresentationPattern::ScrollTo(float height)
1168 {
1169 auto host = GetHost();
1170 CHECK_NULL_VOID(host);
1171 auto scroll = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
1172 CHECK_NULL_VOID(scroll);
1173 auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1174 CHECK_NULL_VOID(scrollPattern);
1175 auto layoutProp = scrollPattern->GetLayoutProperty<ScrollLayoutProperty>();
1176 CHECK_NULL_VOID(layoutProp);
1177 auto geometryNode = scroll->GetGeometryNode();
1178 CHECK_NULL_VOID(geometryNode);
1179 scrollHeight_ = height;
1180 isScrolling_ = height > 0;
1181 layoutProp->UpdateScrollEnabled(isScrolling_);
1182 layoutProp->UpdateUserDefinedIdealSize(CalcSize(
1183 CalcLength(geometryNode->GetFrameSize().Width()), CalcLength(geometryNode->GetFrameSize().Height() - height)));
1184 scrollPattern->JumpToPosition(-height);
1185 scroll->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1186 }
1187
SetColumnMinSize(bool reset)1188 void SheetPresentationPattern::SetColumnMinSize(bool reset)
1189 {
1190 if (!firstMeasure_) {
1191 return;
1192 }
1193 auto host = GetHost();
1194 CHECK_NULL_VOID(host);
1195 auto scroll = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
1196 CHECK_NULL_VOID(scroll);
1197 auto buildContent = AceType::DynamicCast<FrameNode>(scroll->GetChildAtIndex(0));
1198 CHECK_NULL_VOID(buildContent);
1199 auto geometryNode = buildContent->GetGeometryNode();
1200 CHECK_NULL_VOID(geometryNode);
1201 auto props = buildContent->GetLayoutProperty<LayoutProperty>();
1202 CHECK_NULL_VOID(props);
1203 if (reset) {
1204 props->ResetCalcMinSize();
1205 return;
1206 }
1207 props->UpdateCalcMinSize(
1208 CalcSize(CalcLength(geometryNode->GetFrameSize().Width()), CalcLength(geometryNode->GetFrameSize().Height())));
1209 firstMeasure_ = false;
1210 }
1211
GetPopupStyleSheetClipPath(SizeF sheetSize,Dimension sheetRadius)1212 std::string SheetPresentationPattern::GetPopupStyleSheetClipPath(SizeF sheetSize, Dimension sheetRadius)
1213 {
1214 float half = 0.5f;
1215 std::string path = MoveTo(0.0f, SHEET_ARROW_HEIGHT.ConvertToPx() + sheetRadius.ConvertToPx());
1216 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetRadius.ConvertToPx(),
1217 SHEET_ARROW_HEIGHT.ConvertToPx());
1218 path += LineTo(sheetSize.Width() * half - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
1219 SHEET_ARROW_HEIGHT.ConvertToPx()); // P1
1220 path += LineTo(sheetSize.Width() * half - ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
1221 SHEET_ARROW_HEIGHT.ConvertToPx() - ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
1222 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
1223 sheetSize.Width() * half + ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
1224 SHEET_ARROW_HEIGHT.ConvertToPx() - ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx()); // P4
1225 path += LineTo(sheetSize.Width() * half + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
1226 SHEET_ARROW_HEIGHT.ConvertToPx()); // P5
1227 path += LineTo(sheetSize.Width() - sheetRadius.ConvertToPx(), SHEET_ARROW_HEIGHT.ConvertToPx());
1228 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetSize.Width(),
1229 SHEET_ARROW_HEIGHT.ConvertToPx() + sheetRadius.ConvertToPx());
1230 path += LineTo(sheetSize.Width(), sheetSize.Height() - sheetRadius.ConvertToPx());
1231 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0,
1232 sheetSize.Width() - sheetRadius.ConvertToPx(), sheetSize.Height());
1233 path += LineTo(sheetRadius.ConvertToPx(), sheetSize.Height());
1234 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, 0.0f,
1235 sheetSize.Height() - sheetRadius.ConvertToPx());
1236 return path + "Z";
1237 }
1238
GetCenterStyleSheetClipPath(SizeF sheetSize,Dimension sheetRadius)1239 std::string SheetPresentationPattern::GetCenterStyleSheetClipPath(SizeF sheetSize, Dimension sheetRadius)
1240 {
1241 std::string path = MoveTo(0.0f, sheetRadius.ConvertToPx());
1242 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetRadius.ConvertToPx(), 0.0f);
1243 path += LineTo(sheetSize.Width() - sheetRadius.ConvertToPx(), 0.0f);
1244 path += ArcTo(
1245 sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetSize.Width(), sheetRadius.ConvertToPx());
1246 path += LineTo(sheetSize.Width(), sheetSize.Height() - sheetRadius.ConvertToPx());
1247 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0,
1248 sheetSize.Width() - sheetRadius.ConvertToPx(), sheetSize.Height());
1249 path += LineTo(sheetRadius.ConvertToPx(), sheetSize.Height());
1250 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, 0.0f,
1251 sheetSize.Height() - sheetRadius.ConvertToPx());
1252 return path + "Z";
1253 }
1254
GetBottomStyleSheetClipPath(SizeF sheetSize,Dimension sheetRadius)1255 std::string SheetPresentationPattern::GetBottomStyleSheetClipPath(SizeF sheetSize, Dimension sheetRadius)
1256 {
1257 std::string path = MoveTo(0.0f, sheetRadius.ConvertToPx());
1258 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetRadius.ConvertToPx(), 0.0f);
1259 path += LineTo(sheetSize.Width() - sheetRadius.ConvertToPx(), 0.0f);
1260 path += ArcTo(
1261 sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetSize.Width(), sheetRadius.ConvertToPx());
1262 path += LineTo(sheetSize.Width(), sheetSize.Height());
1263 path += LineTo(0.0f, sheetSize.Height());
1264 return path + "Z";
1265 }
1266
MoveTo(double x,double y)1267 std::string SheetPresentationPattern::MoveTo(double x, double y)
1268 {
1269 return "M" + std::to_string(x) + " " + std::to_string(y) + " ";
1270 }
1271
LineTo(double x,double y)1272 std::string SheetPresentationPattern::LineTo(double x, double y)
1273 {
1274 return "L" + std::to_string(x) + " " + std::to_string(y) + " ";
1275 }
1276
ArcTo(double rx,double ry,double rotation,int32_t arc_flag,double x,double y)1277 std::string SheetPresentationPattern::ArcTo(double rx, double ry, double rotation, int32_t arc_flag, double x, double y)
1278 {
1279 int32_t sweep_flag = 1;
1280 return "A" + std::to_string(rx) + " " + std::to_string(ry) + " " + std::to_string(rotation) + " " +
1281 std::to_string(arc_flag) + " " + std::to_string(sweep_flag) + " " + std::to_string(x) + " " +
1282 std::to_string(y) + " ";
1283 }
1284
GetFitContentHeight()1285 float SheetPresentationPattern::GetFitContentHeight()
1286 {
1287 auto sheetNode = GetHost();
1288 CHECK_NULL_RETURN(sheetNode, 0.0f);
1289 auto titleColumn = DynamicCast<FrameNode>(sheetNode->GetFirstChild());
1290 CHECK_NULL_RETURN(titleColumn, 0.0f);
1291 auto titleGeometryNode = titleColumn->GetGeometryNode();
1292 auto scrollNode = DynamicCast<FrameNode>(sheetNode->GetChildAtIndex(1));
1293 CHECK_NULL_RETURN(scrollNode, 0.0f);
1294 auto builderNode = DynamicCast<FrameNode>(scrollNode->GetChildAtIndex(0));
1295 CHECK_NULL_RETURN(builderNode, 0.0f);
1296 auto builderGeometryNode = builderNode->GetGeometryNode();
1297 return builderGeometryNode->GetFrameSize().Height() + titleGeometryNode->GetFrameSize().Height();
1298 }
1299
ProcessColumnRect(float height)1300 void SheetPresentationPattern::ProcessColumnRect(float height)
1301 {
1302 auto sheetNode = GetHost();
1303 CHECK_NULL_VOID(sheetNode);
1304 auto column = DynamicCast<FrameNode>(sheetNode->GetParent());
1305 CHECK_NULL_VOID(column);
1306 auto sheetType = GetSheetType();
1307 auto geometryNode = sheetNode->GetGeometryNode();
1308 CHECK_NULL_VOID(geometryNode);
1309 auto sheetSize = geometryNode->GetFrameSize();
1310 float sheetOffsetX = 0.0f;
1311 float sheetOffsetY = 0.0f;
1312 float sheetWidth = 0.0f;
1313 float sheetHeight = 0.0f;
1314 if (sheetType == SheetType::SHEET_POPUP) {
1315 sheetOffsetX = sheetOffsetX_;
1316 sheetWidth = sheetSize.Width();
1317 sheetOffsetY = sheetOffsetY_;
1318 sheetHeight = sheetSize.Height();
1319 } else if (sheetType == SheetType::SHEET_CENTER) {
1320 sheetOffsetX = sheetOffsetX_;
1321 sheetOffsetY = pageHeight_ - height;
1322 sheetWidth = sheetSize.Width();
1323 sheetHeight = sheetSize.Height();
1324 } else if ((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOM_FREE_WINDOW)) {
1325 sheetOffsetY = pageHeight_ - height;
1326 sheetWidth = sheetMaxWidth_;
1327 sheetHeight = height;
1328 } else if (sheetType == SheetType::SHEET_BOTTOMLANDSPACE) {
1329 sheetOffsetX = sheetOffsetX_;
1330 sheetOffsetY = pageHeight_ - height;
1331 sheetWidth = sheetSize.Width();
1332 sheetHeight = height;
1333 }
1334 auto hub = column->GetEventHub<EventHub>();
1335 auto gestureHub = hub->GetOrCreateGestureEventHub();
1336 std::vector<DimensionRect> mouseResponseRegion;
1337 mouseResponseRegion.emplace_back(Dimension(sheetWidth), Dimension(sheetHeight),
1338 DimensionOffset(Dimension(sheetOffsetX), Dimension(sheetOffsetY)));
1339 gestureHub->SetMouseResponseRegion(mouseResponseRegion);
1340 gestureHub->SetResponseRegion(mouseResponseRegion);
1341 }
1342 } // namespace OHOS::Ace::NG
1343