1 /*
2 * Copyright (c) 2022-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/tabs/tab_bar_pattern.h"
17
18 #include <optional>
19
20 #include "base/geometry/axis.h"
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/log/dump_log.h"
25 #include "base/memory/ace_type.h"
26 #include "base/utils/utils.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components_ng/pattern/scrollable/scrollable.h"
29 #include "core/components/tab_bar/tab_theme.h"
30 #include "core/components_ng/base/frame_node.h"
31 #include "core/components_ng/pattern/image/image_layout_property.h"
32 #include "core/components_ng/pattern/image/image_pattern.h"
33 #include "core/components_ng/pattern/pattern.h"
34 #include "core/components_ng/pattern/scroll/scroll_spring_effect.h"
35 #include "core/components_ng/pattern/swiper/swiper_event_hub.h"
36 #include "core/components_ng/pattern/swiper/swiper_model.h"
37 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
38 #include "core/components_ng/pattern/tabs/tabs_layout_property.h"
39 #include "core/components_ng/pattern/tabs/tabs_node.h"
40 #include "core/components_ng/pattern/tabs/tabs_pattern.h"
41 #include "core/components_ng/pattern/text/text_layout_property.h"
42 #include "core/components_ng/property/property.h"
43 #include "core/components_ng/property/safe_area_insets.h"
44 #include "core/components_v2/inspector/inspector_constants.h"
45 #include "core/pipeline_ng/pipeline_context.h"
46
47 namespace OHOS::Ace::NG {
48 namespace {
49 constexpr int8_t LEFT_GRADIENT = 0;
50 constexpr int8_t RIGHT_GRADIENT = 1;
51 constexpr int8_t TOP_GRADIENT = 2;
52 constexpr int8_t BOTTOM_GRADIENT = 3;
53 constexpr float HALF_PROGRESS = 0.5f;
54 constexpr float FULL_PROGRESS = 1.0f;
55 constexpr float HALF_MASK_RADIUS_RATIO = 0.717f;
56 constexpr float FULL_MASK_RADIUS_RATIO = 1.414f;
57 constexpr float INVALID_RATIO = -1.0f;
58 constexpr uint16_t MASK_ANIMATION_DURATION = 200;
59 constexpr int8_t MASK_COUNT = 2;
60 constexpr float FULL_OPACITY = 1.0f;
61 constexpr float NEAR_FULL_OPACITY = 0.99f;
62 constexpr float NO_OPACITY = 0.0f;
63 constexpr float TEXT_COLOR_THREDHOLD = 0.673f;
64
65 const auto DurationCubicCurve = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
66 } // namespace
67
OnAttachToFrameNode()68 void TabBarPattern::OnAttachToFrameNode()
69 {
70 auto host = GetHost();
71 CHECK_NULL_VOID(host);
72 auto renderContext = host->GetRenderContext();
73 CHECK_NULL_VOID(renderContext);
74 renderContext->SetClipToFrame(true);
75 host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(
76 SafeAreaExpandOpts { .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_BOTTOM });
77 swiperController_->SetTabBarFinishCallback([weak = WeakClaim(this)]() {
78 auto pattern = weak.Upgrade();
79 CHECK_NULL_VOID(pattern);
80 // always swipe with physical curve, ignore animationDuration
81 pattern->SetSwiperCurve(TabBarPhysicalCurve);
82
83 CHECK_NULL_VOID(pattern && pattern->scrollableEvent_);
84 auto scrollable = pattern->scrollableEvent_->GetScrollable();
85 if (scrollable) {
86 scrollable->StopScrollable();
87 }
88 });
89 InitSurfaceChangedCallback();
90 }
91
InitSurfaceChangedCallback()92 void TabBarPattern::InitSurfaceChangedCallback()
93 {
94 auto host = GetHost();
95 CHECK_NULL_VOID(host);
96 auto pipeline = host->GetContext();
97 CHECK_NULL_VOID(pipeline);
98 if (!HasSurfaceChangedCallback()) {
99 auto callbackId = pipeline->RegisterSurfaceChangedCallback(
100 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
101 WindowSizeChangeReason type) {
102 auto pattern = weak.Upgrade();
103 if (!pattern) {
104 return;
105 }
106 if (type == WindowSizeChangeReason::UNDEFINED) {
107 pattern->windowSizeChangeReason_ = type;
108 }
109
110 if (type == WindowSizeChangeReason::ROTATION) {
111 pattern->windowSizeChangeReason_ = type;
112 pattern->StopTranslateAnimation();
113 }
114 });
115 UpdateSurfaceChangedCallbackId(callbackId);
116 }
117 }
118
InitClick(const RefPtr<GestureEventHub> & gestureHub)119 void TabBarPattern::InitClick(const RefPtr<GestureEventHub>& gestureHub)
120 {
121 if (clickEvent_) {
122 return;
123 }
124 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
125 auto tabBar = weak.Upgrade();
126 if (tabBar) {
127 tabBar->HandleClick(info);
128 }
129 };
130 clickEvent_ = AceType::MakeRefPtr<ClickEvent>(std::move(clickCallback));
131 gestureHub->AddClickEvent(clickEvent_);
132 }
133
InitScrollable(const RefPtr<GestureEventHub> & gestureHub)134 void TabBarPattern::InitScrollable(const RefPtr<GestureEventHub>& gestureHub)
135 {
136 auto host = GetHost();
137 CHECK_NULL_VOID(host);
138 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
139 CHECK_NULL_VOID(layoutProperty);
140 auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
141 if (axis_ == axis && scrollableEvent_) {
142 return;
143 }
144
145 axis_ = axis;
146 auto task = [weak = WeakClaim(this)](double offset, int32_t source) {
147 if (source == SCROLL_FROM_START) {
148 return true;
149 }
150 auto pattern = weak.Upgrade();
151 if (!pattern) {
152 return false;
153 }
154 if (pattern->tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE && pattern->axis_ == Axis::HORIZONTAL &&
155 pattern->IsOutOfBoundary()) {
156 // over scroll in drag update from normal to over scroll.
157 float overScroll = 0.0f;
158 // over scroll in drag update during over scroll.
159 if (pattern->tabItemOffsets_.empty()) {
160 return false;
161 }
162 auto startPos =
163 pattern->tabItemOffsets_.begin()->GetX() - pattern->scrollMargin_ - pattern->GetLeftPadding();
164 auto host = pattern->GetHost();
165 CHECK_NULL_RETURN(host, false);
166 auto mainSize = host->GetGeometryNode()->GetPaddingSize().Width();
167 if (Positive(startPos)) {
168 overScroll = startPos;
169 } else {
170 overScroll = mainSize + pattern->GetLeftPadding() - pattern->tabItemOffsets_.back().GetX() -
171 pattern->scrollMargin_;
172 }
173
174 if (source == SCROLL_FROM_UPDATE) {
175 // adjust offset.
176 if (mainSize != 0.0f) {
177 auto friction = CalculateFriction(std::abs(overScroll) / mainSize);
178 pattern->UpdateCurrentOffset(static_cast<float>(offset * friction));
179 }
180 return true;
181 }
182 }
183 if (source == SCROLL_FROM_AXIS) {
184 pattern->AdjustOffset(offset);
185 }
186 pattern->UpdateCurrentOffset(static_cast<float>(offset));
187 return true;
188 };
189
190 if (scrollableEvent_) {
191 gestureHub->RemoveScrollableEvent(scrollableEvent_);
192 }
193
194 scrollableEvent_ = MakeRefPtr<ScrollableEvent>(axis);
195 auto scrollable = MakeRefPtr<Scrollable>(task, axis);
196 scrollable->SetNodeId(host->GetAccessibilityId());
197 scrollable->Initialize(host->GetContext());
198 scrollableEvent_->SetScrollable(scrollable);
199 gestureHub->AddScrollableEvent(scrollableEvent_);
200 scrollableEvent_->GetScrollable()->SetEdgeEffect(EdgeEffect::SPRING);
201 }
202
InitTouch(const RefPtr<GestureEventHub> & gestureHub)203 void TabBarPattern::InitTouch(const RefPtr<GestureEventHub>& gestureHub)
204 {
205 if (touchEvent_) {
206 return;
207 }
208 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
209 auto pattern = weak.Upgrade();
210 CHECK_NULL_VOID(pattern);
211 pattern->HandleTouchEvent(info.GetTouches().front());
212 };
213 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
214 gestureHub->AddTouchEvent(touchEvent_);
215 }
216
InitHoverEvent()217 void TabBarPattern::InitHoverEvent()
218 {
219 if (hoverEvent_) {
220 return;
221 }
222 auto host = GetHost();
223 CHECK_NULL_VOID(host);
224 auto eventHub = GetHost()->GetEventHub<EventHub>();
225 auto inputHub = eventHub->GetOrCreateInputEventHub();
226
227 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
228 auto pattern = weak.Upgrade();
229 if (pattern) {
230 pattern->HandleHoverEvent(isHover);
231 }
232 };
233 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
234 inputHub->AddOnHoverEvent(hoverEvent_);
235 }
236
InitMouseEvent()237 void TabBarPattern::InitMouseEvent()
238 {
239 if (mouseEvent_) {
240 return;
241 }
242 auto host = GetHost();
243 CHECK_NULL_VOID(host);
244 auto eventHub = GetHost()->GetEventHub<EventHub>();
245 auto inputHub = eventHub->GetOrCreateInputEventHub();
246 auto mouseTask = [weak = WeakClaim(this)](const MouseInfo& info) {
247 auto pattern = weak.Upgrade();
248 if (pattern) {
249 pattern->HandleMouseEvent(info);
250 }
251 };
252 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
253 inputHub->AddOnMouseEvent(mouseEvent_);
254 }
255
HandleMouseEvent(const MouseInfo & info)256 void TabBarPattern::HandleMouseEvent(const MouseInfo& info)
257 {
258 if (IsContainsBuilder()) {
259 return;
260 }
261 auto host = GetHost();
262 CHECK_NULL_VOID(host);
263 auto totalCount = host->TotalChildCount() - MASK_COUNT;
264 if (totalCount < 0) {
265 return;
266 }
267 auto index = CalculateSelectedIndex(info.GetLocalLocation());
268 if (index < 0 || index >= totalCount) {
269 if (hoverIndex_.has_value() && !touchingIndex_.has_value()) {
270 HandleMoveAway(hoverIndex_.value());
271 }
272 hoverIndex_.reset();
273 return;
274 }
275 auto mouseAction = info.GetAction();
276 if (mouseAction == MouseAction::MOVE || mouseAction == MouseAction::WINDOW_ENTER) {
277 if (touchingIndex_.has_value()) {
278 hoverIndex_ = index;
279 return;
280 }
281 if (!hoverIndex_.has_value()) {
282 HandleHoverOnEvent(index);
283 hoverIndex_ = index;
284 return;
285 }
286 if (hoverIndex_.value() != index) {
287 HandleMoveAway(hoverIndex_.value());
288 HandleHoverOnEvent(index);
289 hoverIndex_ = index;
290 return;
291 }
292 return;
293 }
294 if (mouseAction == MouseAction::WINDOW_LEAVE) {
295 if (hoverIndex_.has_value()) {
296 HandleMoveAway(hoverIndex_.value());
297 }
298 }
299 }
300
HandleHoverEvent(bool isHover)301 void TabBarPattern::HandleHoverEvent(bool isHover)
302 {
303 if (IsContainsBuilder()) {
304 return;
305 }
306 isHover_ = isHover;
307 if (!isHover_ && hoverIndex_.has_value()) {
308 if (!touchingIndex_.has_value()) {
309 HandleMoveAway(hoverIndex_.value());
310 }
311 hoverIndex_.reset();
312 }
313 }
314
HandleHoverOnEvent(int32_t index)315 void TabBarPattern::HandleHoverOnEvent(int32_t index)
316 {
317 auto pipelineContext = PipelineContext::GetCurrentContext();
318 CHECK_NULL_VOID(pipelineContext);
319 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
320 CHECK_NULL_VOID(tabTheme);
321 PlayPressAnimation(index, tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVER);
322 }
323
HandleMoveAway(int32_t index)324 void TabBarPattern::HandleMoveAway(int32_t index)
325 {
326 PlayPressAnimation(index, Color::TRANSPARENT, AnimationType::HOVER);
327 }
328
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)329 void TabBarPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
330 {
331 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
332 auto pattern = wp.Upgrade();
333 if (pattern) {
334 return pattern->OnKeyEvent(event);
335 }
336 return false;
337 };
338 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
339
340 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
341 auto pattern = wp.Upgrade();
342 if (pattern) {
343 pattern->GetInnerFocusPaintRect(paintRect);
344 }
345 };
346 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
347 }
348
OnKeyEvent(const KeyEvent & event)349 bool TabBarPattern::OnKeyEvent(const KeyEvent& event)
350 {
351 auto pipeline = PipelineContext::GetCurrentContext();
352 CHECK_NULL_RETURN(pipeline, false);
353 if (!pipeline->GetIsFocusActive()) {
354 return false;
355 }
356 isFirstFocus_ = false;
357 if (event.action != KeyAction::DOWN) {
358 return false;
359 }
360 if (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE || tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
361 return OnKeyEventWithoutClick(event);
362 }
363 auto host = GetHost();
364 CHECK_NULL_RETURN(host, false);
365 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
366 auto indicator = tabBarLayoutProperty->GetIndicatorValue(0);
367
368 if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
369 ? KeyCode::KEY_DPAD_LEFT
370 : KeyCode::KEY_DPAD_UP) ||
371 event.IsShiftWith(KeyCode::KEY_TAB)) {
372 if (indicator <= 0) {
373 return false;
374 }
375 indicator -= 1;
376 FocusIndexChange(indicator);
377 return true;
378 }
379 if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
380 ? KeyCode::KEY_DPAD_RIGHT
381 : KeyCode::KEY_DPAD_DOWN) ||
382 event.code == KeyCode::KEY_TAB) {
383 if (indicator >= host->TotalChildCount() - MASK_COUNT - 1) {
384 return false;
385 }
386 indicator += 1;
387 FocusIndexChange(indicator);
388 return true;
389 }
390 if (event.code == KeyCode::KEY_MOVE_HOME) {
391 indicator = 0;
392 FocusIndexChange(indicator);
393 return true;
394 }
395 if (event.code == KeyCode::KEY_MOVE_END) {
396 indicator = host->TotalChildCount() - MASK_COUNT - 1;
397 FocusIndexChange(indicator);
398 return true;
399 }
400 return false;
401 }
402
OnKeyEventWithoutClick(const KeyEvent & event)403 bool TabBarPattern::OnKeyEventWithoutClick(const KeyEvent& event)
404 {
405 auto host = GetHost();
406 CHECK_NULL_RETURN(host, false);
407 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
408
409 if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
410 ? KeyCode::KEY_DPAD_LEFT
411 : KeyCode::KEY_DPAD_UP) ||
412 event.IsShiftWith(KeyCode::KEY_TAB)) {
413 if (focusIndicator_ <= 0) {
414 return false;
415 }
416 if (!ContentWillChange(focusIndicator_ - 1)) {
417 return true;
418 }
419 focusIndicator_ -= 1;
420 PaintFocusState();
421 return true;
422 }
423 if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
424 ? KeyCode::KEY_DPAD_RIGHT
425 : KeyCode::KEY_DPAD_DOWN) ||
426 event.code == KeyCode::KEY_TAB) {
427 if (focusIndicator_ >= host->TotalChildCount() - MASK_COUNT - 1) {
428 return false;
429 }
430 if (!ContentWillChange(focusIndicator_ + 1)) {
431 return true;
432 }
433 focusIndicator_ += 1;
434 PaintFocusState();
435 return true;
436 }
437 return OnKeyEventWithoutClick(host, event);
438 }
439
OnKeyEventWithoutClick(const RefPtr<FrameNode> & host,const KeyEvent & event)440 bool TabBarPattern::OnKeyEventWithoutClick(const RefPtr<FrameNode>& host, const KeyEvent& event)
441 {
442 if (event.code == KeyCode::KEY_MOVE_HOME) {
443 if (!ContentWillChange(0)) {
444 return true;
445 }
446 focusIndicator_ = 0;
447 PaintFocusState();
448 return true;
449 }
450 if (event.code == KeyCode::KEY_MOVE_END) {
451 if (!ContentWillChange(host->TotalChildCount() - MASK_COUNT - 1)) {
452 return true;
453 }
454 focusIndicator_ = host->TotalChildCount() - MASK_COUNT - 1;
455 PaintFocusState();
456 return true;
457 }
458 if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) {
459 TabBarClickEvent(focusIndicator_);
460 FocusIndexChange(focusIndicator_);
461 return true;
462 }
463 return false;
464 }
465
FocusIndexChange(int32_t index)466 void TabBarPattern::FocusIndexChange(int32_t index)
467 {
468 auto host = GetHost();
469 CHECK_NULL_VOID(host);
470 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
471 CHECK_NULL_VOID(tabsNode);
472 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
473 CHECK_NULL_VOID(tabsPattern);
474 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
475 CHECK_NULL_VOID(tabBarLayoutProperty);
476 if (!ContentWillChange(indicator_, index)) {
477 return;
478 }
479 if (tabsPattern->GetIsCustomAnimation()) {
480 OnCustomContentTransition(indicator_, index);
481 tabBarLayoutProperty->UpdateIndicator(index);
482 PaintFocusState(false);
483 } else {
484 if (GetAnimationDuration().has_value()) {
485 swiperController_->SwipeTo(index);
486 } else {
487 swiperController_->SwipeToWithoutAnimation(index);
488 }
489
490 tabBarLayoutProperty->UpdateIndicator(index);
491 PaintFocusState();
492 }
493
494 UpdateTextColorAndFontWeight(index);
495 }
496
GetInnerFocusPaintRect(RoundRect & paintRect)497 void TabBarPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
498 {
499 auto host = GetHost();
500 CHECK_NULL_VOID(host);
501 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
502 CHECK_NULL_VOID(tabBarLayoutProperty);
503 auto indicator = tabBarLayoutProperty->GetIndicatorValue(0);
504 if (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE || tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
505 if (isFirstFocus_) {
506 focusIndicator_ = indicator;
507 } else {
508 indicator = focusIndicator_;
509 }
510 }
511 auto childNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(indicator));
512 CHECK_NULL_VOID(childNode);
513 auto renderContext = childNode->GetRenderContext();
514 CHECK_NULL_VOID(renderContext);
515 auto columnPaintRect = renderContext->GetPaintRectWithoutTransform();
516 auto pipeline = PipelineContext::GetCurrentContext();
517 CHECK_NULL_VOID(pipeline);
518 auto tabTheme = pipeline->GetTheme<TabTheme>();
519 CHECK_NULL_VOID(tabTheme);
520 auto radius = tabTheme->GetFocusIndicatorRadius();
521 auto outLineWidth = tabTheme->GetActiveIndicatorWidth();
522 columnPaintRect.SetOffset(OffsetF((columnPaintRect.GetOffset().GetX() + outLineWidth.ConvertToPx() / 2),
523 (columnPaintRect.GetOffset().GetY() + outLineWidth.ConvertToPx() / 2)));
524 columnPaintRect.SetSize(SizeF((columnPaintRect.GetSize().Width() - outLineWidth.ConvertToPx()),
525 (columnPaintRect.GetSize().Height() - outLineWidth.ConvertToPx())));
526
527 paintRect.SetRect(columnPaintRect);
528 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
529 static_cast<RSScalar>(radius.ConvertToPx()));
530 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
531 static_cast<RSScalar>(radius.ConvertToPx()));
532 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
533 static_cast<RSScalar>(radius.ConvertToPx()));
534 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
535 static_cast<RSScalar>(radius.ConvertToPx()));
536 }
537
PaintFocusState(bool needMarkDirty)538 void TabBarPattern::PaintFocusState(bool needMarkDirty)
539 {
540 auto host = GetHost();
541 CHECK_NULL_VOID(host);
542
543 RoundRect focusRect;
544 GetInnerFocusPaintRect(focusRect);
545
546 auto focusHub = host->GetFocusHub();
547 CHECK_NULL_VOID(focusHub);
548 focusHub->PaintInnerFocusState(focusRect);
549
550 if (needMarkDirty) {
551 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
552 }
553 }
554
OnModifyDone()555 void TabBarPattern::OnModifyDone()
556 {
557 Pattern::OnModifyDone();
558 auto host = GetHost();
559 CHECK_NULL_VOID(host);
560 auto hub = host->GetEventHub<EventHub>();
561 CHECK_NULL_VOID(hub);
562 auto gestureHub = hub->GetOrCreateGestureEventHub();
563 CHECK_NULL_VOID(gestureHub);
564
565 InitClick(gestureHub);
566 InitTurnPageRateEvent();
567 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
568 CHECK_NULL_VOID(layoutProperty);
569 if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
570 InitScrollable(gestureHub);
571 if (layoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
572 SetEdgeEffect(gestureHub);
573 }
574 }
575 InitTouch(gestureHub);
576 InitHoverEvent();
577 InitMouseEvent();
578 auto focusHub = host->GetFocusHub();
579 CHECK_NULL_VOID(focusHub);
580 InitOnKeyEvent(focusHub);
581 SetAccessibilityAction();
582 UpdateSubTabBoard();
583 needSetCentered_ = true;
584
585 CHECK_NULL_VOID(swiperController_);
586 auto removeEventCallback = [weak = WeakClaim(this)]() {
587 auto tabBarPattern = weak.Upgrade();
588 CHECK_NULL_VOID(tabBarPattern);
589 auto host = tabBarPattern->GetHost();
590 CHECK_NULL_VOID(host);
591 auto hub = host->GetEventHub<EventHub>();
592 CHECK_NULL_VOID(hub);
593 auto gestureHub = hub->GetOrCreateGestureEventHub();
594 CHECK_NULL_VOID(gestureHub);
595 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
596 CHECK_NULL_VOID(layoutProperty);
597 gestureHub->RemoveClickEvent(tabBarPattern->clickEvent_);
598 if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
599 gestureHub->RemoveScrollableEvent(tabBarPattern->scrollableEvent_);
600 }
601 gestureHub->RemoveTouchEvent(tabBarPattern->touchEvent_);
602 tabBarPattern->isTouchingSwiper_ = true;
603 };
604 swiperController_->SetRemoveTabBarEventCallback(std::move(removeEventCallback));
605
606 auto addEventCallback = [weak = WeakClaim(this)]() {
607 auto tabBarPattern = weak.Upgrade();
608 CHECK_NULL_VOID(tabBarPattern);
609 auto host = tabBarPattern->GetHost();
610 CHECK_NULL_VOID(host);
611 auto hub = host->GetEventHub<EventHub>();
612 CHECK_NULL_VOID(hub);
613 auto gestureHub = hub->GetOrCreateGestureEventHub();
614 CHECK_NULL_VOID(gestureHub);
615 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
616 CHECK_NULL_VOID(layoutProperty);
617 gestureHub->AddClickEvent(tabBarPattern->clickEvent_);
618 if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
619 gestureHub->AddScrollableEvent(tabBarPattern->scrollableEvent_);
620 }
621 gestureHub->AddTouchEvent(tabBarPattern->touchEvent_);
622 };
623 swiperController_->SetAddTabBarEventCallback(std::move(addEventCallback));
624
625 auto surfaceChangeCallback = [weak = WeakClaim(this)]() {
626 auto tabBarPattern = weak.Upgrade();
627 CHECK_NULL_VOID(tabBarPattern);
628 tabBarPattern->isTouchingSwiper_ = false;
629 };
630 swiperController_->SetSurfaceChangeCallback(std::move(surfaceChangeCallback));
631 }
632
UpdatePaintIndicator(int32_t indicator,bool needMarkDirty)633 void TabBarPattern::UpdatePaintIndicator(int32_t indicator, bool needMarkDirty)
634 {
635 auto tabBarNode = GetHost();
636 CHECK_NULL_VOID(tabBarNode);
637 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
638 CHECK_NULL_VOID(tabBarPattern);
639 auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
640 if (indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
641 return;
642 }
643
644 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
645 CHECK_NULL_VOID(layoutProperty);
646 if (tabBarPattern->IsContainsBuilder() || layoutProperty->GetAxis() == Axis::VERTICAL ||
647 tabBarStyles_[indicator] == TabBarStyle::BOTTOMTABBATSTYLE) {
648 paintProperty->UpdateIndicator({});
649
650 if (needMarkDirty) {
651 tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
652 }
653
654 return;
655 }
656
657 RectF rect = layoutProperty->GetIndicatorRect(indicator);
658 paintProperty->UpdateIndicator(rect);
659 if (!isTouchingSwiper_ || tabBarStyles_[indicator] != TabBarStyle::SUBTABBATSTYLE) {
660 currentIndicatorOffset_ = rect.GetX() + rect.Width() / 2;
661
662 if (needMarkDirty) {
663 tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
664 }
665 }
666 if (tabBarStyles_[indicator] == TabBarStyle::SUBTABBATSTYLE) {
667 UpdateSubTabBoard();
668 }
669 }
670
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)671 bool TabBarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
672 {
673 if (config.skipMeasure && config.skipLayout) {
674 return false;
675 }
676 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
677 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
678 auto tabBarLayoutAlgorithm = DynamicCast<TabBarLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
679 CHECK_NULL_RETURN(tabBarLayoutAlgorithm, false);
680 tabItemOffsets_ = tabBarLayoutAlgorithm->GetTabItemOffset();
681 currentOffset_ = tabBarLayoutAlgorithm->GetCurrentOffset();
682 childrenMainSize_ = tabBarLayoutAlgorithm->GetChildrenMainSize();
683 indicator_ = tabBarLayoutAlgorithm->GetIndicator();
684 scrollMargin_ = tabBarLayoutAlgorithm->GetScrollMargin();
685 auto layoutProperty = DynamicCast<TabBarLayoutProperty>(dirty->GetLayoutProperty());
686 auto host = GetHost();
687 CHECK_NULL_RETURN(host, false);
688 auto tabsFrameNode = AceType::DynamicCast<TabsNode>(host->GetParent());
689 CHECK_NULL_RETURN(tabsFrameNode, false);
690 auto swiperFrameNode = AceType::DynamicCast<FrameNode>(tabsFrameNode->GetTabs());
691 CHECK_NULL_RETURN(swiperFrameNode, false);
692 auto swiperPattern = swiperFrameNode->GetPattern<SwiperPattern>();
693 CHECK_NULL_RETURN(swiperPattern, false);
694 int32_t indicator = swiperPattern->GetCurrentIndex();
695 int32_t totalCount = swiperPattern->TotalCount();
696 if (indicator > totalCount - 1 || indicator < 0) {
697 indicator = 0;
698 }
699
700 if (swiperPattern->IsUseCustomAnimation()) {
701 UpdatePaintIndicator(indicator, false);
702 }
703
704 if ((!swiperPattern->IsUseCustomAnimation() || isFirstLayout_) && !isAnimating_ && !IsMaskAnimationExecuted()) {
705 UpdateIndicator(indicator);
706 }
707 isFirstLayout_ = false;
708
709 if (windowSizeChangeReason_) {
710 if (*windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION && animationTargetIndex_.has_value() &&
711 animationTargetIndex_ != indicator) {
712 swiperController_->SwipeToWithoutAnimation(animationTargetIndex_.value());
713 animationTargetIndex_.reset();
714 } else if (*windowSizeChangeReason_ == WindowSizeChangeReason::UNDEFINED) {
715 // UNDEFINED currently implies window change on foldable
716 TriggerTranslateAnimation(layoutProperty, indicator_, indicator_);
717 UpdateIndicator(indicator_);
718 }
719 windowSizeChangeReason_.reset();
720 }
721 UpdateGradientRegions(!swiperPattern->IsUseCustomAnimation());
722 if (!swiperPattern->IsUseCustomAnimation() && isTouchingSwiper_ &&
723 layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
724 ApplyTurnPageRateToIndicator(turnPageRate_);
725 }
726 return false;
727 }
728
HandleClick(const GestureEvent & info)729 void TabBarPattern::HandleClick(const GestureEvent& info)
730 {
731 if (info.GetSourceDevice() == SourceType::KEYBOARD) {
732 return;
733 }
734 auto host = GetHost();
735 CHECK_NULL_VOID(host);
736 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
737 CHECK_NULL_VOID(layoutProperty);
738 if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
739 layoutProperty->GetAxis() == Axis::HORIZONTAL) {
740 auto scrollable = scrollableEvent_->GetScrollable();
741 if (scrollable && !scrollable->IsSpringStopped()) {
742 if (IsOutOfBoundary()) {
743 return;
744 }
745 scrollable->StopScrollable();
746 }
747 }
748 if (tabItemOffsets_.empty()) {
749 return;
750 }
751
752 auto totalCount = host->TotalChildCount() - MASK_COUNT;
753 if (totalCount < 0) {
754 return;
755 }
756
757 auto index = CalculateSelectedIndex(info.GetLocalLocation());
758 TAG_LOGI(AceLogTag::ACE_TABS, "Clicked tabBarIndex: %{public}d, Clicked tabBarLocation: %{public}s", index,
759 info.GetLocalLocation().ToString().c_str());
760 if (index < 0 || index >= totalCount || !swiperController_ ||
761 indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
762 return;
763 }
764 SetSwiperCurve(DurationCubicCurve);
765
766 TabBarClickEvent(index);
767 if (tabBarStyles_[indicator_] == TabBarStyle::SUBTABBATSTYLE &&
768 tabBarStyles_[index] == TabBarStyle::SUBTABBATSTYLE &&
769 layoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
770 HandleSubTabBarClick(layoutProperty, index);
771 return;
772 }
773
774 if (!ContentWillChange(index)) {
775 return;
776 }
777 ClickTo(host, index);
778 layoutProperty->UpdateIndicator(index);
779 }
780
ClickTo(const RefPtr<FrameNode> & host,int32_t index)781 void TabBarPattern::ClickTo(const RefPtr<FrameNode>& host, int32_t index)
782 {
783 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
784 CHECK_NULL_VOID(tabsNode);
785 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
786 CHECK_NULL_VOID(tabsPattern);
787 if (tabsPattern->GetIsCustomAnimation()) {
788 OnCustomContentTransition(indicator_, index);
789 } else {
790 if (GetAnimationDuration().has_value()) {
791 swiperController_->SwipeTo(index);
792 animationTargetIndex_ = index;
793 } else {
794 swiperController_->SwipeToWithoutAnimation(index);
795 }
796 }
797 }
798
HandleBottomTabBarChange(int32_t index)799 void TabBarPattern::HandleBottomTabBarChange(int32_t index)
800 {
801 AnimationUtils::CloseImplicitAnimation();
802 auto preIndex = GetImageColorOnIndex().value_or(indicator_);
803 UpdateImageColor(index);
804 if (preIndex != index && (tabBarStyles_[preIndex] == TabBarStyle::BOTTOMTABBATSTYLE ||
805 tabBarStyles_[index] == TabBarStyle::BOTTOMTABBATSTYLE)) {
806 int32_t selectedIndex = -1;
807 int32_t unselectedIndex = -1;
808 if (tabBarStyles_[preIndex] == TabBarStyle::BOTTOMTABBATSTYLE && CheckSvg(preIndex)) {
809 unselectedIndex = preIndex;
810 }
811 if (tabBarStyles_[index] == TabBarStyle::BOTTOMTABBATSTYLE && CheckSvg(index)) {
812 selectedIndex = index;
813 }
814 HandleBottomTabBarClick(selectedIndex, unselectedIndex);
815 }
816 }
817
CheckSvg(int32_t index) const818 bool TabBarPattern::CheckSvg(int32_t index) const
819 {
820 auto host = GetHost();
821 CHECK_NULL_RETURN(host, false);
822 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
823 CHECK_NULL_RETURN(columnNode, false);
824 auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
825 CHECK_NULL_RETURN(imageNode, false);
826 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
827 CHECK_NULL_RETURN(imageLayoutProperty, false);
828 ImageSourceInfo info;
829 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
830 return imageSourceInfo.IsSvg();
831 }
832
HandleBottomTabBarClick(int32_t selectedIndex,int32_t unselectedIndex)833 void TabBarPattern::HandleBottomTabBarClick(int32_t selectedIndex, int32_t unselectedIndex)
834 {
835 auto host = GetHost();
836 CHECK_NULL_VOID(host);
837 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
838 CHECK_NULL_VOID(layoutProperty);
839
840 std::vector<int32_t> selectedIndexes = {selectedIndex, unselectedIndex};
841 OffsetF originalSelectedMaskOffset, originalUnselectedMaskOffset;
842 float selectedImageSize = 0.0f, unselectedImageSize = 0.0f;
843 for (int32_t maskIndex = 0; maskIndex < MASK_COUNT; maskIndex++) {
844 if (maskIndex == 0) {
845 layoutProperty->UpdateSelectedMask(selectedIndex);
846 } else {
847 layoutProperty->UpdateUnselectedMask(unselectedIndex);
848 }
849 if (selectedIndexes[maskIndex] < 0) {
850 continue;
851 }
852 GetBottomTabBarImageSizeAndOffset(selectedIndexes, maskIndex, selectedImageSize, unselectedImageSize,
853 originalSelectedMaskOffset, originalUnselectedMaskOffset);
854 }
855 ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, NO_OPACITY, HALF_MASK_RADIUS_RATIO, true);
856 ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset, FULL_OPACITY,
857 FULL_MASK_RADIUS_RATIO, false);
858
859 host->MarkDirtyNode();
860 PlayMaskAnimation(selectedImageSize, originalSelectedMaskOffset, selectedIndex, unselectedImageSize,
861 originalUnselectedMaskOffset, unselectedIndex);
862 }
863
GetBottomTabBarImageSizeAndOffset(const std::vector<int32_t> & selectedIndexes,int32_t maskIndex,float & selectedImageSize,float & unselectedImageSize,OffsetF & originalSelectedMaskOffset,OffsetF & originalUnselectedMaskOffset)864 void TabBarPattern::GetBottomTabBarImageSizeAndOffset(const std::vector<int32_t>& selectedIndexes, int32_t maskIndex,
865 float& selectedImageSize, float& unselectedImageSize, OffsetF& originalSelectedMaskOffset,
866 OffsetF& originalUnselectedMaskOffset)
867 {
868 auto pipelineContext = PipelineContext::GetCurrentContext();
869 CHECK_NULL_VOID(pipelineContext);
870 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
871 CHECK_NULL_VOID(tabTheme);
872
873 auto host = GetHost();
874 CHECK_NULL_VOID(host);
875
876 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndexes[maskIndex]));
877 CHECK_NULL_VOID(columnNode);
878 auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
879 CHECK_NULL_VOID(imageNode);
880 auto imageGeometryNode = imageNode->GetGeometryNode();
881 CHECK_NULL_VOID(imageGeometryNode);
882 auto imageOffset = imageGeometryNode->GetFrameOffset();
883 auto imageSize = imageGeometryNode->GetFrameSize().Width();
884 if (maskIndex == 0) {
885 selectedImageSize = imageSize;
886 } else {
887 unselectedImageSize = imageSize;
888 }
889 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
890 CHECK_NULL_VOID(imageLayoutProperty);
891 ImageSourceInfo info;
892 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
893
894 auto maskPosition = host->GetChildren().size() - MASK_COUNT;
895 if (maskPosition < 0) {
896 return;
897 }
898 auto selectedMaskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(maskPosition + maskIndex));
899 CHECK_NULL_VOID(selectedMaskNode);
900 if (maskIndex == 0) {
901 originalSelectedMaskOffset = imageOffset;
902 } else {
903 originalUnselectedMaskOffset = imageOffset;
904 }
905 auto selectedImageNode = AceType::DynamicCast<FrameNode>(selectedMaskNode->GetChildren().front());
906 CHECK_NULL_VOID(selectedImageNode);
907
908 auto selectedImageLayoutProperty = selectedImageNode->GetLayoutProperty<ImageLayoutProperty>();
909 CHECK_NULL_VOID(selectedImageLayoutProperty);
910 imageSourceInfo.SetFillColor(tabTheme->GetBottomTabIconOn());
911 selectedImageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
912
913 imageSourceInfo.SetFillColor(tabTheme->GetBottomTabIconOff());
914 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
915
916 selectedImageNode->MarkModifyDone();
917 selectedImageNode->MarkDirtyNode();
918 imageNode->MarkModifyDone();
919 imageNode->MarkDirtyNode();
920 }
921
PlayMaskAnimation(float selectedImageSize,const OffsetF & originalSelectedMaskOffset,int32_t selectedIndex,float unselectedImageSize,const OffsetF & originalUnselectedMaskOffset,int32_t unselectedIndex)922 void TabBarPattern::PlayMaskAnimation(float selectedImageSize,
923 const OffsetF& originalSelectedMaskOffset, int32_t selectedIndex, float unselectedImageSize,
924 const OffsetF& originalUnselectedMaskOffset, int32_t unselectedIndex)
925 {
926 auto curve = AceType::MakeRefPtr<CubicCurve>(0.4f, 0.0f, 0.2f, 1.0f);
927 AnimationOption option;
928 option.SetDuration(MASK_ANIMATION_DURATION);
929 option.SetCurve(curve);
930
931 AnimationUtils::OpenImplicitAnimation(option, option.GetCurve(), [weak = AceType::WeakClaim(this),
932 selectedIndex, unselectedIndex]() {
933 auto tabBar = weak.Upgrade();
934 if (tabBar) {
935 auto host = tabBar->GetHost();
936 CHECK_NULL_VOID(host);
937 MaskAnimationFinish(host, selectedIndex, true);
938 MaskAnimationFinish(host, unselectedIndex, false);
939 }
940 });
941
942 AnimationUtils::AddKeyFrame(HALF_PROGRESS, [weak = AceType::WeakClaim(this), selectedIndex, unselectedIndex,
943 selectedImageSize, originalSelectedMaskOffset, unselectedImageSize, originalUnselectedMaskOffset]() {
944 auto tabBar = weak.Upgrade();
945 if (tabBar) {
946 tabBar->ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, FULL_OPACITY,
947 INVALID_RATIO, true);
948 tabBar->ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset, NEAR_FULL_OPACITY,
949 INVALID_RATIO, false);
950 }
951 });
952
953 AnimationUtils::AddKeyFrame(FULL_PROGRESS, [weak = AceType::WeakClaim(this), selectedIndex, unselectedIndex,
954 selectedImageSize, originalSelectedMaskOffset, unselectedImageSize, originalUnselectedMaskOffset]() {
955 auto tabBar = weak.Upgrade();
956 if (tabBar) {
957 tabBar->ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, FULL_OPACITY,
958 FULL_MASK_RADIUS_RATIO, true);
959 tabBar->ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset, NO_OPACITY,
960 HALF_MASK_RADIUS_RATIO, false);
961 }
962 });
963
964 AnimationUtils::CloseImplicitAnimation();
965 }
966
MaskAnimationFinish(const RefPtr<FrameNode> & host,int32_t selectedIndex,bool isSelected)967 void TabBarPattern::MaskAnimationFinish(const RefPtr<FrameNode>& host, int32_t selectedIndex,
968 bool isSelected)
969 {
970 if (selectedIndex < 0) {
971 return;
972 }
973 auto tabBarLayoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
974 CHECK_NULL_VOID(tabBarLayoutProperty);
975 if (isSelected) {
976 tabBarLayoutProperty->UpdateSelectedMask(-1);
977 } else {
978 tabBarLayoutProperty->UpdateUnselectedMask(-1);
979 }
980
981 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
982 CHECK_NULL_VOID(columnNode);
983 auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
984 CHECK_NULL_VOID(imageNode);
985
986 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
987 CHECK_NULL_VOID(imageLayoutProperty);
988 ImageSourceInfo info;
989 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
990
991 auto pipelineContext = PipelineContext::GetCurrentContext();
992 CHECK_NULL_VOID(pipelineContext);
993 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
994 CHECK_NULL_VOID(tabTheme);
995 imageSourceInfo.SetFillColor(isSelected ? tabTheme->GetBottomTabIconOn() :
996 tabTheme->GetBottomTabIconOff());
997 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
998
999 host->MarkDirtyNode();
1000 imageNode->MarkModifyDone();
1001 imageNode->MarkDirtyNode();
1002 }
1003
ChangeMask(int32_t index,float imageSize,const OffsetF & originalMaskOffset,float opacity,float radiusRatio,bool isSelected)1004 void TabBarPattern::ChangeMask(int32_t index, float imageSize, const OffsetF& originalMaskOffset, float opacity,
1005 float radiusRatio, bool isSelected)
1006 {
1007 auto host = GetHost();
1008 CHECK_NULL_VOID(host);
1009 auto maskPosition = host->GetChildren().size() - MASK_COUNT;
1010 if (index < 0 || NearZero(imageSize) || maskPosition < 0) {
1011 return;
1012 }
1013
1014 auto maskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(maskPosition + !isSelected));
1015 CHECK_NULL_VOID(maskNode);
1016 auto maskImageNode = AceType::DynamicCast<FrameNode>(maskNode->GetChildren().front());
1017 CHECK_NULL_VOID(maskImageNode);
1018 auto maskImageRenderContext = maskImageNode->GetRenderContext();
1019 CHECK_NULL_VOID(maskImageRenderContext);
1020
1021 if (NonNegative(radiusRatio)) {
1022 auto maskRenderContext = maskNode->GetRenderContext();
1023 CHECK_NULL_VOID(maskRenderContext);
1024 auto maskGeometryNode = maskNode->GetGeometryNode();
1025 CHECK_NULL_VOID(maskGeometryNode);
1026 auto tabBarNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1027 CHECK_NULL_VOID(tabBarNode);
1028 auto tabBarGeometryNode = tabBarNode->GetGeometryNode();
1029 CHECK_NULL_VOID(tabBarGeometryNode);
1030
1031 OffsetF maskOffset = originalMaskOffset;
1032 maskOffset.AddX(-imageSize * radiusRatio);
1033 maskOffset.AddY(imageSize * (1.0f - radiusRatio));
1034 auto tabBarOffset = tabBarGeometryNode->GetMarginFrameOffset();
1035 maskGeometryNode->SetMarginFrameOffset(maskOffset + tabBarOffset);
1036 maskGeometryNode->SetFrameSize(SizeF(imageSize * radiusRatio * 2.0f, imageSize * radiusRatio * 2.0f));
1037 maskRenderContext->SyncGeometryProperties(nullptr);
1038 BorderRadiusProperty borderRadiusProperty;
1039 borderRadiusProperty.SetRadius(Dimension(imageSize * radiusRatio));
1040 maskRenderContext->UpdateBorderRadius(borderRadiusProperty);
1041 maskImageRenderContext->UpdateOffset(OffsetT<Dimension>(Dimension(imageSize * radiusRatio),
1042 Dimension(imageSize * (radiusRatio - 1.0f))));
1043 auto maskImageGeometryNode = maskImageNode->GetGeometryNode();
1044 CHECK_NULL_VOID(maskImageGeometryNode);
1045 maskImageGeometryNode->SetFrameSize(SizeF(imageSize, imageSize));
1046 auto maskImageProperty = maskImageNode->GetLayoutProperty<ImageLayoutProperty>();
1047 CHECK_NULL_VOID(maskImageProperty);
1048 maskImageProperty->UpdateUserDefinedIdealSize(
1049 CalcSize(NG::CalcLength(Dimension(imageSize)), NG::CalcLength(Dimension(imageSize))));
1050 maskImageRenderContext->SetVisible(false);
1051 maskImageRenderContext->SyncGeometryProperties(nullptr);
1052 }
1053 maskImageRenderContext->UpdateOpacity(opacity);
1054 }
1055
HandleSubTabBarClick(const RefPtr<TabBarLayoutProperty> & layoutProperty,int32_t index)1056 void TabBarPattern::HandleSubTabBarClick(const RefPtr<TabBarLayoutProperty>& layoutProperty, int32_t index)
1057 {
1058 auto host = GetHost();
1059 CHECK_NULL_VOID(host);
1060 auto tabsFrameNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1061 CHECK_NULL_VOID(tabsFrameNode);
1062 auto swiperFrameNode = AceType::DynamicCast<FrameNode>(tabsFrameNode->GetTabs());
1063 CHECK_NULL_VOID(swiperFrameNode);
1064 auto swiperPattern = swiperFrameNode->GetPattern<SwiperPattern>();
1065 CHECK_NULL_VOID(swiperPattern);
1066 CHECK_NULL_VOID(swiperController_);
1067 swiperController_->FinishAnimation();
1068 int32_t indicator = swiperPattern->GetCurrentIndex();
1069 auto tabsPattern = tabsFrameNode->GetPattern<TabsPattern>();
1070 CHECK_NULL_VOID(tabsPattern);
1071 if (!tabsPattern->GetIsCustomAnimation() && indicator == index) {
1072 return;
1073 }
1074 changeByClick_ = true;
1075
1076 if (tabsPattern->GetIsCustomAnimation()) {
1077 OnCustomContentTransition(indicator, index);
1078 TriggerTranslateAnimation(layoutProperty, index, swiperPattern->GetCurrentIndex());
1079 } else {
1080 TriggerTranslateAnimation(layoutProperty, index, indicator);
1081 swiperController_->SwipeTo(index);
1082 }
1083
1084 layoutProperty->UpdateIndicator(index);
1085 }
1086
HandleTouchEvent(const TouchLocationInfo & info)1087 void TabBarPattern::HandleTouchEvent(const TouchLocationInfo& info)
1088 {
1089 if (IsContainsBuilder()) {
1090 return;
1091 }
1092 auto host = GetHost();
1093 CHECK_NULL_VOID(host);
1094 auto totalCount = host->TotalChildCount() - MASK_COUNT;
1095 if (totalCount < 0) {
1096 return;
1097 }
1098 auto touchType = info.GetTouchType();
1099 auto index = CalculateSelectedIndex(info.GetLocalLocation());
1100 if (touchType == TouchType::DOWN && index >= 0 && index < totalCount) {
1101 HandleTouchDown(index);
1102 touchingIndex_ = index;
1103 return;
1104 }
1105 if ((touchType == TouchType::UP || touchType == TouchType::CANCEL) && touchingIndex_.has_value()) {
1106 HandleTouchUp(index);
1107 touchingIndex_.reset();
1108 }
1109 }
1110
CalculateSelectedIndex(const Offset & info)1111 int32_t TabBarPattern::CalculateSelectedIndex(const Offset& info)
1112 {
1113 if (tabItemOffsets_.empty()) {
1114 return -1;
1115 }
1116 auto host = GetHost();
1117 CHECK_NULL_RETURN(host, -1);
1118 auto geometryNode = host->GetGeometryNode();
1119 CHECK_NULL_RETURN(geometryNode, -1);
1120 auto frameSize = geometryNode->GetFrameSize();
1121 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1122 CHECK_NULL_RETURN(layoutProperty, -1);
1123 auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1124 auto local = OffsetF(info.GetX(), info.GetY());
1125 if (axis == Axis::VERTICAL) {
1126 auto clickRange = std::make_pair(tabItemOffsets_[0].GetY(), tabItemOffsets_[tabItemOffsets_.size() - 1].GetY());
1127 if (LessNotEqual(local.GetY(), clickRange.first) || GreatNotEqual(local.GetY(), clickRange.second)) {
1128 return -1;
1129 }
1130 } else {
1131 auto clickRange = std::make_pair(tabItemOffsets_[0].GetX(), tabItemOffsets_[tabItemOffsets_.size() - 1].GetX());
1132 if (!isRTL_) {
1133 if (LessNotEqual(local.GetX(), clickRange.first) || GreatNotEqual(local.GetX(), clickRange.second)) {
1134 return -1;
1135 }
1136 } else {
1137 if (GreatNotEqual(local.GetX(), frameSize.MainSize(axis)) ||
1138 LessNotEqual(local.GetX(), clickRange.second)) {
1139 return -1;
1140 }
1141 }
1142 }
1143 auto pos = std::lower_bound(tabItemOffsets_.begin(), tabItemOffsets_.end(), local,
1144 [axis, isRTL = isRTL_](const OffsetF& a, const OffsetF& b) {
1145 return isRTL
1146 ? GreatNotEqual(a.GetX(), b.GetX())
1147 : (axis == Axis::VERTICAL ? LessNotEqual(a.GetY(), b.GetY()) : LessNotEqual(a.GetX(), b.GetX()));
1148 });
1149
1150 if (pos == tabItemOffsets_.end()) {
1151 return -1;
1152 }
1153 return isRTL_ ? std::distance(tabItemOffsets_.begin(), pos) : std::distance(tabItemOffsets_.begin(), pos) - 1;
1154 }
1155
HandleTouchDown(int32_t index)1156 void TabBarPattern::HandleTouchDown(int32_t index)
1157 {
1158 const auto& removeSwiperEventCallback = swiperController_->GetRemoveSwiperEventCallback();
1159 if (removeSwiperEventCallback) {
1160 removeSwiperEventCallback();
1161 }
1162 SetTouching(true);
1163 auto pipelineContext = PipelineContext::GetCurrentContext();
1164 CHECK_NULL_VOID(pipelineContext);
1165 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1166 CHECK_NULL_VOID(tabTheme);
1167 PlayPressAnimation(index, tabTheme->GetSubTabBarPressedColor(), AnimationType::PRESS);
1168 }
1169
HandleTouchUp(int32_t index)1170 void TabBarPattern::HandleTouchUp(int32_t index)
1171 {
1172 const auto& addSwiperEventCallback = swiperController_->GetAddSwiperEventCallback();
1173 if (addSwiperEventCallback) {
1174 addSwiperEventCallback();
1175 }
1176 auto pipelineContext = PipelineContext::GetCurrentContext();
1177 CHECK_NULL_VOID(pipelineContext);
1178 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1179 CHECK_NULL_VOID(tabTheme);
1180 if (IsTouching()) {
1181 SetTouching(false);
1182 if (hoverIndex_.has_value() && touchingIndex_.value_or(-1) == index) {
1183 PlayPressAnimation(index, tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVERTOPRESS);
1184 return;
1185 }
1186 PlayPressAnimation(touchingIndex_.value_or(-1), Color::TRANSPARENT, AnimationType::PRESS);
1187 if (hoverIndex_.has_value()) {
1188 PlayPressAnimation(hoverIndex_.value(), tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVER);
1189 }
1190 }
1191 }
1192
PlayPressAnimation(int32_t index,const Color & pressColor,AnimationType animationType)1193 void TabBarPattern::PlayPressAnimation(int32_t index, const Color& pressColor, AnimationType animationType)
1194 {
1195 auto pipelineContext = PipelineContext::GetCurrentContext();
1196 CHECK_NULL_VOID(pipelineContext);
1197 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1198 CHECK_NULL_VOID(tabTheme);
1199 AnimationOption option = AnimationOption();
1200 option.SetDuration(animationType == AnimationType::HOVERTOPRESS
1201 ? static_cast<int32_t>(tabTheme->GetSubTabBarHoverToPressDuration())
1202 : static_cast<int32_t>(tabTheme->GetSubTabBarHoverDuration()));
1203 option.SetDelay(0);
1204
1205 option.SetCurve(animationType == AnimationType::PRESS ? DurationCubicCurve
1206 : animationType == AnimationType::HOVER ? Curves::FRICTION
1207 : Curves::SHARP);
1208 option.SetFillMode(FillMode::FORWARDS);
1209 Color color = pressColor;
1210 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1211 if (color == Color::TRANSPARENT && tabBarStyles_[index] == TabBarStyle::SUBTABBATSTYLE && index == indicator_ &&
1212 selectedModes_[index] == SelectedMode::BOARD &&
1213 layoutProperty->GetAxis().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1214 color = indicatorStyles_[index].color;
1215 }
1216 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), selectedIndex = index, color = color]() {
1217 auto tabBar = weak.Upgrade();
1218 if (tabBar) {
1219 auto host = tabBar->GetHost();
1220 CHECK_NULL_VOID(host);
1221 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
1222 CHECK_NULL_VOID(columnNode);
1223 auto renderContext = columnNode->GetRenderContext();
1224 CHECK_NULL_VOID(renderContext);
1225 if (tabBar->tabBarStyles_[selectedIndex] != TabBarStyle::SUBTABBATSTYLE) {
1226 BorderRadiusProperty borderRadiusProperty;
1227 auto pipelineContext = PipelineContext::GetCurrentContext();
1228 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1229 borderRadiusProperty.SetRadius(tabTheme->GetFocusIndicatorRadius());
1230 renderContext->UpdateBorderRadius(borderRadiusProperty);
1231 }
1232 renderContext->UpdateBackgroundColor(color);
1233 columnNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1234 }
1235 }, [weak = AceType::WeakClaim(this), selectedIndex = index]() {
1236 auto tabBar = weak.Upgrade();
1237 if (tabBar) {
1238 if (tabBar->tabBarStyles_[selectedIndex] != TabBarStyle::SUBTABBATSTYLE) {
1239 auto host = tabBar->GetHost();
1240 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
1241 auto renderContext = columnNode->GetRenderContext();
1242 renderContext->ResetBorderRadius();
1243 columnNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1244 }
1245 }
1246 });
1247 }
1248
UpdateCurrentOffset(float offset)1249 void TabBarPattern::UpdateCurrentOffset(float offset)
1250 {
1251 auto host = GetHost();
1252 CHECK_NULL_VOID(host);
1253 currentOffset_ = currentOffset_ + offset;
1254 UpdateIndicator(indicator_);
1255 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1256 }
1257
UpdateIndicator(int32_t indicator)1258 void TabBarPattern::UpdateIndicator(int32_t indicator)
1259 {
1260 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1261 CHECK_NULL_VOID(layoutProperty);
1262 layoutProperty->UpdateIndicator(indicator);
1263
1264 UpdatePaintIndicator(indicator, true);
1265 }
1266
UpdateGradientRegions(bool needMarkDirty)1267 void TabBarPattern::UpdateGradientRegions(bool needMarkDirty)
1268 {
1269 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1270 CHECK_NULL_VOID(layoutProperty);
1271 auto barMode = layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED);
1272 auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1273 auto tarBarNode = GetHost();
1274 CHECK_NULL_VOID(tarBarNode);
1275 auto geometryNode = tarBarNode->GetGeometryNode();
1276 CHECK_NULL_VOID(geometryNode);
1277 auto frameRect = geometryNode->GetFrameRect();
1278
1279 std::fill(gradientRegions_.begin(), gradientRegions_.end(), false);
1280 if (barMode == TabBarMode::SCROLLABLE && !tabItemOffsets_.empty()) {
1281 if (axis == Axis::HORIZONTAL) {
1282 if (LessNotEqual(tabItemOffsets_.front().GetX() - GetLeftPadding(), scrollMargin_)) {
1283 gradientRegions_[LEFT_GRADIENT] = true;
1284 }
1285 if (GreatNotEqual(tabItemOffsets_.back().GetX() + scrollMargin_, frameRect.Width() - GetLeftPadding())) {
1286 gradientRegions_[RIGHT_GRADIENT] = true;
1287 }
1288 } else if (axis == Axis::VERTICAL) {
1289 if (LessNotEqual(tabItemOffsets_.front().GetY(), 0.0f)) {
1290 gradientRegions_[TOP_GRADIENT] = true;
1291 }
1292 if (GreatNotEqual(tabItemOffsets_.front().GetY() + childrenMainSize_, frameRect.Height())) {
1293 gradientRegions_[BOTTOM_GRADIENT] = true;
1294 }
1295 }
1296 }
1297
1298 if (needMarkDirty) {
1299 tarBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1300 }
1301 }
1302
UpdateTextColorAndFontWeight(int32_t indicator)1303 void TabBarPattern::UpdateTextColorAndFontWeight(int32_t indicator)
1304 {
1305 auto tabBarNode = GetHost();
1306 CHECK_NULL_VOID(tabBarNode);
1307 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1308 CHECK_NULL_VOID(tabBarPattern);
1309 if (tabBarPattern->IsContainsBuilder()) {
1310 return;
1311 }
1312 auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(indicator));
1313 CHECK_NULL_VOID(columnNode);
1314 auto selectedColumnId = columnNode->GetId();
1315 auto pipelineContext = PipelineContext::GetCurrentContext();
1316 CHECK_NULL_VOID(pipelineContext);
1317 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1318 CHECK_NULL_VOID(tabTheme);
1319 int32_t index = 0;
1320 for (const auto& columnNode : tabBarNode->GetChildren()) {
1321 CHECK_NULL_VOID(columnNode);
1322 auto textNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().back());
1323 CHECK_NULL_VOID(textNode);
1324 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1325 CHECK_NULL_VOID(textLayoutProperty);
1326 auto isSelected = columnNode->GetId() == selectedColumnId;
1327 textLayoutProperty->UpdateTextColor(isSelected ? tabTheme->GetSubTabTextOnColor()
1328 : tabTheme->GetSubTabTextOffColor());
1329 if (IsNeedUpdateFontWeight(index)) {
1330 textLayoutProperty->UpdateFontWeight(isSelected ? FontWeight::MEDIUM : FontWeight::NORMAL);
1331 }
1332 textNode->MarkModifyDone();
1333 textNode->MarkDirtyNode();
1334 index++;
1335 }
1336 }
1337
IsNeedUpdateFontWeight(int32_t index)1338 bool TabBarPattern::IsNeedUpdateFontWeight(int32_t index)
1339 {
1340 if (index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size()) ||
1341 tabBarStyles_[index] != TabBarStyle::SUBTABBATSTYLE) {
1342 return false;
1343 }
1344 if (index >= static_cast<int32_t>(labelStyles_.size()) || labelStyles_[index].fontWeight.has_value()) {
1345 return false;
1346 }
1347 return true;
1348 }
1349
UpdateImageColor(int32_t indicator)1350 void TabBarPattern::UpdateImageColor(int32_t indicator)
1351 {
1352 auto tabBarNode = GetHost();
1353 CHECK_NULL_VOID(tabBarNode);
1354 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1355 CHECK_NULL_VOID(tabBarPattern);
1356 if (tabBarPattern->IsContainsBuilder()) {
1357 return;
1358 }
1359 auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(indicator));
1360 CHECK_NULL_VOID(columnNode);
1361 auto selectedColumnId = columnNode->GetId();
1362 auto pipelineContext = PipelineContext::GetCurrentContext();
1363 CHECK_NULL_VOID(pipelineContext);
1364 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1365 CHECK_NULL_VOID(tabTheme);
1366 for (const auto& columnNode : tabBarNode->GetChildren()) {
1367 CHECK_NULL_VOID(columnNode);
1368 auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
1369 CHECK_NULL_VOID(imageNode);
1370
1371 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1372 CHECK_NULL_VOID(imageLayoutProperty);
1373 ImageSourceInfo info;
1374 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
1375 imageSourceInfo.SetFillColor(columnNode->GetId() == selectedColumnId ? tabTheme->GetBottomTabIconOn() :
1376 tabTheme->GetBottomTabIconOff());
1377 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1378 imageNode->MarkModifyDone();
1379 imageNode->MarkDirtyNode();
1380 }
1381 SetImageColorOnIndex(indicator);
1382 }
1383
UpdateSubTabBoard()1384 void TabBarPattern::UpdateSubTabBoard()
1385 {
1386 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1387 CHECK_NULL_VOID(layoutProperty);
1388 auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1389
1390 if (indicator_ >= static_cast<int32_t>(indicatorStyles_.size()) ||
1391 indicator_ >= static_cast<int32_t>(selectedModes_.size())) {
1392 return;
1393 }
1394 auto tabBarNode = GetHost();
1395 CHECK_NULL_VOID(tabBarNode);
1396 auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
1397 CHECK_NULL_VOID(paintProperty);
1398 auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(indicator_));
1399 CHECK_NULL_VOID(columnNode);
1400 auto selectedColumnId = columnNode->GetId();
1401
1402 for (const auto& columnNode : tabBarNode->GetChildren()) {
1403 CHECK_NULL_VOID(columnNode);
1404 auto columnFrameNode = AceType::DynamicCast<FrameNode>(columnNode);
1405 auto renderContext = columnFrameNode->GetRenderContext();
1406 CHECK_NULL_VOID(renderContext);
1407 if (tabBarStyles_[indicator_] == TabBarStyle::SUBTABBATSTYLE) {
1408 if (selectedModes_[indicator_] == SelectedMode::BOARD && columnFrameNode->GetId() == selectedColumnId &&
1409 axis == Axis::HORIZONTAL) {
1410 renderContext->UpdateBackgroundColor(indicatorStyles_[indicator_].color);
1411 } else {
1412 renderContext->UpdateBackgroundColor(Color::BLACK.BlendOpacity(0.0f));
1413 }
1414 columnFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1415 }
1416 }
1417 }
1418
GetSelectedMode() const1419 SelectedMode TabBarPattern::GetSelectedMode() const
1420 {
1421 if (indicator_ >= static_cast<int32_t>(selectedModes_.size())) {
1422 return SelectedMode::INDICATOR;
1423 } else {
1424 return selectedModes_[indicator_];
1425 }
1426 }
1427
IsContainsBuilder()1428 bool TabBarPattern::IsContainsBuilder()
1429 {
1430 return std::any_of(tabBarType_.begin(), tabBarType_.end(), [](const auto& isBuilder) { return isBuilder.second; });
1431 }
1432
TriggerTranslateAnimation(const RefPtr<TabBarLayoutProperty> & layoutProperty,int32_t index,int32_t indicator)1433 void TabBarPattern::TriggerTranslateAnimation(
1434 const RefPtr<TabBarLayoutProperty>& layoutProperty, int32_t index, int32_t indicator)
1435 {
1436 auto host = GetHost();
1437 CHECK_NULL_VOID(host);
1438 auto originalPaintRect = layoutProperty->GetIndicatorRect(indicator);
1439 auto targetPaintRect = layoutProperty->GetIndicatorRect(index);
1440 auto paintProperty = host->GetPaintProperty<TabBarPaintProperty>();
1441 CHECK_NULL_VOID(paintProperty);
1442 paintProperty->UpdateIndicator(targetPaintRect);
1443 float targetOffset = 0.0f;
1444 if (host->GetGeometryNode()->GetPaddingSize().Width() < childrenMainSize_ &&
1445 layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
1446 auto space = GetSpace(index);
1447 float frontChildrenMainSize = CalculateFrontChildrenMainSize(index);
1448 float backChildrenMainSize = CalculateBackChildrenMainSize(index);
1449 targetOffset = space < 0.0f ? -frontChildrenMainSize
1450 : frontChildrenMainSize < space ? 0.0f
1451 : backChildrenMainSize < space
1452 ? host->GetGeometryNode()->GetPaddingSize().Width() - childrenMainSize_
1453 : space - frontChildrenMainSize;
1454 if (tabItemOffsets_.empty()) {
1455 return;
1456 }
1457 PlayTranslateAnimation(originalPaintRect.GetX() + originalPaintRect.Width() / 2,
1458 targetPaintRect.GetX() + targetPaintRect.Width() / 2 - tabItemOffsets_.front().GetX() + scrollMargin_ +
1459 targetOffset + GetLeftPadding(),
1460 targetOffset);
1461 } else {
1462 PlayTranslateAnimation(originalPaintRect.GetX() + originalPaintRect.Width() / 2,
1463 targetPaintRect.GetX() + targetPaintRect.Width() / 2, targetOffset);
1464 }
1465 swiperStartIndex_ = indicator;
1466 animationTargetIndex_ = index;
1467 UpdateTextColorAndFontWeight(index);
1468 }
1469
PlayTranslateAnimation(float startPos,float endPos,float targetCurrentOffset)1470 void TabBarPattern::PlayTranslateAnimation(float startPos, float endPos, float targetCurrentOffset)
1471 {
1472 auto curve = DurationCubicCurve;
1473 isAnimating_ = true;
1474 StopTranslateAnimation();
1475 SetSwiperCurve(curve);
1476 auto pipelineContext = PipelineContext::GetCurrentContext();
1477 CHECK_NULL_VOID(pipelineContext);
1478 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1479 CHECK_NULL_VOID(tabTheme);
1480 AnimationOption option = AnimationOption();
1481 option.SetDuration(static_cast<int32_t>(GetAnimationDuration().value_or(
1482 tabTheme->GetTabContentAnimationDuration())));
1483 option.SetCurve(curve);
1484 option.SetFillMode(FillMode::FORWARDS);
1485
1486 auto weak = AceType::WeakClaim(this);
1487 const auto& pattern = weak.Upgrade();
1488 auto host = pattern->GetHost();
1489 indicatorStartPos_ = startPos;
1490 indicatorEndPos_ = endPos;
1491 turnPageRate_ = 0.0f;
1492
1493 host->CreateAnimatablePropertyFloat("tabbarindicator", 0, [weak](float value) {
1494 auto tabBarPattern = weak.Upgrade();
1495 CHECK_NULL_VOID(tabBarPattern);
1496 if (!tabBarPattern->isAnimating_ ||
1497 NearZero(tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_)) {
1498 return;
1499 }
1500 tabBarPattern->turnPageRate_ = (value - tabBarPattern->indicatorStartPos_) /
1501 (tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_);
1502 tabBarPattern->UpdateIndicatorCurrentOffset(static_cast<float>(value - tabBarPattern->currentIndicatorOffset_));
1503 });
1504 host->UpdateAnimatablePropertyFloat("tabbarindicator", startPos);
1505 auto delta = endPos;
1506 indicatorAnimationIsRunning_ = true;
1507 tabbarIndicatorAnimation_ = AnimationUtils::StartAnimation(option,
1508 [host, delta]() {
1509 host->UpdateAnimatablePropertyFloat("tabbarindicator", delta);
1510 },
1511 [weak]() {
1512 auto tabBarPattern = weak.Upgrade();
1513 CHECK_NULL_VOID(tabBarPattern);
1514 tabBarPattern->indicatorAnimationIsRunning_ = false;
1515 });
1516
1517 auto startCurrentOffset = currentOffset_;
1518 host->CreateAnimatablePropertyFloat("tabbar", 0, [weak](float value) {
1519 auto tabBarPattern = weak.Upgrade();
1520 CHECK_NULL_VOID(tabBarPattern);
1521 tabBarPattern->currentOffset_ = value;
1522 auto host = tabBarPattern->GetHost();
1523 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1524 });
1525 host->UpdateAnimatablePropertyFloat("tabbar", startCurrentOffset);
1526 delta = targetCurrentOffset;
1527 translateAnimationIsRunning_ = true;
1528 translateAnimation_ = AnimationUtils::StartAnimation(option,
1529 [host, delta]() {
1530 host->UpdateAnimatablePropertyFloat("tabbar", delta);
1531 },
1532 [weak]() {
1533 auto tabBarPattern = weak.Upgrade();
1534 CHECK_NULL_VOID(tabBarPattern);
1535 tabBarPattern->translateAnimationIsRunning_ = false;
1536 });
1537 }
1538
StopTranslateAnimation()1539 void TabBarPattern::StopTranslateAnimation()
1540 {
1541 if (translateAnimation_)
1542 AnimationUtils::StopAnimation(translateAnimation_);
1543
1544 if (tabbarIndicatorAnimation_)
1545 AnimationUtils::StopAnimation(tabbarIndicatorAnimation_);
1546
1547 if (indicatorAnimationIsRunning_)
1548 indicatorAnimationIsRunning_ = false;
1549
1550 if (translateAnimationIsRunning_)
1551 translateAnimationIsRunning_ = false;
1552 }
1553
PlayTabBarTranslateAnimation(int32_t targetIndex)1554 void TabBarPattern::PlayTabBarTranslateAnimation(int32_t targetIndex)
1555 {
1556 StopTabBarTranslateAnimation();
1557 auto host = GetHost();
1558 CHECK_NULL_VOID(host);
1559 if (host->GetGeometryNode()->GetPaddingSize().Width() >= childrenMainSize_) {
1560 return;
1561 }
1562 auto space = GetSpace(targetIndex);
1563 float frontChildrenMainSize = CalculateFrontChildrenMainSize(targetIndex);
1564 float backChildrenMainSize = CalculateBackChildrenMainSize(targetIndex);
1565 auto targetOffset = space < 0.0f ? -frontChildrenMainSize
1566 : frontChildrenMainSize < space ? 0.0f
1567 : backChildrenMainSize < space
1568 ? host->GetGeometryNode()->GetPaddingSize().Width() - childrenMainSize_
1569 : space - frontChildrenMainSize;
1570 auto startOffset = currentOffset_;
1571
1572 auto pipelineContext = PipelineContext::GetCurrentContext();
1573 CHECK_NULL_VOID(pipelineContext);
1574 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1575 CHECK_NULL_VOID(tabTheme);
1576 auto curve = DurationCubicCurve;
1577 AnimationOption option = AnimationOption();
1578 option.SetDuration(static_cast<int32_t>(GetAnimationDuration().value_or(
1579 tabTheme->GetTabContentAnimationDuration())));
1580 option.SetCurve(curve);
1581
1582 auto weak = AceType::WeakClaim(this);
1583 host->CreateAnimatablePropertyFloat("tabbar", 0, [weak, startOffset, targetOffset](float value) {
1584 auto tabBarPattern = weak.Upgrade();
1585 CHECK_NULL_VOID(tabBarPattern);
1586 tabBarPattern->currentOffset_ = value;
1587 auto host = tabBarPattern->GetHost();
1588 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1589 });
1590 host->UpdateAnimatablePropertyFloat("tabbar", startOffset);
1591 auto delta = targetOffset;
1592 tabBarTranslateAnimationIsRunning_ = true;
1593 tabBarTranslateAnimation_ = AnimationUtils::StartAnimation(option,
1594 [host, delta]() {
1595 host->UpdateAnimatablePropertyFloat("tabbar", delta);
1596 },
1597 [weak]() {
1598 auto tabBarPattern = weak.Upgrade();
1599 CHECK_NULL_VOID(tabBarPattern);
1600 tabBarPattern->tabBarTranslateAnimationIsRunning_ = false;
1601 });
1602 }
1603
StopTabBarTranslateAnimation()1604 void TabBarPattern::StopTabBarTranslateAnimation()
1605 {
1606 if (tabBarTranslateAnimation_)
1607 AnimationUtils::StopAnimation(tabBarTranslateAnimation_);
1608
1609 if (tabBarTranslateAnimationIsRunning_)
1610 tabBarTranslateAnimationIsRunning_ = false;
1611 }
1612
UpdateIndicatorCurrentOffset(float offset)1613 void TabBarPattern::UpdateIndicatorCurrentOffset(float offset)
1614 {
1615 currentIndicatorOffset_ = currentIndicatorOffset_ + offset;
1616 auto host = GetHost();
1617 CHECK_NULL_VOID(host);
1618 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1619 }
1620
CreateNodePaintMethod()1621 RefPtr<NodePaintMethod> TabBarPattern::CreateNodePaintMethod()
1622 {
1623 if (indicator_ < 0 || indicator_ >= static_cast<int32_t>(indicatorStyles_.size()) ||
1624 indicator_ >= static_cast<int32_t>(selectedModes_.size())) {
1625 return nullptr;
1626 }
1627 Color backgroundColor = Color::WHITE;
1628 auto tabBarNode = GetHost();
1629 CHECK_NULL_RETURN(tabBarNode, nullptr);
1630 auto tabBarRenderContext = tabBarNode->GetRenderContext();
1631 CHECK_NULL_RETURN(tabBarRenderContext, nullptr);
1632 if (tabBarRenderContext->GetBackgroundColor().has_value()) {
1633 backgroundColor = tabBarRenderContext->GetBackgroundColor().value();
1634 } else {
1635 auto tabsNode = AceType::DynamicCast<FrameNode>(tabBarNode->GetParent());
1636 CHECK_NULL_RETURN(tabsNode, nullptr);
1637 auto tabsRenderContext = tabsNode->GetRenderContext();
1638 CHECK_NULL_RETURN(tabsRenderContext, nullptr);
1639 backgroundColor = tabsRenderContext->GetBackgroundColor().value_or(Color::WHITE);
1640 }
1641 if (!tabBarModifier_) {
1642 tabBarModifier_ = AceType::MakeRefPtr<TabBarModifier>();
1643 }
1644
1645 IndicatorStyle indicatorStyle;
1646 GetIndicatorStyle(indicatorStyle);
1647
1648 return MakeRefPtr<TabBarPaintMethod>(tabBarModifier_, gradientRegions_, backgroundColor, indicatorStyle,
1649 currentIndicatorOffset_, selectedModes_[indicator_]);
1650 }
1651
GetIndicatorStyle(IndicatorStyle & indicatorStyle)1652 void TabBarPattern::GetIndicatorStyle(IndicatorStyle& indicatorStyle)
1653 {
1654 if (indicator_ < 0 || indicator_ >= static_cast<int32_t>(indicatorStyles_.size())) {
1655 return;
1656 }
1657 indicatorStyle = indicatorStyles_[indicator_];
1658
1659 auto host = GetHost();
1660 CHECK_NULL_VOID(host);
1661 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1662 CHECK_NULL_VOID(layoutProperty);
1663
1664 if (NonPositive(indicatorStyle.width.Value())) {
1665 indicatorStyle.width = Dimension(layoutProperty->GetIndicatorRect(indicator_).Width());
1666 }
1667
1668 if ((!isTouchingSwiper_ && !isAnimating_) || axis_ != Axis::HORIZONTAL) {
1669 return;
1670 }
1671
1672 if (LessOrEqual(turnPageRate_, 0.0f)) {
1673 turnPageRate_ = 0.0f;
1674 }
1675 if (GreatOrEqual(turnPageRate_, 1.0f)) {
1676 turnPageRate_ = 1.0f;
1677 }
1678
1679 if (swiperStartIndex_ < 0 || swiperStartIndex_ >= static_cast<int32_t>(tabBarStyles_.size()) ||
1680 tabBarStyles_[swiperStartIndex_] != TabBarStyle::SUBTABBATSTYLE ||
1681 swiperStartIndex_ >= static_cast<int32_t>(selectedModes_.size()) ||
1682 selectedModes_[swiperStartIndex_] != SelectedMode::INDICATOR ||
1683 swiperStartIndex_ >= static_cast<int32_t>(indicatorStyles_.size())) {
1684 return;
1685 }
1686
1687 auto nextIndex = isTouchingSwiper_ ? swiperStartIndex_ + 1 : animationTargetIndex_.value_or(-1);
1688 if (nextIndex < 0 || nextIndex >= static_cast<int32_t>(tabBarStyles_.size()) ||
1689 tabBarStyles_[nextIndex] != TabBarStyle::SUBTABBATSTYLE ||
1690 nextIndex >= static_cast<int32_t>(selectedModes_.size()) ||
1691 selectedModes_[nextIndex] != SelectedMode::INDICATOR ||
1692 nextIndex >= static_cast<int32_t>(indicatorStyles_.size())) {
1693 return;
1694 }
1695
1696 indicatorStyle = indicatorStyles_[swiperStartIndex_];
1697
1698 if (NonPositive(indicatorStyle.width.Value())) {
1699 indicatorStyle.width = Dimension(layoutProperty->GetIndicatorRect(swiperStartIndex_).Width());
1700 }
1701
1702 IndicatorStyle nextIndicatorStyle = indicatorStyles_[nextIndex];
1703 if (NonPositive(nextIndicatorStyle.width.Value())) {
1704 nextIndicatorStyle.width = Dimension(layoutProperty->GetIndicatorRect(nextIndex).Width());
1705 }
1706 indicatorStyle.width =
1707 Dimension(indicatorStyle.width.ConvertToPx() +
1708 (nextIndicatorStyle.width.ConvertToPx() - indicatorStyle.width.ConvertToPx()) * turnPageRate_);
1709 indicatorStyle.marginTop = Dimension(
1710 indicatorStyle.marginTop.ConvertToPx() +
1711 (nextIndicatorStyle.marginTop.ConvertToPx() - indicatorStyle.marginTop.ConvertToPx()) * turnPageRate_);
1712 indicatorStyle.height =
1713 Dimension(indicatorStyle.height.ConvertToPx() +
1714 (nextIndicatorStyle.height.ConvertToPx() - indicatorStyle.height.ConvertToPx()) * turnPageRate_);
1715 LinearColor color = LinearColor(indicatorStyle.color) +
1716 (LinearColor(nextIndicatorStyle.color) - LinearColor(indicatorStyle.color)) * turnPageRate_;
1717 indicatorStyle.color = color.ToColor();
1718 }
1719
GetSpace(int32_t indicator)1720 float TabBarPattern::GetSpace(int32_t indicator)
1721 {
1722 auto host = GetHost();
1723 CHECK_NULL_RETURN(host, 0.0f);
1724 auto geometryNode = host->GetGeometryNode();
1725 auto childFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(indicator));
1726 CHECK_NULL_RETURN(childFrameNode, 0.0f);
1727 auto childGeometryNode = childFrameNode->GetGeometryNode();
1728
1729 return (geometryNode->GetPaddingSize().MainSize(axis_) - childGeometryNode->GetMarginFrameSize().MainSize(axis_)) /
1730 2;
1731 }
1732
CalculateFrontChildrenMainSize(int32_t indicator)1733 float TabBarPattern::CalculateFrontChildrenMainSize(int32_t indicator)
1734 {
1735 auto host = GetHost();
1736 CHECK_NULL_RETURN(host, 0.0f);
1737 float frontChildrenMainSize = scrollMargin_;
1738 for (int32_t index = 0; index < indicator; ++index) {
1739 auto childFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1740 CHECK_NULL_RETURN(childFrameNode, 0.0f);
1741 auto childGeometryNode = childFrameNode->GetGeometryNode();
1742 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
1743 frontChildrenMainSize += childFrameSize.MainSize(axis_);
1744 }
1745 return indicator == 0 ? 0.0f : frontChildrenMainSize;
1746 }
1747
CalculateBackChildrenMainSize(int32_t indicator)1748 float TabBarPattern::CalculateBackChildrenMainSize(int32_t indicator)
1749 {
1750 auto host = GetHost();
1751 CHECK_NULL_RETURN(host, 0.0f);
1752 float backChildrenMainSize = scrollMargin_;
1753 auto childCount = host->GetChildren().size() - MASK_COUNT;
1754 for (uint32_t index = static_cast<uint32_t>(indicator) + 1; index < childCount; ++index) {
1755 auto childFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1756 CHECK_NULL_RETURN(childFrameNode, 0.0f);
1757 auto childGeometryNode = childFrameNode->GetGeometryNode();
1758 auto childFrameSize = childGeometryNode->GetMarginFrameSize();
1759 backChildrenMainSize += childFrameSize.MainSize(axis_);
1760 }
1761 return indicator == static_cast<int32_t>(childCount - 1) ? 0.0f : backChildrenMainSize;
1762 }
1763
SetEdgeEffect(const RefPtr<GestureEventHub> & gestureHub)1764 void TabBarPattern::SetEdgeEffect(const RefPtr<GestureEventHub>& gestureHub)
1765 {
1766 CHECK_NULL_VOID(gestureHub);
1767 if (scrollEffect_) {
1768 gestureHub->RemoveScrollEdgeEffect(scrollEffect_);
1769 scrollEffect_.Reset();
1770 }
1771 if (!scrollEffect_) {
1772 auto springEffect = AceType::MakeRefPtr<ScrollSpringEffect>();
1773 CHECK_NULL_VOID(springEffect);
1774 springEffect->SetOutBoundaryCallback([weak = AceType::WeakClaim(this)]() {
1775 auto pattern = weak.Upgrade();
1776 CHECK_NULL_RETURN(pattern, false);
1777 return pattern->IsAtTop() || pattern->IsAtBottom();
1778 });
1779 // add callback to springEdgeEffect
1780 SetEdgeEffectCallback(springEffect);
1781 scrollEffect_ = springEffect;
1782 gestureHub->AddScrollEdgeEffect(axis_, scrollEffect_);
1783 }
1784 }
1785
SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)1786 void TabBarPattern::SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect)
1787 {
1788 scrollEffect->SetCurrentPositionCallback([weak = AceType::WeakClaim(this)]() -> double {
1789 auto tabBar = weak.Upgrade();
1790 CHECK_NULL_RETURN(tabBar, 0.0);
1791 return tabBar->tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE ? tabBar->currentOffset_ : 0.0;
1792 });
1793 scrollEffect->SetLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1794 auto tabBar = weak.Upgrade();
1795 auto host = tabBar->GetHost();
1796 return host->GetGeometryNode()->GetPaddingSize().Width() - tabBar->childrenMainSize_;
1797 });
1798 scrollEffect->SetTrailingCallback([]() -> double { return 0.0; });
1799 scrollEffect->SetInitLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1800 auto tabBar = weak.Upgrade();
1801 auto host = tabBar->GetHost();
1802 return host->GetGeometryNode()->GetPaddingSize().Width() - tabBar->childrenMainSize_;
1803 });
1804 scrollEffect->SetInitTrailingCallback([]() -> double { return 0.0; });
1805 }
1806
IsAtTop() const1807 bool TabBarPattern::IsAtTop() const
1808 {
1809 return NonNegative(currentOffset_);
1810 }
1811
IsAtBottom() const1812 bool TabBarPattern::IsAtBottom() const
1813 {
1814 if (tabItemOffsets_.empty()) {
1815 return false;
1816 }
1817 auto host = GetHost();
1818 CHECK_NULL_RETURN(host, false);
1819 return LessOrEqual(tabItemOffsets_.back().GetX() + scrollMargin_,
1820 host->GetGeometryNode()->GetPaddingSize().Width() + GetLeftPadding());
1821 }
1822
IsOutOfBoundary()1823 bool TabBarPattern::IsOutOfBoundary()
1824 {
1825 if (tabItemOffsets_.empty()) {
1826 return false;
1827 }
1828 auto host = GetHost();
1829 CHECK_NULL_RETURN(host, false);
1830 auto geometryNode = host->GetGeometryNode();
1831 CHECK_NULL_RETURN(geometryNode, false);
1832
1833 auto mainSize = geometryNode->GetPaddingSize().Width();
1834 bool outOfStart = Positive(tabItemOffsets_.front().GetX() - scrollMargin_ - GetLeftPadding()) &&
1835 GreatNotEqual(tabItemOffsets_.back().GetX() + scrollMargin_, mainSize + GetLeftPadding());
1836 bool outOfEnd = LessNotEqual(tabItemOffsets_.back().GetX() + scrollMargin_, mainSize + GetLeftPadding()) &&
1837 Negative(tabItemOffsets_.front().GetX() - scrollMargin_ - GetLeftPadding());
1838 return outOfStart || outOfEnd;
1839 }
1840
SetAccessibilityAction()1841 void TabBarPattern::SetAccessibilityAction()
1842 {
1843 auto host = GetHost();
1844 CHECK_NULL_VOID(host);
1845 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1846 CHECK_NULL_VOID(accessibilityProperty);
1847 accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1848 const auto& pattern = weakPtr.Upgrade();
1849 CHECK_NULL_VOID(pattern);
1850 auto tabBarLayoutProperty = pattern->GetLayoutProperty<TabBarLayoutProperty>();
1851 CHECK_NULL_VOID(tabBarLayoutProperty);
1852 auto frameNode = pattern->GetHost();
1853 CHECK_NULL_VOID(frameNode);
1854 if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
1855 frameNode->TotalChildCount() - MASK_COUNT > 1) {
1856 auto index = pattern->GetIndicator() + 1;
1857 pattern->FocusIndexChange(index);
1858 // AccessibilityEventType::SCROLL_END
1859 }
1860 });
1861
1862 accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
1863 const auto& pattern = weakPtr.Upgrade();
1864 CHECK_NULL_VOID(pattern);
1865 auto tabBarLayoutProperty = pattern->GetLayoutProperty<TabBarLayoutProperty>();
1866 CHECK_NULL_VOID(tabBarLayoutProperty);
1867 auto frameNode = pattern->GetHost();
1868 CHECK_NULL_VOID(frameNode);
1869 if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
1870 frameNode->TotalChildCount() - MASK_COUNT > 1) {
1871 auto index = pattern->GetIndicator() - 1;
1872 pattern->FocusIndexChange(index);
1873 // AccessibilityEventType::SCROLL_END
1874 }
1875 });
1876 }
1877
ProvideRestoreInfo()1878 std::string TabBarPattern::ProvideRestoreInfo()
1879 {
1880 auto jsonObj = JsonUtil::Create(true);
1881 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1882 CHECK_NULL_RETURN(tabBarLayoutProperty, "");
1883 jsonObj->Put("Index", tabBarLayoutProperty->GetIndicator().value_or(0));
1884 return jsonObj->ToString();
1885 }
1886
OnRestoreInfo(const std::string & restoreInfo)1887 void TabBarPattern::OnRestoreInfo(const std::string& restoreInfo)
1888 {
1889 auto host = GetHost();
1890 CHECK_NULL_VOID(host);
1891 auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1892 CHECK_NULL_VOID(tabBarLayoutProperty);
1893 auto info = JsonUtil::ParseJsonString(restoreInfo);
1894 if (!info->IsValid() || !info->IsObject()) {
1895 return;
1896 }
1897 auto jsonIsOn = info->GetValue("Index");
1898 auto index = jsonIsOn->GetInt();
1899 auto totalCount = host->TotalChildCount();
1900 if (index < 0 || index >= totalCount || !swiperController_ ||
1901 indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
1902 return;
1903 }
1904 tabBarLayoutProperty->UpdateIndicator(index);
1905 if (GetAnimationDuration().has_value()) {
1906 swiperController_->SwipeTo(index);
1907 } else {
1908 swiperController_->SwipeToWithoutAnimation(index);
1909 }
1910 }
1911
ToJsonValue(std::unique_ptr<JsonValue> & json) const1912 void TabBarPattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
1913 {
1914 Pattern::ToJsonValue(json);
1915 auto selectedModes = JsonUtil::CreateArray(true);
1916 for (const auto& selectedMode : selectedModes_) {
1917 auto mode = JsonUtil::Create(true);
1918 mode->Put("mode", selectedMode == SelectedMode::INDICATOR ? "INDICATOR" : "BOARD");
1919 selectedModes->Put(mode);
1920 }
1921 json->Put("selectedModes", selectedModes->ToString().c_str());
1922
1923 auto indicatorStyles = JsonUtil::CreateArray(true);
1924 for (const auto& indicatorStyle : indicatorStyles_) {
1925 auto indicator = JsonUtil::Create(true);
1926 indicator->Put("color", indicatorStyle.color.ColorToString().c_str());
1927 indicator->Put("height", indicatorStyle.height.ToString().c_str());
1928 indicator->Put("width", indicatorStyle.width.ToString().c_str());
1929 indicator->Put("borderRadius", indicatorStyle.borderRadius.ToString().c_str());
1930 indicator->Put("marginTop", indicatorStyle.marginTop.ToString().c_str());
1931 indicatorStyles->Put(indicator);
1932 }
1933 json->Put("indicatorStyles", indicatorStyles->ToString().c_str());
1934
1935 auto tabBarStyles = JsonUtil::CreateArray(true);
1936 for (const auto& tabBarStyle : tabBarStyles_) {
1937 auto style = JsonUtil::Create(true);
1938 style->Put("style", tabBarStyle == TabBarStyle::NOSTYLE ? "NOSTYLE"
1939 : tabBarStyle == TabBarStyle::SUBTABBATSTYLE ? "SUBTABBATSTYLE"
1940 : "BOTTOMTABBATSTYLE");
1941 tabBarStyles->Put(style);
1942 }
1943 json->Put("tabBarStyles", tabBarStyles->ToString().c_str());
1944 }
1945
FromJson(const std::unique_ptr<JsonValue> & json)1946 void TabBarPattern::FromJson(const std::unique_ptr<JsonValue>& json)
1947 {
1948 auto selectedModes = JsonUtil::ParseJsonString(json->GetString("selectedModes"));
1949 for (int32_t i = 0; i < selectedModes->GetArraySize(); i++) {
1950 auto selectedMode = selectedModes->GetArrayItem(i);
1951 auto mode = selectedMode->GetString("mode");
1952 SetSelectedMode(mode == "INDICATOR" ? SelectedMode::INDICATOR : SelectedMode::BOARD, i);
1953 }
1954
1955 auto indicatorStyles = JsonUtil::ParseJsonString(json->GetString("indicatorStyles"));
1956 for (int32_t i = 0; i < indicatorStyles->GetArraySize(); i++) {
1957 auto indicatorStyle = indicatorStyles->GetArrayItem(i);
1958 IndicatorStyle style;
1959 style.color = Color::ColorFromString(indicatorStyle->GetString("color"));
1960 style.height = Dimension::FromString(indicatorStyle->GetString("height"));
1961 style.width = Dimension::FromString(indicatorStyle->GetString("width"));
1962 style.borderRadius = Dimension::FromString(indicatorStyle->GetString("borderRadius"));
1963 style.marginTop = Dimension::FromString(indicatorStyle->GetString("marginTop"));
1964 SetIndicatorStyle(style, i);
1965 }
1966
1967 auto tabBarStyles = JsonUtil::ParseJsonString(json->GetString("tabBarStyles"));
1968 for (int32_t i = 0; i < tabBarStyles->GetArraySize(); i++) {
1969 auto tabBarStyle = tabBarStyles->GetArrayItem(i);
1970 auto style = tabBarStyle->GetString("style");
1971 SetTabBarStyle(style == "NOSTYLE" ? TabBarStyle::NOSTYLE
1972 : style == "SUBTABBATSTYLE" ? TabBarStyle::SUBTABBATSTYLE
1973 : TabBarStyle::BOTTOMTABBATSTYLE,
1974 i);
1975 }
1976
1977 auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1978 CHECK_NULL_VOID(layoutProperty);
1979 auto indicatorValue = layoutProperty->GetIndicatorValue(0);
1980 UpdateIndicator(indicatorValue);
1981 Pattern::FromJson(json);
1982 }
1983
AdjustFocusPosition()1984 void TabBarPattern::AdjustFocusPosition()
1985 {
1986 auto host = GetHost();
1987 CHECK_NULL_VOID(host);
1988 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1989 CHECK_NULL_VOID(layoutProperty);
1990 if (focusIndicator_ < 0 || static_cast<uint32_t>(focusIndicator_ + 1) >= tabItemOffsets_.size() ||
1991 layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) != TabBarMode::SCROLLABLE) {
1992 return;
1993 }
1994 if (axis_ == Axis::HORIZONTAL) {
1995 auto mainSize = host->GetGeometryNode()->GetPaddingSize().Width();
1996 if (LessNotEqual(tabItemOffsets_[focusIndicator_].GetX(), GetLeftPadding())) {
1997 currentOffset_ -= tabItemOffsets_[focusIndicator_].GetX() - GetLeftPadding();
1998 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1999 } else if (GreatNotEqual(tabItemOffsets_[focusIndicator_ + 1].GetX(), mainSize + GetLeftPadding())) {
2000 currentOffset_ += mainSize + GetLeftPadding() - tabItemOffsets_[focusIndicator_ + 1].GetX();
2001 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
2002 }
2003 } else {
2004 auto mainSize = host->GetGeometryNode()->GetPaddingSize().Height();
2005 if (LessNotEqual(tabItemOffsets_[focusIndicator_].GetY(), 0.0f)) {
2006 currentOffset_ -= tabItemOffsets_[focusIndicator_].GetY();
2007 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
2008 } else if (GreatNotEqual(tabItemOffsets_[focusIndicator_ + 1].GetY(), mainSize)) {
2009 currentOffset_ += mainSize - tabItemOffsets_[focusIndicator_ + 1].GetY();
2010 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
2011 }
2012 }
2013 }
2014
TabBarClickEvent(int32_t index) const2015 void TabBarPattern::TabBarClickEvent(int32_t index) const
2016 {
2017 auto host = GetHost();
2018 CHECK_NULL_VOID(host);
2019 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2020 CHECK_NULL_VOID(tabsNode);
2021 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
2022 CHECK_NULL_VOID(tabsPattern);
2023 auto tabBarClickEvent = tabsPattern->GetTabBarClickEvent();
2024 CHECK_NULL_VOID(tabBarClickEvent);
2025 auto event = *tabBarClickEvent;
2026 event(index);
2027 }
2028
2029
OnCustomContentTransition(int32_t fromIndex,int32_t toIndex)2030 void TabBarPattern::OnCustomContentTransition(int32_t fromIndex, int32_t toIndex)
2031 {
2032 auto host = GetHost();
2033 CHECK_NULL_VOID(host);
2034 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2035 CHECK_NULL_VOID(tabsNode);
2036 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
2037 CHECK_NULL_VOID(tabsPattern);
2038 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2039 CHECK_NULL_VOID(swiperNode);
2040 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
2041 CHECK_NULL_VOID(swiperPattern);
2042
2043 swiperPattern->OnCustomContentTransition(toIndex);
2044 }
2045
CheckSwiperDisable() const2046 bool TabBarPattern::CheckSwiperDisable() const
2047 {
2048 auto host = GetHost();
2049 CHECK_NULL_RETURN(host, true);
2050 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2051 CHECK_NULL_RETURN(tabsNode, true);
2052 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2053 CHECK_NULL_RETURN(swiperNode, true);
2054 auto props = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
2055 CHECK_NULL_RETURN(props, true);
2056 return props->GetDisableSwipe().value_or(false);
2057 }
2058
SetSwiperCurve(const RefPtr<Curve> & curve) const2059 void TabBarPattern::SetSwiperCurve(const RefPtr<Curve>& curve) const
2060 {
2061 auto host = GetHost();
2062 CHECK_NULL_VOID(host);
2063 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2064 CHECK_NULL_VOID(tabsNode);
2065 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2066 CHECK_NULL_VOID(swiperNode);
2067 auto swiperPaintProperty = swiperNode->GetPaintProperty<SwiperPaintProperty>();
2068 CHECK_NULL_VOID(swiperPaintProperty);
2069 swiperPaintProperty->UpdateCurve(curve);
2070 }
2071
ApplyTurnPageRateToIndicator(float turnPageRate)2072 void TabBarPattern::ApplyTurnPageRateToIndicator(float turnPageRate)
2073 {
2074 auto host = GetHost();
2075 CHECK_NULL_VOID(host);
2076 auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
2077 CHECK_NULL_VOID(layoutProperty);
2078 if (swiperStartIndex_ < 0 || swiperStartIndex_ >= static_cast<int32_t>(tabBarStyles_.size()) ||
2079 tabBarStyles_[swiperStartIndex_] != TabBarStyle::SUBTABBATSTYLE ||
2080 swiperStartIndex_ >= static_cast<int32_t>(selectedModes_.size()) ||
2081 selectedModes_[swiperStartIndex_] != SelectedMode::INDICATOR) {
2082 return;
2083 }
2084
2085 auto index = swiperStartIndex_ + 1;
2086 if (index >= static_cast<int32_t>(tabBarStyles_.size())) {
2087 swiperStartIndex_--;
2088 index--;
2089 turnPageRate += 1.0f;
2090 }
2091 if (Negative(turnPageRate)) {
2092 turnPageRate = 0.0f;
2093 }
2094 if (index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size()) ||
2095 tabBarStyles_[index] != TabBarStyle::SUBTABBATSTYLE || index >= static_cast<int32_t>(selectedModes_.size()) ||
2096 selectedModes_[index] != SelectedMode::INDICATOR) {
2097 return;
2098 }
2099
2100 if (GreatOrEqual(turnPageRate, 1.0f)) {
2101 turnPageRate_ = 1.0f;
2102 } else if (LessOrEqual(turnPageRate, 0.0f)) {
2103 turnPageRate_ = 0.0f;
2104 } else {
2105 if (turnPageRate_ <= TEXT_COLOR_THREDHOLD && turnPageRate > TEXT_COLOR_THREDHOLD) {
2106 UpdateTextColorAndFontWeight(index);
2107 } else if (turnPageRate <= 1.0f - TEXT_COLOR_THREDHOLD && turnPageRate_ > 1.0f - TEXT_COLOR_THREDHOLD) {
2108 UpdateTextColorAndFontWeight(swiperStartIndex_);
2109 }
2110 turnPageRate_ = turnPageRate;
2111 }
2112
2113 auto originalPaintRect = layoutProperty->GetIndicatorRect(swiperStartIndex_);
2114 auto targetPaintRect = layoutProperty->GetIndicatorRect(index);
2115 auto paintRectDiff = std::abs(targetPaintRect.GetX() + targetPaintRect.Width() / 2 - originalPaintRect.GetX() -
2116 originalPaintRect.Width() / 2);
2117
2118 currentIndicatorOffset_ = originalPaintRect.GetX() + originalPaintRect.Width() / 2 + paintRectDiff * turnPageRate_;
2119 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2120 }
2121
AdjustOffset(double & offset) const2122 void TabBarPattern::AdjustOffset(double& offset) const
2123 {
2124 auto host = GetHost();
2125 CHECK_NULL_VOID(host);
2126 auto geometryNode = host->GetGeometryNode();
2127 CHECK_NULL_VOID(geometryNode);
2128 auto mainSize = geometryNode->GetPaddingSize().Width();
2129 if (GreatNotEqual(currentOffset_ + offset, 0.0f)) {
2130 offset = -currentOffset_;
2131 } else if (LessNotEqual(childrenMainSize_ + currentOffset_ + offset, mainSize)) {
2132 offset = mainSize - childrenMainSize_ - currentOffset_;
2133 }
2134 }
2135
InitTurnPageRateEvent()2136 void TabBarPattern::InitTurnPageRateEvent()
2137 {
2138 auto turnPageRateCallback = [weak = WeakClaim(this)](int32_t swipingIndex, float turnPageRate) {
2139 auto pattern = weak.Upgrade();
2140 if (pattern) {
2141 if (!pattern->CheckSwiperDisable() && pattern->axis_ == Axis::HORIZONTAL && pattern->isTouchingSwiper_) {
2142 pattern->swiperStartIndex_ = swipingIndex;
2143 pattern->ApplyTurnPageRateToIndicator(turnPageRate);
2144 } else if (!pattern->isAnimating_) {
2145 pattern->turnPageRate_ = 0.0f;
2146 }
2147 }
2148 };
2149 swiperController_->SetTurnPageRateCallback(std::move(turnPageRateCallback));
2150
2151 auto host = GetHost();
2152 CHECK_NULL_VOID(host);
2153 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2154 CHECK_NULL_VOID(tabsNode);
2155 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2156 CHECK_NULL_VOID(swiperNode);
2157 auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
2158 CHECK_NULL_VOID(eventHub);
2159 if (!animationStartEvent_) {
2160 AnimationStartEvent animationStartEvent =
2161 [weak = WeakClaim(this)](int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info) {
2162 auto pattern = weak.Upgrade();
2163 if (pattern) {
2164 pattern->HandleBottomTabBarAnimation(targetIndex);
2165 }
2166 };
2167 animationStartEvent_ = std::make_shared<AnimationStartEvent>(std::move(animationStartEvent));
2168 eventHub->AddAnimationStartEvent(animationStartEvent_);
2169 }
2170 if (!animationEndEvent_) {
2171 AnimationEndEvent animationEndEvent =
2172 [weak = WeakClaim(this)](int32_t index, const AnimationCallbackInfo& info) {
2173 auto pattern = weak.Upgrade();
2174 if (pattern && (NearZero(pattern->turnPageRate_) || NearEqual(pattern->turnPageRate_, 1.0f))) {
2175 pattern->isTouchingSwiper_ = false;
2176 }
2177 pattern->SetMaskAnimationExecuted(false);
2178 };
2179 animationEndEvent_ = std::make_shared<AnimationEndEvent>(std::move(animationEndEvent));
2180 eventHub->AddAnimationEndEvent(animationEndEvent_);
2181 }
2182 }
2183
HandleBottomTabBarAnimation(int32_t index)2184 void TabBarPattern::HandleBottomTabBarAnimation(int32_t index)
2185 {
2186 auto preIndex = GetImageColorOnIndex().value_or(indicator_);
2187 if (preIndex < 0 || preIndex >= static_cast<int32_t>(tabBarStyles_.size())
2188 || index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size())) {
2189 return;
2190 }
2191 if (tabBarStyles_[preIndex] != TabBarStyle::BOTTOMTABBATSTYLE &&
2192 tabBarStyles_[index] != TabBarStyle::BOTTOMTABBATSTYLE) {
2193 return;
2194 }
2195 if (preIndex != index) {
2196 auto host = GetHost();
2197 CHECK_NULL_VOID(host);
2198 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2199 CHECK_NULL_VOID(tabsNode);
2200 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
2201 CHECK_NULL_VOID(tabsPattern);
2202 auto onChangeEvent = tabsPattern->GetChangeEvent();
2203 if (onChangeEvent) {
2204 (*onChangeEvent)(index);
2205 }
2206 auto onIndexChangeEvent = tabsPattern->GetIndexChangeEvent();
2207 if (onIndexChangeEvent) {
2208 (*onIndexChangeEvent)(index);
2209 }
2210 }
2211 SetMaskAnimationExecuted(true);
2212 }
2213
GetLeftPadding() const2214 float TabBarPattern::GetLeftPadding() const
2215 {
2216 auto host = GetHost();
2217 CHECK_NULL_RETURN(host, 0.0f);
2218 auto geometryNode = host->GetGeometryNode();
2219 CHECK_NULL_RETURN(geometryNode, 0.0f);
2220 if (!geometryNode->GetPadding()) {
2221 return 0.0f;
2222 }
2223 return geometryNode->GetPadding()->left.value_or(0.0f);
2224 }
2225
GetAnimationDuration()2226 std::optional<int32_t> TabBarPattern::GetAnimationDuration()
2227 {
2228 if (animationDuration_.has_value() && animationDuration_.value() >= 0) {
2229 return animationDuration_;
2230 }
2231 if (!animationDuration_.has_value() && Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
2232 return animationDuration_;
2233 }
2234
2235 std::optional<int32_t> duration;
2236 auto pipelineContext = PipelineContext::GetCurrentContext();
2237 CHECK_NULL_RETURN(pipelineContext, duration);
2238 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
2239 CHECK_NULL_RETURN(tabTheme, duration);
2240 auto host = GetHost();
2241 CHECK_NULL_RETURN(host, duration);
2242 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2243 CHECK_NULL_RETURN(tabsNode, duration);
2244 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2245 CHECK_NULL_RETURN(swiperNode, duration);
2246 auto swiperPaintProperty = swiperNode->GetPaintProperty<SwiperPaintProperty>();
2247 CHECK_NULL_RETURN(swiperPaintProperty, duration);
2248 duration = static_cast<int32_t>(tabTheme->GetTabContentAnimationDuration());
2249 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
2250 std::count(tabBarStyles_.begin(), tabBarStyles_.end(), TabBarStyle::BOTTOMTABBATSTYLE)) {
2251 duration = 0;
2252 }
2253 SetAnimationDuration(duration.value());
2254 swiperPaintProperty->UpdateDuration(duration.value());
2255 return duration;
2256 }
2257
DumpAdvanceInfo()2258 void TabBarPattern::DumpAdvanceInfo()
2259 {
2260 isRTL_ ? DumpLog::GetInstance().AddDesc("isRTL:true") : DumpLog::GetInstance().AddDesc("isRTL:false");
2261 touching_ ? DumpLog::GetInstance().AddDesc("touching:true") : DumpLog::GetInstance().AddDesc("touching:false");
2262 isMaskAnimationByCreate_ ? DumpLog::GetInstance().AddDesc("isMaskAnimationByCreate:true")
2263 : DumpLog::GetInstance().AddDesc("isMaskAnimationByCreate:false");
2264 animationDuration_.has_value()
2265 ? DumpLog::GetInstance().AddDesc("animationDuration:" + std::to_string(animationDuration_.value()))
2266 : DumpLog::GetInstance().AddDesc("animationDuration:null");
2267 isFirstFocus_ ? DumpLog::GetInstance().AddDesc("isFirstFocus:true")
2268 : DumpLog::GetInstance().AddDesc("isFirstFocus:false");
2269 isTouchingSwiper_ ? DumpLog::GetInstance().AddDesc("isTouchingSwiper:true")
2270 : DumpLog::GetInstance().AddDesc("isTouchingSwiper:false");
2271 isAnimating_ ? DumpLog::GetInstance().AddDesc("isAnimating:true")
2272 : DumpLog::GetInstance().AddDesc("isAnimating:false");
2273 changeByClick_ ? DumpLog::GetInstance().AddDesc("changeByClick:true")
2274 : DumpLog::GetInstance().AddDesc("changeByClick:false");
2275 needSetCentered_ ? DumpLog::GetInstance().AddDesc("needSetCentered:true")
2276 : DumpLog::GetInstance().AddDesc("needSetCentered:false");
2277 DumpLog::GetInstance().AddDesc("childrenMainSize:" + std::to_string(childrenMainSize_));
2278 DumpLog::GetInstance().AddDesc("indicator:" + std::to_string(indicator_));
2279 DumpLog::GetInstance().AddDesc("swiperStartIndex:" + std::to_string(swiperStartIndex_));
2280 DumpLog::GetInstance().AddDesc("scrollMargin:" + std::to_string(scrollMargin_));
2281 std::string regionString = std::string("region:");
2282 for (auto item : gradientRegions_) {
2283 item ? regionString.append("true ") : regionString.append("false ");
2284 }
2285 DumpLog::GetInstance().AddDesc(regionString);
2286 switch (axis_) {
2287 case Axis::NONE: {
2288 DumpLog::GetInstance().AddDesc("Axis:NONE");
2289 break;
2290 }
2291 case Axis::HORIZONTAL: {
2292 DumpLog::GetInstance().AddDesc("Axis:HORIZONTAL");
2293 break;
2294 }
2295 case Axis::FREE: {
2296 DumpLog::GetInstance().AddDesc("Axis:FREE");
2297 break;
2298 }
2299 case Axis::VERTICAL: {
2300 DumpLog::GetInstance().AddDesc("Axis:VERTICAL");
2301 break;
2302 }
2303 default: {
2304 break;
2305 }
2306 }
2307 }
2308
ContentWillChange(int32_t comingIndex)2309 bool TabBarPattern::ContentWillChange(int32_t comingIndex)
2310 {
2311 auto host = GetHost();
2312 CHECK_NULL_RETURN(host, true);
2313 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2314 CHECK_NULL_RETURN(tabsNode, true);
2315 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2316 CHECK_NULL_RETURN(swiperNode, true);
2317 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
2318 CHECK_NULL_RETURN(swiperPattern, true);
2319 int32_t currentIndex = swiperPattern->GetCurrentIndex();
2320 return ContentWillChange(currentIndex, comingIndex);
2321 }
2322
ContentWillChange(int32_t currentIndex,int32_t comingIndex)2323 bool TabBarPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
2324 {
2325 auto host = GetHost();
2326 CHECK_NULL_RETURN(host, true);
2327 auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2328 CHECK_NULL_RETURN(tabsNode, true);
2329 auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
2330 CHECK_NULL_RETURN(tabsPattern, true);
2331 if (tabsPattern->GetInterceptStatus()) {
2332 auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
2333 return ret.has_value() ? ret.value() : true;
2334 }
2335 return true;
2336 }
2337 } // namespace OHOS::Ace::NG
2338