• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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