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