1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/tabs/tab_bar_pattern.h"
17 
18 #include <optional>
19 
20 #include "base/geometry/axis.h"
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/log/dump_log.h"
25 #include "base/memory/ace_type.h"
26 #include "base/utils/utils.h"
27 #include "core/common/agingadapation/aging_adapation_dialog_util.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components_ng/pattern/scrollable/scrollable.h"
30 #include "core/components/tab_bar/tab_theme.h"
31 #include "core/components_ng/base/frame_node.h"
32 #include "core/components_ng/base/inspector_filter.h"
33 #include "core/components_ng/pattern/image/image_layout_property.h"
34 #include "core/components_ng/pattern/image/image_pattern.h"
35 #include "core/components_ng/pattern/pattern.h"
36 #include "core/components_ng/pattern/scroll/scroll_spring_effect.h"
37 #include "core/components_ng/pattern/swiper/swiper_event_hub.h"
38 #include "core/components_ng/pattern/swiper/swiper_model.h"
39 #include "core/components_ng/pattern/tabs/tabs_controller.h"
40 #include "core/components_ng/pattern/tabs/tabs_layout_property.h"
41 #include "core/components_ng/pattern/tabs/tabs_node.h"
42 #include "core/components_ng/pattern/tabs/tabs_pattern.h"
43 #include "core/components_ng/pattern/tabs/tab_content_model_ng.h"
44 #include "core/components_ng/pattern/text/text_layout_property.h"
45 #include "core/components_ng/pattern/symbol/constants.h"
46 #include "core/components_ng/pattern/symbol/symbol_effect_options.h"
47 #include "core/components_ng/property/property.h"
48 #include "core/components_v2/inspector/inspector_constants.h"
49 #include "core/pipeline_ng/pipeline_context.h"
50 #include "base/perfmonitor/perf_constants.h"
51 #include "base/perfmonitor/perf_monitor.h"
52 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
53 #include "core/components_ng/pattern/text/text_pattern.h"
54 #include "core/components/toast/toast_theme.h"
55 #include "core/components/text_field/textfield_theme.h"
56 #include "core/components_ng/pattern/app_bar/app_bar_theme.h"
57 namespace OHOS::Ace::NG {
58 namespace {
59 constexpr int8_t LEFT_GRADIENT = 0;
60 constexpr int8_t RIGHT_GRADIENT = 1;
61 constexpr int8_t TOP_GRADIENT = 2;
62 constexpr int8_t BOTTOM_GRADIENT = 3;
63 constexpr float HALF_PROGRESS = 0.5f;
64 constexpr float FULL_PROGRESS = 1.0f;
65 constexpr float HALF_MASK_RADIUS_RATIO = 0.717f;
66 constexpr float FULL_MASK_RADIUS_RATIO = 1.414f;
67 constexpr float INVALID_RATIO = -1.0f;
68 constexpr uint16_t MASK_ANIMATION_DURATION = 200;
69 constexpr int8_t MASK_COUNT = 2;
70 constexpr float FULL_OPACITY = 1.0f;
71 constexpr float NEAR_FULL_OPACITY = 0.99f;
72 constexpr float NO_OPACITY = 0.0f;
73 constexpr float TEXT_COLOR_THREDHOLD = 0.673f;
74 constexpr int8_t HALF_OF_WIDTH = 2;
75 constexpr float MAX_FLING_VELOCITY = 4200.0f;
76 
77 const auto DurationCubicCurve = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.0f, 0.1f, 1.0f);
78 const auto SHOW_TAB_BAR_CURVE = AceType::MakeRefPtr<CubicCurve>(0.4f, 0.0f, 0.2f, 1.0f);
79 const auto SHOW_TAB_BAR_DURATION = 500.0f;
80 const std::string TAB_BAR_PROPERTY_NAME = "tabBar";
81 const std::string INDICATOR_OFFSET_PROPERTY_NAME = "indicatorOffset";
82 const std::string INDICATOR_WIDTH_PROPERTY_NAME = "translateWidth";
83 const auto SHOW_TAB_BAR_FRAME_RATE = 120;
84 const auto SHOW_TAB_BAR_FRAME_RATE_RANGE =
85     AceType::MakeRefPtr<FrameRateRange>(0, SHOW_TAB_BAR_FRAME_RATE, SHOW_TAB_BAR_FRAME_RATE);
86 } // namespace
87 
TabBarPattern(const RefPtr<SwiperController> & swiperController)88 TabBarPattern::TabBarPattern(const RefPtr<SwiperController>& swiperController) : swiperController_(swiperController)
89 {
90     auto tabsController = AceType::DynamicCast<TabsControllerNG>(swiperController_);
91     CHECK_NULL_VOID(tabsController);
92     auto weak = WeakClaim(this);
93     tabsController->SetStartShowTabBarImpl([weak](int32_t delay) {
94         auto pattern = weak.Upgrade();
95         CHECK_NULL_VOID(pattern);
96         pattern->StartShowTabBar(delay);
97     });
98     tabsController->SetStopShowTabBarImpl([weak]() {
99         auto pattern = weak.Upgrade();
100         CHECK_NULL_VOID(pattern);
101         pattern->StopShowTabBar();
102     });
103     tabsController->SetUpdateTabBarHiddenRatioImpl([weak](float ratio) {
104         auto pattern = weak.Upgrade();
105         CHECK_NULL_VOID(pattern);
106         pattern->UpdateTabBarHiddenRatio(ratio);
107     });
108     tabsController->SetTabBarTranslateImpl([weak](const TranslateOptions& options) {
109         auto pattern = weak.Upgrade();
110         CHECK_NULL_VOID(pattern);
111         pattern->SetTabBarTranslate(options);
112     });
113     tabsController->SetTabBarOpacityImpl([weak](float opacity) {
114         auto pattern = weak.Upgrade();
115         CHECK_NULL_VOID(pattern);
116         pattern->SetTabBarOpacity(opacity);
117     });
118 }
119 
StartShowTabBar(int32_t delay)120 void TabBarPattern::StartShowTabBar(int32_t delay)
121 {
122     auto host = GetHost();
123     CHECK_NULL_VOID(host);
124     auto renderContext = host->GetRenderContext();
125     CHECK_NULL_VOID(renderContext);
126     auto options = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
127     auto translate = options.y.ConvertToPx();
128     auto size = renderContext->GetPaintRectWithoutTransform().Height();
129     if (axis_ == Axis::VERTICAL || NearZero(translate) || NearZero(size)) {
130         return;
131     }
132     if (delay == 0 && GreatOrEqual(std::abs(translate), size)) {
133         StopShowTabBar();
134     }
135     if (isTabBarShowing_) {
136         return;
137     }
138 
139     InitTabBarProperty();
140     AnimationOption option;
141     delay = LessNotEqual(std::abs(translate), size) ? 0 : delay;
142     option.SetDelay(delay);
143     auto duration = SHOW_TAB_BAR_DURATION * (std::abs(translate) / size);
144     option.SetDuration(duration);
145     option.SetCurve(SHOW_TAB_BAR_CURVE);
146     option.SetFrameRateRange(SHOW_TAB_BAR_FRAME_RATE_RANGE);
147 
148     showTabBarProperty_->Set(translate);
149     auto propertyCallback = [weak = WeakClaim(this)]() {
150         auto pattern = weak.Upgrade();
151         CHECK_NULL_VOID(pattern);
152         pattern->showTabBarProperty_->Set(0.0f);
153     };
154     auto finishCallback = [weak = WeakClaim(this)]() {
155         auto pattern = weak.Upgrade();
156         CHECK_NULL_VOID(pattern);
157         pattern->isTabBarShowing_ = false;
158     };
159     AnimationUtils::Animate(option, propertyCallback, finishCallback);
160     isTabBarShowing_ = true;
161 }
162 
InitTabBarProperty()163 void TabBarPattern::InitTabBarProperty()
164 {
165     if (showTabBarProperty_) {
166         return;
167     }
168     auto host = GetHost();
169     CHECK_NULL_VOID(host);
170     auto renderContext = host->GetRenderContext();
171     CHECK_NULL_VOID(renderContext);
172 
173     auto propertyCallback = [weak = WeakClaim(this)](float value) {
174         auto pattern = weak.Upgrade();
175         CHECK_NULL_VOID(pattern);
176         auto host = pattern->GetHost();
177         CHECK_NULL_VOID(host);
178         auto renderContext = host->GetRenderContext();
179         CHECK_NULL_VOID(renderContext);
180 
181         pattern->SetTabBarTranslate(TranslateOptions(0.0f, value, 0.0f));
182         auto size = renderContext->GetPaintRectWithoutTransform().Height();
183         if (NearZero(size)) {
184             return;
185         }
186         pattern->SetTabBarOpacity(1.0f - std::abs(value) / size);
187     };
188     showTabBarProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
189     renderContext->AttachNodeAnimatableProperty(showTabBarProperty_);
190 }
191 
StopShowTabBar()192 void TabBarPattern::StopShowTabBar()
193 {
194     if (axis_ == Axis::VERTICAL || !isTabBarShowing_) {
195         return;
196     }
197     auto host = GetHost();
198     CHECK_NULL_VOID(host);
199     auto renderContext = host->GetRenderContext();
200     CHECK_NULL_VOID(renderContext);
201 
202     AnimationOption option;
203     option.SetDuration(0);
204     option.SetCurve(Curves::LINEAR);
205     auto options = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
206     auto translate = options.y.ConvertToPx();
207     auto propertyCallback = [weak = WeakClaim(this), translate]() {
208         auto pattern = weak.Upgrade();
209         CHECK_NULL_VOID(pattern);
210         pattern->showTabBarProperty_->Set(translate);
211     };
212     AnimationUtils::Animate(option, propertyCallback);
213     isTabBarShowing_ = false;
214 }
215 
UpdateTabBarHiddenRatio(float ratio)216 void TabBarPattern::UpdateTabBarHiddenRatio(float ratio)
217 {
218     if (axis_ == Axis::VERTICAL || isTabBarShowing_) {
219         return;
220     }
221     auto host = GetHost();
222     CHECK_NULL_VOID(host);
223     auto renderContext = host->GetRenderContext();
224     CHECK_NULL_VOID(renderContext);
225     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
226     CHECK_NULL_VOID(tabsNode);
227     auto tabsLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
228     CHECK_NULL_VOID(tabsLayoutProperty);
229 
230     auto options = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
231     float translate = options.y.ConvertToPx();
232     auto size = renderContext->GetPaintRectWithoutTransform().Height();
233     auto barPosition = tabsLayoutProperty->GetTabBarPosition().value_or(BarPosition::START);
234     if (barPosition == BarPosition::START) {
235         translate = std::clamp(translate - size * ratio, -size, 0.0f);
236     } else {
237         translate = std::clamp(translate + size * ratio, 0.0f, size);
238     }
239     renderContext->UpdateTransformTranslate(TranslateOptions(0.0f, translate, 0.0f));
240     float opacity = renderContext->GetOpacityValue(1.0f);
241     opacity = std::clamp(opacity - ratio, 0.0f, 1.0f);
242     renderContext->UpdateOpacity(opacity);
243 }
244 
SetTabBarTranslate(const TranslateOptions & options)245 void TabBarPattern::SetTabBarTranslate(const TranslateOptions& options)
246 {
247     auto host = GetHost();
248     CHECK_NULL_VOID(host);
249     auto renderContext = host->GetRenderContext();
250     CHECK_NULL_VOID(renderContext);
251     renderContext->UpdateTransformTranslate(options);
252 }
253 
SetTabBarOpacity(float opacity)254 void TabBarPattern::SetTabBarOpacity(float opacity)
255 {
256     auto host = GetHost();
257     CHECK_NULL_VOID(host);
258     auto renderContext = host->GetRenderContext();
259     CHECK_NULL_VOID(renderContext);
260     renderContext->UpdateOpacity(opacity);
261 }
262 
FindTextAndImageNode(const RefPtr<FrameNode> & columnNode,RefPtr<FrameNode> & textNode,RefPtr<FrameNode> & imageNode)263 void FindTextAndImageNode(
264     const RefPtr<FrameNode>& columnNode, RefPtr<FrameNode>& textNode, RefPtr<FrameNode>& imageNode)
265 {
266     if (columnNode->GetTag() == V2::TEXT_ETS_TAG) {
267         textNode = columnNode;
268     } else if (columnNode->GetTag() == V2::IMAGE_ETS_TAG || columnNode->GetTag() == V2::SYMBOL_ETS_TAG) {
269         imageNode = columnNode;
270     } else {
271         std::list<RefPtr<UINode>> children = columnNode->GetChildren();
272         for (auto child : children) {
273             FindTextAndImageNode(AceType::DynamicCast<FrameNode>(child), textNode, imageNode);
274         }
275     }
276 }
277 
OnAttachToFrameNode()278 void TabBarPattern::OnAttachToFrameNode()
279 {
280     auto host = GetHost();
281     CHECK_NULL_VOID(host);
282     auto renderContext = host->GetRenderContext();
283     CHECK_NULL_VOID(renderContext);
284     renderContext->SetClipToFrame(true);
285     host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(
286         { .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_BOTTOM });
287     swiperController_->SetTabBarFinishCallback([weak = WeakClaim(this)]() {
288         auto pattern = weak.Upgrade();
289         CHECK_NULL_VOID(pattern);
290         // always swipe with physical curve, ignore animationDuration
291         pattern->SetSwiperCurve(TabBarPhysicalCurve);
292 
293         if (pattern->scrollableEvent_) {
294             auto scrollable = pattern->scrollableEvent_->GetScrollable();
295             if (scrollable) {
296                 scrollable->StopScrollable();
297             }
298         }
299 
300         pattern->StopTranslateAnimation();
301         pattern->ResetIndicatorAnimationState();
302         auto swiperPattern = pattern->GetSwiperPattern();
303         CHECK_NULL_VOID(swiperPattern);
304         auto currentIndex = swiperPattern->GetCurrentIndex();
305         auto totalCount = swiperPattern->TotalCount();
306         if (currentIndex >= totalCount || currentIndex < 0) {
307             currentIndex = 0;
308         }
309         auto layoutProperty = pattern->GetLayoutProperty<TabBarLayoutProperty>();
310         CHECK_NULL_VOID(layoutProperty);
311         if (layoutProperty->GetIndicatorValue(0) != currentIndex) {
312             pattern->UpdateSubTabBoard(currentIndex);
313             pattern->UpdateTextColorAndFontWeight(currentIndex);
314             pattern->UpdateIndicator(currentIndex);
315             pattern->SetChangeByClick(false);
316         }
317     });
318     InitSurfaceChangedCallback();
319 }
320 
InitSurfaceChangedCallback()321 void TabBarPattern::InitSurfaceChangedCallback()
322 {
323     auto host = GetHost();
324     CHECK_NULL_VOID(host);
325     auto pipeline = host->GetContextRefPtr();
326     CHECK_NULL_VOID(pipeline);
327     if (!HasSurfaceChangedCallback()) {
328         auto callbackId = pipeline->RegisterSurfaceChangedCallback(
329             [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
330                 WindowSizeChangeReason type) {
331                 auto pattern = weak.Upgrade();
332                 if (!pattern) {
333                     return;
334                 }
335 
336                 pattern->windowSizeChangeReason_ = type;
337                 pattern->prevRootSize_ = std::make_pair(prevWidth, prevHeight);
338 
339                 if (type == WindowSizeChangeReason::ROTATION) {
340                     pattern->StopTranslateAnimation();
341                 }
342             });
343         UpdateSurfaceChangedCallbackId(callbackId);
344     }
345 }
346 
OnDetachFromFrameNode(FrameNode * node)347 void TabBarPattern::OnDetachFromFrameNode(FrameNode* node)
348 {
349     auto pipeline = GetContext();
350     CHECK_NULL_VOID(pipeline);
351     if (HasSurfaceChangedCallback()) {
352         pipeline->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
353     }
354     pipeline->RemoveWindowStateChangedCallback(node->GetId());
355 }
356 
BeforeCreateLayoutWrapper()357 void TabBarPattern::BeforeCreateLayoutWrapper()
358 {
359     auto host = GetHost();
360     CHECK_NULL_VOID(host);
361     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
362     CHECK_NULL_VOID(layoutProperty);
363     if (targetIndex_) {
364         targetIndex_ = GetLoopIndex(targetIndex_.value());
365     }
366     if (isExecuteBuilder_) {
367         jumpIndex_ = layoutProperty->GetIndicatorValue(0);
368         isExecuteBuilder_ = false;
369     }
370 }
371 
AddTabBarItemClickEvent(const RefPtr<FrameNode> & tabBarItem)372 void TabBarPattern::AddTabBarItemClickEvent(const RefPtr<FrameNode>& tabBarItem)
373 {
374     CHECK_NULL_VOID(tabBarItem);
375     auto tabBarItemId = tabBarItem->GetId();
376     if (clickEvents_.find(tabBarItemId) != clickEvents_.end()) {
377         return;
378     }
379 
380     auto eventHub = tabBarItem->GetEventHub<EventHub>();
381     CHECK_NULL_VOID(eventHub);
382     auto gestureHub = eventHub->GetOrCreateGestureEventHub();
383     CHECK_NULL_VOID(gestureHub);
384     auto clickCallback = [weak = WeakClaim(this), tabBarItemId](GestureEvent& info) {
385         auto tabBar = weak.Upgrade();
386         CHECK_NULL_VOID(tabBar);
387         auto host = tabBar->GetHost();
388         CHECK_NULL_VOID(host);
389         auto index = host->GetChildFlatIndex(tabBarItemId).second;
390         tabBar->HandleClick(info.GetSourceDevice(), index);
391     };
392     auto clickEvent = AceType::MakeRefPtr<ClickEvent>(std::move(clickCallback));
393     clickEvents_[tabBarItemId] = clickEvent;
394     gestureHub->AddClickEvent(clickEvent);
395 }
396 
AddMaskItemClickEvent()397 void TabBarPattern::AddMaskItemClickEvent()
398 {
399     auto host = GetHost();
400     CHECK_NULL_VOID(host);
401     auto childCount = host->GetChildren().size() - MASK_COUNT;
402 
403     for (int32_t maskIndex = 0; maskIndex < MASK_COUNT; maskIndex++) {
404         auto maskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(childCount + maskIndex));
405         CHECK_NULL_VOID(maskNode);
406         auto maskNodeId = maskNode->GetId();
407         if (clickEvents_.find(maskNodeId) != clickEvents_.end()) {
408             continue;
409         }
410 
411         auto eventHub = maskNode->GetEventHub<EventHub>();
412         CHECK_NULL_VOID(eventHub);
413         auto gestureHub = eventHub->GetOrCreateGestureEventHub();
414         CHECK_NULL_VOID(gestureHub);
415         auto clickCallback = [weak = WeakClaim(this), maskIndex](GestureEvent& info) {
416             auto tabBar = weak.Upgrade();
417             CHECK_NULL_VOID(tabBar);
418             auto layoutProperty = tabBar->GetLayoutProperty<TabBarLayoutProperty>();
419             CHECK_NULL_VOID(layoutProperty);
420             auto index = (maskIndex == 0) ? layoutProperty->GetSelectedMask().value_or(-1) :
421                 layoutProperty->GetUnselectedMask().value_or(-1);
422             if (index >= 0) {
423                 tabBar->HandleClick(info.GetSourceDevice(), index);
424             }
425         };
426         auto clickEvent = AceType::MakeRefPtr<ClickEvent>(std::move(clickCallback));
427         clickEvents_[maskNodeId] = clickEvent;
428         gestureHub->AddClickEvent(clickEvent);
429     }
430 }
431 
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub)432 void TabBarPattern::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub)
433 {
434     if (longPressEvent_) {
435         return;
436     }
437 
438     auto longPressTask = [weak = WeakClaim(this)](GestureEvent& info) {
439         auto tabBar = weak.Upgrade();
440         if (tabBar) {
441             tabBar->HandleLongPressEvent(info);
442         }
443     };
444     longPressEvent_ = AceType::MakeRefPtr<LongPressEvent>(std::move(longPressTask));
445     gestureHub->SetLongPressEvent(longPressEvent_);
446 }
447 
InitDragEvent(const RefPtr<GestureEventHub> & gestureHub)448 void TabBarPattern::InitDragEvent(const RefPtr<GestureEventHub>& gestureHub)
449 {
450     CHECK_NULL_VOID(!dragEvent_);
451     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
452         auto tabBar = weak.Upgrade();
453         auto index = tabBar->CalculateSelectedIndex(info.GetLocalLocation());
454         auto host = tabBar->GetHost();
455         CHECK_NULL_VOID(host);
456         auto totalCount = host->TotalChildCount() - MASK_COUNT;
457         if (tabBar && tabBar->dialogNode_ && index >= 0 && index < totalCount) {
458             if (!tabBar->moveIndex_.has_value()) {
459                 tabBar->moveIndex_ = index;
460             }
461 
462             if (tabBar->moveIndex_ != index) {
463                 tabBar->CloseDialog();
464                 tabBar->moveIndex_ = index;
465                 tabBar->ShowDialogWithNode(index);
466             }
467         }
468     };
469     dragEvent_ = MakeRefPtr<DragEvent>(nullptr, std::move(actionUpdateTask), nullptr, nullptr);
470     PanDirection panDirection = { .type = PanDirection::ALL };
471     gestureHub->SetDragEvent(dragEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
472 }
473 
InitScrollableEvent(const RefPtr<TabBarLayoutProperty> & layoutProperty,const RefPtr<GestureEventHub> & gestureHub)474 void TabBarPattern::InitScrollableEvent(
475     const RefPtr<TabBarLayoutProperty>& layoutProperty, const RefPtr<GestureEventHub>& gestureHub)
476 {
477     if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
478         InitScrollable(gestureHub);
479         SetEdgeEffect(gestureHub);
480     } else {
481         if (scrollableEvent_) {
482             gestureHub->RemoveScrollableEvent(scrollableEvent_);
483             scrollableEvent_.Reset();
484         }
485         if (scrollEffect_) {
486             gestureHub->RemoveScrollEdgeEffect(scrollEffect_);
487             scrollEffect_.Reset();
488         }
489     }
490 }
491 
InitScrollable(const RefPtr<GestureEventHub> & gestureHub)492 void TabBarPattern::InitScrollable(const RefPtr<GestureEventHub>& gestureHub)
493 {
494     auto host = GetHost();
495     CHECK_NULL_VOID(host);
496     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
497     CHECK_NULL_VOID(layoutProperty);
498     auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
499     if (axis_ == axis && scrollableEvent_) {
500         return;
501     }
502 
503     axis_ = axis;
504     auto task = [weak = WeakClaim(this)](double offset, int32_t source) {
505         if (source == SCROLL_FROM_START) {
506             return true;
507         }
508         auto pattern = weak.Upgrade();
509         CHECK_NULL_RETURN(pattern, false);
510         if (!pattern->CanScroll()) {
511             return false;
512         }
513 
514         if (pattern->IsOutOfBoundary()) {
515             // over scroll in drag update from normal to over scroll or during over scroll.
516             auto scrollable = pattern->scrollableEvent_->GetScrollable();
517             if (scrollable) {
518                 scrollable->SetCanOverScroll(true);
519             }
520 
521             auto host = pattern->GetHost();
522             CHECK_NULL_RETURN(host, false);
523             auto geometryNode = host->GetGeometryNode();
524             CHECK_NULL_RETURN(geometryNode, false);
525             auto overScrollInfo = pattern->GetOverScrollInfo(geometryNode->GetPaddingSize());
526             if (source == SCROLL_FROM_UPDATE) {
527                 // adjust offset.
528                 if (overScrollInfo.second != 0.0f) {
529                     pattern->canOverScroll_ = true;
530                     auto friction = CalculateFriction(std::abs(overScrollInfo.first) / overScrollInfo.second);
531                     pattern->UpdateCurrentOffset(static_cast<float>(offset * friction));
532                 }
533                 return true;
534             }
535         }
536         if (source != SCROLL_FROM_AXIS) {
537             pattern->canOverScroll_ = true;
538         }
539         pattern->UpdateCurrentOffset(static_cast<float>(offset));
540         return true;
541     };
542 
543     if (scrollableEvent_) {
544         gestureHub->RemoveScrollableEvent(scrollableEvent_);
545     }
546 
547     scrollableEvent_ = MakeRefPtr<ScrollableEvent>(axis);
548     auto scrollable = MakeRefPtr<Scrollable>(task, axis);
549     scrollable->SetNodeId(host->GetAccessibilityId());
550     scrollable->Initialize(host->GetContextRefPtr());
551     scrollable->SetMaxFlingVelocity(MAX_FLING_VELOCITY);
552     auto renderContext = host->GetRenderContext();
553     CHECK_NULL_VOID(renderContext);
554     auto springProperty = scrollable->GetSpringProperty();
555     renderContext->AttachNodeAnimatableProperty(springProperty);
556     auto frictionProperty = scrollable->GetFrictionProperty();
557     renderContext->AttachNodeAnimatableProperty(frictionProperty);
558     scrollableEvent_->SetScrollable(scrollable);
559     gestureHub->AddScrollableEvent(scrollableEvent_);
560     scrollableEvent_->GetScrollable()->SetEdgeEffect(EdgeEffect::SPRING);
561 }
562 
CanScroll() const563 bool TabBarPattern::CanScroll() const
564 {
565     auto host = GetHost();
566     CHECK_NULL_RETURN(host, false);
567     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
568     CHECK_NULL_RETURN(layoutProperty, false);
569     if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::FIXED) {
570         return false;
571     }
572 
573     if (visibleItemPosition_.empty()) {
574         return false;
575     }
576     auto geometryNode = host->GetGeometryNode();
577     CHECK_NULL_RETURN(geometryNode, false);
578     auto visibleItemStartIndex = visibleItemPosition_.begin()->first;
579     auto visibleItemEndIndex = visibleItemPosition_.rbegin()->first;
580     auto visibleItemStartPos = visibleItemPosition_.begin()->second.startPos;
581     auto visibleItemEndPos = visibleItemPosition_.rbegin()->second.endPos;
582     auto childCount = host->TotalChildCount() - MASK_COUNT;
583     auto contentMainSize =
584         geometryNode->GetPaddingSize().MainSize(layoutProperty->GetAxis().value_or(Axis::HORIZONTAL));
585     return visibleItemStartIndex > 0 || LessNotEqual(visibleItemStartPos, scrollMargin_) ||
586         visibleItemEndIndex < (childCount - 1) || GreatNotEqual(visibleItemEndPos, contentMainSize - scrollMargin_);
587 }
588 
GetOverScrollInfo(const SizeF & size)589 std::pair<float, float> TabBarPattern::GetOverScrollInfo(const SizeF& size)
590 {
591     auto overScroll = 0.0f;
592     auto mainSize = 0.0f;
593     if (visibleItemPosition_.empty()) {
594         return std::make_pair(overScroll, mainSize);
595     }
596 
597     auto visibleItemStartPos = visibleItemPosition_.begin()->second.startPos;
598     auto visibleItemEndPos = visibleItemPosition_.rbegin()->second.endPos;
599     auto startPos = visibleItemStartPos - scrollMargin_;
600     mainSize = size.MainSize(axis_);
601     if (Positive(startPos)) {
602         overScroll = startPos;
603     } else {
604         overScroll = mainSize - visibleItemEndPos - scrollMargin_;
605     }
606     return std::make_pair(overScroll, mainSize);
607 }
608 
InitTouch(const RefPtr<GestureEventHub> & gestureHub)609 void TabBarPattern::InitTouch(const RefPtr<GestureEventHub>& gestureHub)
610 {
611     if (touchEvent_) {
612         return;
613     }
614     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
615         auto pattern = weak.Upgrade();
616         CHECK_NULL_VOID(pattern);
617         pattern->HandleTouchEvent(info.GetTouches().front());
618     };
619     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
620     gestureHub->AddTouchEvent(touchEvent_);
621 }
622 
InitHoverEvent()623 void TabBarPattern::InitHoverEvent()
624 {
625     if (hoverEvent_) {
626         return;
627     }
628     auto host = GetHost();
629     CHECK_NULL_VOID(host);
630     auto eventHub = GetHost()->GetEventHub<EventHub>();
631     auto inputHub = eventHub->GetOrCreateInputEventHub();
632 
633     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
634         auto pattern = weak.Upgrade();
635         if (pattern) {
636             pattern->HandleHoverEvent(isHover);
637         }
638     };
639     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
640     inputHub->AddOnHoverEvent(hoverEvent_);
641 }
642 
InitMouseEvent()643 void TabBarPattern::InitMouseEvent()
644 {
645     if (mouseEvent_) {
646         return;
647     }
648     auto host = GetHost();
649     CHECK_NULL_VOID(host);
650     auto eventHub = GetHost()->GetEventHub<EventHub>();
651     auto inputHub = eventHub->GetOrCreateInputEventHub();
652     auto mouseTask = [weak = WeakClaim(this)](const MouseInfo& info) {
653         auto pattern = weak.Upgrade();
654         if (pattern) {
655             pattern->HandleMouseEvent(info);
656         }
657     };
658     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
659     inputHub->AddOnMouseEvent(mouseEvent_);
660 }
661 
HandleMouseEvent(const MouseInfo & info)662 void TabBarPattern::HandleMouseEvent(const MouseInfo& info)
663 {
664     if (IsContainsBuilder()) {
665         return;
666     }
667     auto host = GetHost();
668     CHECK_NULL_VOID(host);
669     auto totalCount = host->TotalChildCount() - MASK_COUNT;
670     if (totalCount < 0) {
671         return;
672     }
673     auto index = CalculateSelectedIndex(info.GetLocalLocation());
674     if (index < 0 || index >= totalCount) {
675         if (hoverIndex_.has_value() && !touchingIndex_.has_value()) {
676             HandleMoveAway(hoverIndex_.value());
677         }
678         hoverIndex_.reset();
679         return;
680     }
681     auto mouseAction = info.GetAction();
682     if (mouseAction == MouseAction::MOVE || mouseAction == MouseAction::WINDOW_ENTER) {
683         if (touchingIndex_.has_value()) {
684             hoverIndex_ = index;
685             return;
686         }
687         if (!hoverIndex_.has_value()) {
688             HandleHoverOnEvent(index);
689             hoverIndex_ = index;
690             return;
691         }
692         if (hoverIndex_.value() != index) {
693             HandleMoveAway(hoverIndex_.value());
694             HandleHoverOnEvent(index);
695             hoverIndex_ = index;
696             return;
697         }
698         return;
699     }
700     if (mouseAction == MouseAction::WINDOW_LEAVE) {
701         if (hoverIndex_.has_value()) {
702             HandleMoveAway(hoverIndex_.value());
703         }
704     }
705 }
706 
HandleHoverEvent(bool isHover)707 void TabBarPattern::HandleHoverEvent(bool isHover)
708 {
709     if (IsContainsBuilder()) {
710         return;
711     }
712     isHover_ = isHover;
713     if (!isHover_ && hoverIndex_.has_value()) {
714         if (!touchingIndex_.has_value()) {
715             HandleMoveAway(hoverIndex_.value());
716         }
717         hoverIndex_.reset();
718     }
719 }
720 
HandleHoverOnEvent(int32_t index)721 void TabBarPattern::HandleHoverOnEvent(int32_t index)
722 {
723     auto pipelineContext = PipelineContext::GetCurrentContext();
724     CHECK_NULL_VOID(pipelineContext);
725     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
726     CHECK_NULL_VOID(tabTheme);
727     PlayPressAnimation(index, tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVER);
728 }
729 
HandleMoveAway(int32_t index)730 void TabBarPattern::HandleMoveAway(int32_t index)
731 {
732     PlayPressAnimation(index, Color::TRANSPARENT, AnimationType::HOVER);
733 }
734 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)735 void TabBarPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
736 {
737     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
738         auto pattern = wp.Upgrade();
739         if (pattern) {
740             return pattern->OnKeyEvent(event);
741         }
742         return false;
743     };
744     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
745 
746     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
747         auto pattern = wp.Upgrade();
748         if (pattern) {
749             pattern->GetInnerFocusPaintRect(paintRect);
750         }
751     };
752     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
753 }
754 
OnKeyEvent(const KeyEvent & event)755 bool TabBarPattern::OnKeyEvent(const KeyEvent& event)
756 {
757     auto pipeline = PipelineContext::GetCurrentContext();
758     CHECK_NULL_RETURN(pipeline, false);
759     if (!pipeline->GetIsFocusActive()) {
760         return false;
761     }
762     isFirstFocus_ = false;
763     if (event.action != KeyAction::DOWN) {
764         return false;
765     }
766     if (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE || tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
767         return OnKeyEventWithoutClick(event);
768     }
769     auto host = GetHost();
770     CHECK_NULL_RETURN(host, false);
771     CHECK_NULL_RETURN(swiperController_, false);
772     swiperController_->FinishAnimation();
773     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
774     auto indicator = tabBarLayoutProperty->GetIndicatorValue(0);
775     if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
776                     ? (isRTL_ ? KeyCode::KEY_DPAD_RIGHT : KeyCode::KEY_DPAD_LEFT) : KeyCode::KEY_DPAD_UP) ||
777         event.IsShiftWith(KeyCode::KEY_TAB)) {
778         if (indicator <= 0) {
779             return false;
780         }
781         indicator -= 1;
782         FocusIndexChange(indicator);
783         return true;
784     }
785     if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
786                     ? (isRTL_ ? KeyCode::KEY_DPAD_LEFT : KeyCode::KEY_DPAD_RIGHT) : KeyCode::KEY_DPAD_DOWN) ||
787         event.code == KeyCode::KEY_TAB) {
788         if (indicator >= host->TotalChildCount() - MASK_COUNT - 1) {
789             return false;
790         }
791         indicator += 1;
792         FocusIndexChange(indicator);
793         return true;
794     }
795     if (event.code == KeyCode::KEY_MOVE_HOME) {
796         indicator = 0;
797         FocusIndexChange(indicator);
798         return true;
799     }
800     if (event.code == KeyCode::KEY_MOVE_END) {
801         indicator = host->TotalChildCount() - MASK_COUNT - 1;
802         FocusIndexChange(indicator);
803         return true;
804     }
805     return false;
806 }
807 
OnKeyEventWithoutClick(const KeyEvent & event)808 bool TabBarPattern::OnKeyEventWithoutClick(const KeyEvent& event)
809 {
810     auto host = GetHost();
811     CHECK_NULL_RETURN(host, false);
812     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
813     if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
814                               ? KeyCode::KEY_DPAD_LEFT
815                               : KeyCode::KEY_DPAD_UP) ||
816         event.IsShiftWith(KeyCode::KEY_TAB)) {
817         if (focusIndicator_ <= 0) {
818             return false;
819         }
820         if (!ContentWillChange(focusIndicator_ - 1)) {
821             return true;
822         }
823         focusIndicator_ -= 1;
824         PaintFocusState();
825         return true;
826     }
827     if (event.code == (tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL
828                               ? KeyCode::KEY_DPAD_RIGHT
829                               : KeyCode::KEY_DPAD_DOWN) ||
830         event.code == KeyCode::KEY_TAB) {
831         if (focusIndicator_ >= host->TotalChildCount() - MASK_COUNT - 1) {
832             return false;
833         }
834         if (!ContentWillChange(focusIndicator_ + 1)) {
835             return true;
836         }
837         focusIndicator_ += 1;
838         PaintFocusState();
839         return true;
840     }
841     return OnKeyEventWithoutClick(host, event);
842 }
843 
OnKeyEventWithoutClick(const RefPtr<FrameNode> & host,const KeyEvent & event)844 bool TabBarPattern::OnKeyEventWithoutClick(const RefPtr<FrameNode>& host, const KeyEvent& event)
845 {
846     if (event.code == KeyCode::KEY_MOVE_HOME) {
847         if (!ContentWillChange(0)) {
848             return true;
849         }
850         focusIndicator_ = 0;
851         PaintFocusState();
852         return true;
853     }
854     if (event.code == KeyCode::KEY_MOVE_END) {
855         if (!ContentWillChange(host->TotalChildCount() - MASK_COUNT - 1)) {
856             return true;
857         }
858         focusIndicator_ = host->TotalChildCount() - MASK_COUNT - 1;
859         PaintFocusState();
860         return true;
861     }
862     if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) {
863         TabBarClickEvent(focusIndicator_);
864         FocusIndexChange(focusIndicator_);
865         return true;
866     }
867     return false;
868 }
869 
FocusIndexChange(int32_t index)870 void TabBarPattern::FocusIndexChange(int32_t index)
871 {
872     auto host = GetHost();
873     CHECK_NULL_VOID(host);
874     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
875     CHECK_NULL_VOID(tabsNode);
876     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
877     CHECK_NULL_VOID(tabsPattern);
878     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
879     CHECK_NULL_VOID(tabBarLayoutProperty);
880 
881     if (!ContentWillChange(tabBarLayoutProperty->GetIndicatorValue(0), index)) {
882         return;
883     }
884     changeByClick_ = true;
885     clickRepeat_ = true;
886     SetSwiperCurve(DurationCubicCurve);
887     if (tabsPattern->GetIsCustomAnimation()) {
888         OnCustomContentTransition(indicator_, index);
889         tabBarLayoutProperty->UpdateIndicator(index);
890         PaintFocusState(false);
891     } else {
892         UpdateAnimationDuration();
893         if (GetAnimationDuration().has_value()
894             && tabsPattern->GetAnimateMode() != TabAnimateMode::NO_ANIMATION) {
895             tabContentWillChangeFlag_ = true;
896             swiperController_->SwipeTo(index);
897         } else {
898             swiperController_->SwipeToWithoutAnimation(index);
899         }
900 
901         tabBarLayoutProperty->UpdateIndicator(index);
902         PaintFocusState();
903     }
904     UpdateTextColorAndFontWeight(index);
905     UpdateSubTabBoard(index);
906 }
907 
GetInnerFocusPaintRect(RoundRect & paintRect)908 void TabBarPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
909 {
910     auto host = GetHost();
911     CHECK_NULL_VOID(host);
912     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
913     CHECK_NULL_VOID(tabBarLayoutProperty);
914     auto indicator = tabBarLayoutProperty->GetIndicatorValue(0);
915     if (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE || tabBarStyle_ == TabBarStyle::SUBTABBATSTYLE) {
916         if (isFirstFocus_) {
917             focusIndicator_ = indicator;
918         } else {
919             indicator = focusIndicator_;
920         }
921     }
922     auto childNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(indicator));
923     CHECK_NULL_VOID(childNode);
924     auto renderContext = childNode->GetRenderContext();
925     CHECK_NULL_VOID(renderContext);
926     auto columnPaintRect = renderContext->GetPaintRectWithoutTransform();
927     auto pipeline = PipelineContext::GetCurrentContext();
928     CHECK_NULL_VOID(pipeline);
929     auto tabTheme = pipeline->GetTheme<TabTheme>();
930     CHECK_NULL_VOID(tabTheme);
931     auto radius = tabTheme->GetFocusIndicatorRadius();
932     auto outLineWidth = tabTheme->GetActiveIndicatorWidth();
933     columnPaintRect.SetOffset(OffsetF((columnPaintRect.GetOffset().GetX() + outLineWidth.ConvertToPx() / 2),
934         (columnPaintRect.GetOffset().GetY() + outLineWidth.ConvertToPx() / 2)));
935     columnPaintRect.SetSize(SizeF((columnPaintRect.GetSize().Width() - outLineWidth.ConvertToPx()),
936         (columnPaintRect.GetSize().Height() - outLineWidth.ConvertToPx())));
937 
938     paintRect.SetRect(columnPaintRect);
939     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
940         static_cast<RSScalar>(radius.ConvertToPx()));
941     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
942         static_cast<RSScalar>(radius.ConvertToPx()));
943     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
944         static_cast<RSScalar>(radius.ConvertToPx()));
945     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(radius.ConvertToPx()),
946         static_cast<RSScalar>(radius.ConvertToPx()));
947 }
948 
PaintFocusState(bool needMarkDirty)949 void TabBarPattern::PaintFocusState(bool needMarkDirty)
950 {
951     auto host = GetHost();
952     CHECK_NULL_VOID(host);
953 
954     RoundRect focusRect;
955     GetInnerFocusPaintRect(focusRect);
956 
957     auto focusHub = host->GetFocusHub();
958     CHECK_NULL_VOID(focusHub);
959     focusHub->PaintInnerFocusState(focusRect);
960 
961     if (needMarkDirty) {
962         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
963     }
964 }
965 
OnModifyDone()966 void TabBarPattern::OnModifyDone()
967 {
968     Pattern::OnModifyDone();
969     auto host = GetHost();
970     CHECK_NULL_VOID(host);
971     auto hub = host->GetEventHub<EventHub>();
972     CHECK_NULL_VOID(hub);
973     auto gestureHub = hub->GetOrCreateGestureEventHub();
974     CHECK_NULL_VOID(gestureHub);
975 
976     AddMaskItemClickEvent();
977     InitTurnPageRateEvent();
978     auto pipelineContext = PipelineContext::GetCurrentContext();
979     CHECK_NULL_VOID(pipelineContext);
980     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
981         auto tabBarPaintProperty = host->GetPaintProperty<TabBarPaintProperty>();
982         CHECK_NULL_VOID(tabBarPaintProperty);
983         auto theme = pipelineContext->GetTheme<TabTheme>();
984         CHECK_NULL_VOID(theme);
985         auto defaultBlurStyle = static_cast<BlurStyle>(theme->GetBottomTabBackgroundBlurStyle());
986         if (defaultBlurStyle != BlurStyle::NO_MATERIAL) {
987             tabBarPaintProperty->UpdateTabBarBlurStyle(defaultBlurStyle);
988         }
989     }
990     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
991     CHECK_NULL_VOID(layoutProperty);
992     InitScrollableEvent(layoutProperty, gestureHub);
993     InitTouch(gestureHub);
994     InitHoverEvent();
995     InitMouseEvent();
996     SetSurfaceChangeCallback();
997     auto focusHub = host->GetFocusHub();
998     CHECK_NULL_VOID(focusHub);
999     InitOnKeyEvent(focusHub);
1000     SetAccessibilityAction();
1001     UpdateSubTabBoard(indicator_);
1002     StopTranslateAnimation();
1003     jumpIndex_ = layoutProperty->GetIndicatorValue(0);
1004 
1005     RemoveTabBarEventCallback();
1006     AddTabBarEventCallback();
1007 
1008     axis_ = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1009     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1010     CHECK_NULL_VOID(tabsNode);
1011     auto tabsLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
1012     CHECK_NULL_VOID(tabsLayoutProperty);
1013     isRTL_ = tabsLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
1014 }
1015 
SetSurfaceChangeCallback()1016 void TabBarPattern::SetSurfaceChangeCallback()
1017 {
1018     CHECK_NULL_VOID(swiperController_);
1019     auto surfaceChangeCallback = [weak = WeakClaim(this)]() {
1020         auto tabBarPattern = weak.Upgrade();
1021         CHECK_NULL_VOID(tabBarPattern);
1022         tabBarPattern->isTouchingSwiper_ = false;
1023     };
1024     swiperController_->SetSurfaceChangeCallback(std::move(surfaceChangeCallback));
1025 }
1026 
RemoveTabBarEventCallback()1027 void TabBarPattern::RemoveTabBarEventCallback()
1028 {
1029     CHECK_NULL_VOID(swiperController_);
1030     auto removeEventCallback = [weak = WeakClaim(this)]() {
1031         auto tabBarPattern = weak.Upgrade();
1032         CHECK_NULL_VOID(tabBarPattern);
1033         auto host = tabBarPattern->GetHost();
1034         CHECK_NULL_VOID(host);
1035         auto hub = host->GetEventHub<EventHub>();
1036         CHECK_NULL_VOID(hub);
1037         auto gestureHub = hub->GetOrCreateGestureEventHub();
1038         CHECK_NULL_VOID(gestureHub);
1039         auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1040         CHECK_NULL_VOID(layoutProperty);
1041         if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
1042             gestureHub->RemoveScrollableEvent(tabBarPattern->scrollableEvent_);
1043         }
1044         gestureHub->RemoveTouchEvent(tabBarPattern->touchEvent_);
1045         gestureHub->RemoveDragEvent();
1046         gestureHub->SetLongPressEvent(nullptr);
1047         tabBarPattern->longPressEvent_ = nullptr;
1048         tabBarPattern->dragEvent_ = nullptr;
1049         tabBarPattern->isTouchingSwiper_ = true;
1050         for (const auto& childNode : host->GetChildren()) {
1051             CHECK_NULL_VOID(childNode);
1052             auto frameNode = AceType::DynamicCast<FrameNode>(childNode);
1053             CHECK_NULL_VOID(frameNode);
1054             auto childHub = frameNode->GetEventHub<EventHub>();
1055             CHECK_NULL_VOID(childHub);
1056             auto childGestureHub = childHub->GetOrCreateGestureEventHub();
1057             CHECK_NULL_VOID(childGestureHub);
1058             auto iter = tabBarPattern->clickEvents_.find(frameNode->GetId());
1059             if (iter != tabBarPattern->clickEvents_.end()) {
1060                 childGestureHub->RemoveClickEvent(iter->second);
1061             }
1062         }
1063     };
1064     swiperController_->SetRemoveTabBarEventCallback(std::move(removeEventCallback));
1065 }
1066 
AddTabBarEventCallback()1067 void TabBarPattern::AddTabBarEventCallback()
1068 {
1069     CHECK_NULL_VOID(swiperController_);
1070     auto addEventCallback = [weak = WeakClaim(this)]() {
1071         auto tabBarPattern = weak.Upgrade();
1072         CHECK_NULL_VOID(tabBarPattern);
1073         auto host = tabBarPattern->GetHost();
1074         CHECK_NULL_VOID(host);
1075         auto hub = host->GetEventHub<EventHub>();
1076         CHECK_NULL_VOID(hub);
1077         auto gestureHub = hub->GetOrCreateGestureEventHub();
1078         CHECK_NULL_VOID(gestureHub);
1079         auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1080         CHECK_NULL_VOID(layoutProperty);
1081         if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
1082             gestureHub->AddScrollableEvent(tabBarPattern->scrollableEvent_);
1083         }
1084         gestureHub->AddTouchEvent(tabBarPattern->touchEvent_);
1085         for (const auto& childNode : host->GetChildren()) {
1086             CHECK_NULL_VOID(childNode);
1087             auto frameNode = AceType::DynamicCast<FrameNode>(childNode);
1088             CHECK_NULL_VOID(frameNode);
1089             auto childHub = frameNode->GetEventHub<EventHub>();
1090             CHECK_NULL_VOID(childHub);
1091             auto childGestureHub = childHub->GetOrCreateGestureEventHub();
1092             CHECK_NULL_VOID(childGestureHub);
1093             auto iter = tabBarPattern->clickEvents_.find(frameNode->GetId());
1094             if (iter != tabBarPattern->clickEvents_.end()) {
1095                 childGestureHub->AddClickEvent(iter->second);
1096             }
1097         }
1098         tabBarPattern->InitLongPressAndDragEvent();
1099     };
1100     swiperController_->SetAddTabBarEventCallback(std::move(addEventCallback));
1101 }
1102 
UpdatePaintIndicator(int32_t indicator,bool needMarkDirty)1103 void TabBarPattern::UpdatePaintIndicator(int32_t indicator, bool needMarkDirty)
1104 {
1105     auto tabBarNode = GetHost();
1106     CHECK_NULL_VOID(tabBarNode);
1107     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
1108     CHECK_NULL_VOID(tabBarPattern);
1109     auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
1110     if (indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
1111         return;
1112     }
1113     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1114     CHECK_NULL_VOID(layoutProperty);
1115     if (tabBarPattern->IsContainsBuilder() || layoutProperty->GetAxis() == Axis::VERTICAL ||
1116         tabBarStyles_[indicator] == TabBarStyle::BOTTOMTABBATSTYLE) {
1117         paintProperty->UpdateIndicator({});
1118 
1119         if (needMarkDirty) {
1120             tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1121         }
1122 
1123         return;
1124     }
1125 
1126     RectF rect = {};
1127     if (visibleItemPosition_.find(indicator) != visibleItemPosition_.end()) {
1128         rect = layoutProperty->GetIndicatorRect(indicator);
1129     }
1130     paintProperty->UpdateIndicator(rect);
1131     if (!isTouchingSwiper_ || tabBarStyles_[indicator] != TabBarStyle::SUBTABBATSTYLE) {
1132         currentIndicatorOffset_ = rect.GetX() + rect.Width() / 2;
1133 
1134         if (needMarkDirty) {
1135             tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1136         }
1137     }
1138 }
1139 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1140 bool TabBarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1141 {
1142     if (config.skipMeasure && config.skipLayout) {
1143         return false;
1144     }
1145     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
1146     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
1147     auto tabBarLayoutAlgorithm = DynamicCast<TabBarLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
1148     CHECK_NULL_RETURN(tabBarLayoutAlgorithm, false);
1149     currentDelta_ = 0.0f;
1150     canOverScroll_ = false;
1151     visibleItemPosition_ = tabBarLayoutAlgorithm->GetVisibleItemPosition();
1152     scrollMargin_ = tabBarLayoutAlgorithm->GetScrollMargin();
1153     jumpIndex_ = tabBarLayoutAlgorithm->GetJumpIndex();
1154     auto layoutProperty = DynamicCast<TabBarLayoutProperty>(dirty->GetLayoutProperty());
1155     auto host = GetHost();
1156     CHECK_NULL_RETURN(host, false);
1157     auto swiperPattern = GetSwiperPattern();
1158     CHECK_NULL_RETURN(swiperPattern, false);
1159     int32_t indicator = swiperPattern->GetCurrentIndex();
1160     int32_t totalCount = swiperPattern->TotalCount();
1161     if (indicator > totalCount - 1 || indicator < 0) {
1162         indicator = 0;
1163     }
1164     if (totalCount == 0) {
1165         isTouchingSwiper_ = false;
1166     }
1167     auto pipelineContext = GetHost()->GetContext();
1168     CHECK_NULL_RETURN(pipelineContext, false);
1169     if (targetIndex_) {
1170         TriggerTranslateAnimation(indicator_, targetIndex_.value());
1171         targetIndex_.reset();
1172     }
1173 
1174     if (swiperPattern->IsUseCustomAnimation()) {
1175         UpdateSubTabBoard(indicator);
1176         UpdatePaintIndicator(indicator, false);
1177     }
1178     if ((!swiperPattern->IsUseCustomAnimation() || isFirstLayout_) && !isAnimating_ && !IsMaskAnimationExecuted()) {
1179         UpdateSubTabBoard(indicator);
1180         UpdatePaintIndicator(indicator, true);
1181     }
1182     isFirstLayout_ = false;
1183     indicator_ = layoutProperty->GetIndicatorValue(0);
1184 
1185     if (windowSizeChangeReason_) {
1186         if (*windowSizeChangeReason_ == WindowSizeChangeReason::ROTATION &&
1187             animationTargetIndex_.value_or(indicator) != indicator) {
1188             swiperController_->SwipeToWithoutAnimation(animationTargetIndex_.value());
1189             animationTargetIndex_.reset();
1190             windowSizeChangeReason_.reset();
1191         } else if (prevRootSize_.first != PipelineContext::GetCurrentRootWidth() ||
1192             prevRootSize_.second != PipelineContext::GetCurrentRootHeight()) {
1193             StopTranslateAnimation();
1194             jumpIndex_ = indicator_;
1195             UpdateSubTabBoard(indicator_);
1196             UpdateIndicator(indicator_);
1197             windowSizeChangeReason_.reset();
1198             host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1199         }
1200     }
1201     UpdateGradientRegions(!swiperPattern->IsUseCustomAnimation());
1202     if (!swiperPattern->IsUseCustomAnimation() && isTouchingSwiper_ &&
1203         layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
1204         ApplyTurnPageRateToIndicator(turnPageRate_);
1205     }
1206     return false;
1207 }
1208 
CustomizeExpandSafeArea()1209 bool TabBarPattern::CustomizeExpandSafeArea()
1210 {
1211     auto host = GetHost();
1212     CHECK_NULL_RETURN(host, false);
1213     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1214     CHECK_NULL_RETURN(tabsNode, false);
1215     auto tabLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
1216     CHECK_NULL_RETURN(tabLayoutProperty, false);
1217     return tabLayoutProperty->GetSafeAreaPaddingProperty() ? true : false;
1218 }
1219 
OnSyncGeometryNode(const DirtySwapConfig & config)1220 void TabBarPattern::OnSyncGeometryNode(const DirtySwapConfig& config)
1221 {
1222     auto host = GetHost();
1223     CHECK_NULL_VOID(host);
1224     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1225     CHECK_NULL_VOID(tabsNode);
1226     auto tabLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
1227     CHECK_NULL_VOID(tabLayoutProperty);
1228     if (!tabLayoutProperty->GetSafeAreaPaddingProperty()) {
1229         return;
1230     }
1231     auto tabBarSize = host->GetGeometryNode()->GetMarginFrameSize();
1232     auto tabBarOffset = host->GetGeometryNode()->GetMarginFrameOffset();
1233     auto tabsExpandEdges = tabsNode->GetAccumulatedSafeAreaExpand();
1234     auto tabBarExpandEdges = host->GetAccumulatedSafeAreaExpand();
1235     auto tabBarRect = RectF(tabBarOffset.GetX(), tabBarOffset.GetY(), tabBarSize.Width(),
1236         tabBarSize.Height() + tabsExpandEdges.bottom.value_or(0) + tabBarExpandEdges.bottom.value_or(0));
1237     auto tabBarRenderContext = host->GetRenderContext();
1238     CHECK_NULL_VOID(tabBarRenderContext);
1239     tabBarRenderContext->UpdatePaintRect(tabBarRect);
1240 }
1241 
InitLongPressAndDragEvent()1242 void TabBarPattern::InitLongPressAndDragEvent()
1243 {
1244     auto host = GetHost();
1245     CHECK_NULL_VOID(host);
1246     auto hub = host->GetEventHub<EventHub>();
1247     CHECK_NULL_VOID(hub);
1248     auto gestureHub = hub->GetOrCreateGestureEventHub();
1249     CHECK_NULL_VOID(gestureHub);
1250     auto pipelineContext = PipelineContext::GetCurrentContext();
1251     CHECK_NULL_VOID(pipelineContext);
1252     float scale = pipelineContext->GetFontScale();
1253 
1254     bigScale_ = AgingAdapationDialogUtil::GetDialogBigFontSizeScale();
1255     largeScale_ = AgingAdapationDialogUtil::GetDialogLargeFontSizeScale();
1256     maxScale_ = AgingAdapationDialogUtil::GetDialogMaxFontSizeScale();
1257 
1258     if (tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE && scale >= bigScale_) {
1259         InitLongPressEvent(gestureHub);
1260         InitDragEvent(gestureHub);
1261     } else {
1262         gestureHub->RemoveDragEvent();
1263         gestureHub->SetLongPressEvent(nullptr);
1264         longPressEvent_ = nullptr;
1265         dragEvent_ = nullptr;
1266     }
1267 }
1268 
HandleLongPressEvent(const GestureEvent & info)1269 void TabBarPattern::HandleLongPressEvent(const GestureEvent& info)
1270 {
1271     auto index = CalculateSelectedIndex(info.GetLocalLocation());
1272     HandleClick(info.GetSourceDevice(), index);
1273     ShowDialogWithNode(index);
1274 }
1275 
ShowDialogWithNode(int32_t index)1276 void TabBarPattern::ShowDialogWithNode(int32_t index)
1277 {
1278     auto tabBarNode = GetHost();
1279     CHECK_NULL_VOID(tabBarNode);
1280     auto columnNode = AceType::DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(index));
1281     CHECK_NULL_VOID(columnNode);
1282     RefPtr<FrameNode> imageNode = nullptr;
1283     RefPtr<FrameNode> textNode = nullptr;
1284     FindTextAndImageNode(columnNode, textNode, imageNode);
1285     CHECK_NULL_VOID(imageNode);
1286     CHECK_NULL_VOID(textNode);
1287 
1288     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1289     CHECK_NULL_VOID(textLayoutProperty);
1290     auto textValue = textLayoutProperty->GetContent();
1291     if (imageNode->GetTag() == V2::SYMBOL_ETS_TAG) {
1292         dialogNode_ = AgingAdapationDialogUtil::ShowLongPressDialog(textValue.value_or(""), imageNode);
1293     } else {
1294         auto imageProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1295         CHECK_NULL_VOID(imageProperty);
1296         ImageSourceInfo imageSourceInfo = imageProperty->GetImageSourceInfoValue();
1297         dialogNode_ = AgingAdapationDialogUtil::ShowLongPressDialog(textValue.value_or(""), imageSourceInfo);
1298     }
1299 }
1300 
CloseDialog()1301 void TabBarPattern::CloseDialog()
1302 {
1303     auto pipelineContext = PipelineContext::GetCurrentContext();
1304     CHECK_NULL_VOID(pipelineContext);
1305     auto context = AceType::DynamicCast<NG::PipelineContext>(pipelineContext);
1306     CHECK_NULL_VOID(context);
1307     auto overlayManager = context->GetOverlayManager();
1308     CHECK_NULL_VOID(overlayManager);
1309     overlayManager->CloseDialog(dialogNode_);
1310     dialogNode_.Reset();
1311 }
1312 
HandleClick(SourceType type,int32_t index)1313 void TabBarPattern::HandleClick(SourceType type, int32_t index)
1314 {
1315     if (type == SourceType::KEYBOARD) {
1316         return;
1317     }
1318     auto host = GetHost();
1319     CHECK_NULL_VOID(host);
1320     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1321     CHECK_NULL_VOID(layoutProperty);
1322     if (layoutProperty->GetTabBarModeValue(TabBarMode::FIXED) == TabBarMode::SCROLLABLE && scrollableEvent_) {
1323         auto scrollable = scrollableEvent_->GetScrollable();
1324         if (scrollable) {
1325             if (IsOutOfBoundary()) {
1326                 return;
1327             }
1328             scrollable->StopScrollable();
1329         }
1330     }
1331 
1332     auto totalCount = host->TotalChildCount() - MASK_COUNT;
1333     if (totalCount < 0) {
1334         return;
1335     }
1336 
1337     TAG_LOGI(AceLogTag::ACE_TABS, "Clicked tabBarIndex: %{public}d", index);
1338     if (index < 0 || index >= totalCount || !swiperController_ ||
1339         indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
1340         return;
1341     }
1342     SetSwiperCurve(DurationCubicCurve);
1343 
1344     TabBarClickEvent(index);
1345     if (!ContentWillChange(layoutProperty->GetIndicatorValue(0), index)) {
1346         return;
1347     }
1348     if (tabBarStyles_[indicator_] == TabBarStyle::SUBTABBATSTYLE &&
1349         tabBarStyles_[index] == TabBarStyle::SUBTABBATSTYLE &&
1350         layoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1351         HandleSubTabBarClick(layoutProperty, index);
1352         return;
1353     }
1354     ClickTo(host, index);
1355     layoutProperty->UpdateIndicator(index);
1356 }
1357 
ClickTo(const RefPtr<FrameNode> & host,int32_t index)1358 void TabBarPattern::ClickTo(const RefPtr<FrameNode>& host, int32_t index)
1359 {
1360     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1361     CHECK_NULL_VOID(tabsNode);
1362     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
1363     CHECK_NULL_VOID(tabsPattern);
1364     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1365     CHECK_NULL_VOID(layoutProperty);
1366     int32_t indicator = layoutProperty->GetIndicatorValue(0);
1367     if (!tabsPattern->GetIsCustomAnimation() && indicator == index) {
1368         return;
1369     }
1370     swiperController_->FinishAnimation();
1371     UpdateAnimationDuration();
1372     auto duration = GetAnimationDuration().value_or(0);
1373     if (tabsPattern->GetIsCustomAnimation()) {
1374         OnCustomContentTransition(indicator, index);
1375     } else {
1376         if (duration > 0 && tabsPattern->GetAnimateMode() != TabAnimateMode::NO_ANIMATION) {
1377             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_TAB_SWITCH, PerfActionType::LAST_UP, "");
1378             tabContentWillChangeFlag_ = true;
1379             swiperController_->SwipeTo(index);
1380             animationTargetIndex_ = index;
1381         } else {
1382             swiperController_->SwipeToWithoutAnimation(index);
1383         }
1384     }
1385 
1386     changeByClick_ = true;
1387     clickRepeat_ = true;
1388     if (duration > 0 && CanScroll()) {
1389         targetIndex_ = index;
1390     } else {
1391         jumpIndex_ = index;
1392     }
1393     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1394 }
1395 
HandleBottomTabBarChange(int32_t index)1396 void TabBarPattern::HandleBottomTabBarChange(int32_t index)
1397 {
1398     AnimationUtils::StopAnimation(maskAnimation_);
1399     auto preIndex = GetImageColorOnIndex().value_or(indicator_);
1400     if (preIndex == index) {
1401         return;
1402     }
1403     UpdateImageColor(index);
1404     UpdateSymbolStats(index, preIndex);
1405     if (preIndex < 0 || preIndex >= static_cast<int32_t>(tabBarStyles_.size()) ||
1406         index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size())) {
1407         return;
1408     }
1409     if (preIndex != index && (tabBarStyles_[preIndex] == TabBarStyle::BOTTOMTABBATSTYLE ||
1410                                    tabBarStyles_[index] == TabBarStyle::BOTTOMTABBATSTYLE)) {
1411         auto host = GetHost();
1412         CHECK_NULL_VOID(host);
1413         auto childCount = host->TotalChildCount() - MASK_COUNT;
1414         int32_t selectedIndex = -1;
1415         int32_t unselectedIndex = -1;
1416         if (preIndex < childCount && tabBarStyles_[preIndex] == TabBarStyle::BOTTOMTABBATSTYLE && CheckSvg(preIndex)) {
1417             unselectedIndex = preIndex;
1418         }
1419         if (index < childCount && tabBarStyles_[index] == TabBarStyle::BOTTOMTABBATSTYLE && CheckSvg(index)) {
1420             selectedIndex = index;
1421         }
1422         HandleBottomTabBarClick(selectedIndex, unselectedIndex);
1423     }
1424 }
1425 
CheckSvg(int32_t index) const1426 bool TabBarPattern::CheckSvg(int32_t index) const
1427 {
1428     auto host = GetHost();
1429     CHECK_NULL_RETURN(host, false);
1430     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1431     CHECK_NULL_RETURN(columnNode, false);
1432     auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
1433     CHECK_NULL_RETURN(imageNode, false);
1434     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1435     CHECK_NULL_RETURN(imageLayoutProperty, false);
1436     ImageSourceInfo info;
1437     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
1438     return imageSourceInfo.IsSvg();
1439 }
1440 
HandleBottomTabBarClick(int32_t selectedIndex,int32_t unselectedIndex)1441 void TabBarPattern::HandleBottomTabBarClick(int32_t selectedIndex, int32_t unselectedIndex)
1442 {
1443     auto host = GetHost();
1444     CHECK_NULL_VOID(host);
1445     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1446     CHECK_NULL_VOID(layoutProperty);
1447 
1448     std::vector<int32_t> selectedIndexes = {selectedIndex, unselectedIndex};
1449     OffsetF originalSelectedMaskOffset, originalUnselectedMaskOffset;
1450     float selectedImageSize = 0.0f, unselectedImageSize = 0.0f;
1451     for (int32_t maskIndex = 0; maskIndex < MASK_COUNT; maskIndex++) {
1452         if (maskIndex == 0) {
1453             layoutProperty->UpdateSelectedMask(selectedIndex);
1454         } else {
1455             layoutProperty->UpdateUnselectedMask(unselectedIndex);
1456         }
1457         if (selectedIndexes[maskIndex] < 0) {
1458             continue;
1459         }
1460         GetBottomTabBarImageSizeAndOffset(selectedIndexes, maskIndex, selectedImageSize, unselectedImageSize,
1461             originalSelectedMaskOffset, originalUnselectedMaskOffset);
1462     }
1463     ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, NO_OPACITY, HALF_MASK_RADIUS_RATIO, true);
1464     ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset, FULL_OPACITY,
1465         FULL_MASK_RADIUS_RATIO, false);
1466 
1467     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1468     PlayMaskAnimation(selectedImageSize, originalSelectedMaskOffset, selectedIndex, unselectedImageSize,
1469         originalUnselectedMaskOffset, unselectedIndex);
1470 }
1471 
GetBottomTabBarImageSizeAndOffset(const std::vector<int32_t> & selectedIndexes,int32_t maskIndex,float & selectedImageSize,float & unselectedImageSize,OffsetF & originalSelectedMaskOffset,OffsetF & originalUnselectedMaskOffset)1472 void TabBarPattern::GetBottomTabBarImageSizeAndOffset(const std::vector<int32_t>& selectedIndexes, int32_t maskIndex,
1473     float& selectedImageSize, float& unselectedImageSize, OffsetF& originalSelectedMaskOffset,
1474     OffsetF& originalUnselectedMaskOffset)
1475 {
1476     auto pipelineContext = PipelineContext::GetCurrentContext();
1477     CHECK_NULL_VOID(pipelineContext);
1478     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1479     CHECK_NULL_VOID(tabTheme);
1480 
1481     auto host = GetHost();
1482     CHECK_NULL_VOID(host);
1483 
1484     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndexes[maskIndex]));
1485     CHECK_NULL_VOID(columnNode);
1486     auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
1487     CHECK_NULL_VOID(imageNode);
1488     auto imageGeometryNode = imageNode->GetGeometryNode();
1489     CHECK_NULL_VOID(imageGeometryNode);
1490     auto imageOffset = imageGeometryNode->GetFrameOffset();
1491     auto imageSize = imageGeometryNode->GetFrameSize().Width();
1492     if (maskIndex == 0) {
1493         selectedImageSize = imageSize;
1494     } else {
1495         unselectedImageSize = imageSize;
1496     }
1497     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1498     CHECK_NULL_VOID(imageLayoutProperty);
1499     ImageSourceInfo info;
1500     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
1501 
1502     auto maskPosition = host->GetChildren().size() - MASK_COUNT;
1503     if (maskPosition < 0) {
1504         return;
1505     }
1506     auto selectedMaskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(maskPosition + maskIndex));
1507     CHECK_NULL_VOID(selectedMaskNode);
1508     selectedMaskNode->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::LTR);
1509     if (maskIndex == 0) {
1510         originalSelectedMaskOffset = imageOffset;
1511     } else {
1512         originalUnselectedMaskOffset = imageOffset;
1513     }
1514     auto selectedImageNode = AceType::DynamicCast<FrameNode>(selectedMaskNode->GetChildren().front());
1515     CHECK_NULL_VOID(selectedImageNode);
1516 
1517     auto selectedImageLayoutProperty = selectedImageNode->GetLayoutProperty<ImageLayoutProperty>();
1518     CHECK_NULL_VOID(selectedImageLayoutProperty);
1519     UpdateBottomTabBarImageColor(selectedIndexes, maskIndex);
1520     selectedImageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1521     imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1522 
1523     selectedImageNode->MarkModifyDone();
1524     selectedImageNode->MarkDirtyNode();
1525     imageNode->MarkModifyDone();
1526     imageNode->MarkDirtyNode();
1527 }
1528 
UpdateBottomTabBarImageColor(const std::vector<int32_t> & selectedIndexes,int32_t maskIndex)1529 void TabBarPattern::UpdateBottomTabBarImageColor(const std::vector<int32_t>& selectedIndexes, int32_t maskIndex)
1530 {
1531     auto pipelineContext = PipelineContext::GetCurrentContext();
1532     CHECK_NULL_VOID(pipelineContext);
1533     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1534     CHECK_NULL_VOID(tabTheme);
1535 
1536     auto host = GetHost();
1537     CHECK_NULL_VOID(host);
1538 
1539     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndexes[maskIndex]));
1540     CHECK_NULL_VOID(columnNode);
1541     auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
1542     CHECK_NULL_VOID(imageNode);
1543 
1544     auto maskPosition = host->GetChildren().size() - MASK_COUNT;
1545     if (maskPosition < 0) {
1546         return;
1547     }
1548     auto selectedMaskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(maskPosition + maskIndex));
1549     CHECK_NULL_VOID(selectedMaskNode);
1550     auto selectedImageNode = AceType::DynamicCast<FrameNode>(selectedMaskNode->GetChildren().front());
1551     CHECK_NULL_VOID(selectedImageNode);
1552 
1553     auto selectedImagePaintProperty = selectedImageNode->GetPaintProperty<ImageRenderProperty>();
1554     CHECK_NULL_VOID(selectedImagePaintProperty);
1555     auto unselectedImagePaintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
1556     CHECK_NULL_VOID(unselectedImagePaintProperty);
1557     if (selectedIndexes[maskIndex] >= 0 && selectedIndexes[maskIndex] < static_cast<int32_t>(iconStyles_.size())) {
1558         if (iconStyles_[selectedIndexes[maskIndex]].selectedColor.has_value()) {
1559             selectedImagePaintProperty->UpdateSvgFillColor(
1560                 iconStyles_[selectedIndexes[maskIndex]].selectedColor.value());
1561         } else {
1562             selectedImagePaintProperty->UpdateSvgFillColor(tabTheme->GetBottomTabIconOn());
1563         }
1564 
1565         if (iconStyles_[selectedIndexes[maskIndex]].unselectedColor.has_value()) {
1566             unselectedImagePaintProperty->UpdateSvgFillColor(
1567                 iconStyles_[selectedIndexes[maskIndex]].unselectedColor.value());
1568         } else {
1569             unselectedImagePaintProperty->UpdateSvgFillColor(tabTheme->GetBottomTabIconOff());
1570         }
1571     }
1572 }
1573 
PlayMaskAnimation(float selectedImageSize,const OffsetF & originalSelectedMaskOffset,int32_t selectedIndex,float unselectedImageSize,const OffsetF & originalUnselectedMaskOffset,int32_t unselectedIndex)1574 void TabBarPattern::PlayMaskAnimation(float selectedImageSize,
1575     const OffsetF& originalSelectedMaskOffset, int32_t selectedIndex, float unselectedImageSize,
1576     const OffsetF& originalUnselectedMaskOffset, int32_t unselectedIndex)
1577 {
1578     auto curve = AceType::MakeRefPtr<CubicCurve>(0.4f, 0.0f, 0.2f, 1.0f);
1579     AnimationOption option;
1580     option.SetDuration(MASK_ANIMATION_DURATION);
1581     option.SetCurve(curve);
1582 
1583     maskAnimation_ = AnimationUtils::StartAnimation(
1584         option,
1585         [weak = AceType::WeakClaim(this), selectedIndex, unselectedIndex, selectedImageSize, originalSelectedMaskOffset,
1586             unselectedImageSize, originalUnselectedMaskOffset]() {
1587             AnimationUtils::AddKeyFrame(
1588                 HALF_PROGRESS, [weak, selectedIndex, unselectedIndex, selectedImageSize, originalSelectedMaskOffset,
1589                                    unselectedImageSize, originalUnselectedMaskOffset]() {
1590                     auto tabBar = weak.Upgrade();
1591                     if (tabBar) {
1592                         tabBar->ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, FULL_OPACITY,
1593                             INVALID_RATIO, true);
1594                         tabBar->ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset,
1595                             NEAR_FULL_OPACITY, INVALID_RATIO, false);
1596                     }
1597                 });
1598             AnimationUtils::AddKeyFrame(
1599                 FULL_PROGRESS, [weak, selectedIndex, unselectedIndex, selectedImageSize, originalSelectedMaskOffset,
1600                                    unselectedImageSize, originalUnselectedMaskOffset]() {
1601                     auto tabBar = weak.Upgrade();
1602                     if (tabBar) {
1603                         tabBar->ChangeMask(selectedIndex, selectedImageSize, originalSelectedMaskOffset, FULL_OPACITY,
1604                             FULL_MASK_RADIUS_RATIO, true);
1605                         tabBar->ChangeMask(unselectedIndex, unselectedImageSize, originalUnselectedMaskOffset,
1606                             NO_OPACITY, HALF_MASK_RADIUS_RATIO, false);
1607                     }
1608                 });
1609         },
1610         [weak = AceType::WeakClaim(this), selectedIndex, unselectedIndex]() {
1611             auto tabBar = weak.Upgrade();
1612             if (tabBar) {
1613                 auto host = tabBar->GetHost();
1614                 CHECK_NULL_VOID(host);
1615                 MaskAnimationFinish(host, selectedIndex, true);
1616                 MaskAnimationFinish(host, unselectedIndex, false);
1617             }
1618         });
1619 }
1620 
MaskAnimationFinish(const RefPtr<FrameNode> & host,int32_t selectedIndex,bool isSelected)1621 void TabBarPattern::MaskAnimationFinish(const RefPtr<FrameNode>& host, int32_t selectedIndex,
1622     bool isSelected)
1623 {
1624     if (selectedIndex < 0) {
1625         return;
1626     }
1627     auto tabBarLayoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1628     CHECK_NULL_VOID(tabBarLayoutProperty);
1629     if (isSelected) {
1630         tabBarLayoutProperty->UpdateSelectedMask(-1);
1631     } else {
1632         tabBarLayoutProperty->UpdateUnselectedMask(-1);
1633     }
1634 
1635     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
1636     CHECK_NULL_VOID(columnNode);
1637     auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
1638     CHECK_NULL_VOID(imageNode);
1639 
1640     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
1641     CHECK_NULL_VOID(imageLayoutProperty);
1642     auto imagePaintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
1643     CHECK_NULL_VOID(imagePaintProperty);
1644     ImageSourceInfo info;
1645     auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
1646 
1647     auto pipelineContext = PipelineContext::GetCurrentContext();
1648     CHECK_NULL_VOID(pipelineContext);
1649     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1650     CHECK_NULL_VOID(tabTheme);
1651     auto tabBarPattern = host->GetPattern<TabBarPattern>();
1652     CHECK_NULL_VOID(tabBarPattern);
1653     auto iconStyles = tabBarPattern->GetIconStyle();
1654     if (selectedIndex >= 0 && selectedIndex < static_cast<int32_t>(iconStyles.size())) {
1655         if (isSelected) {
1656             if (iconStyles[selectedIndex].selectedColor.has_value()) {
1657                 imagePaintProperty->UpdateSvgFillColor(iconStyles[selectedIndex].selectedColor.value());
1658             } else {
1659                 imagePaintProperty->UpdateSvgFillColor(tabTheme->GetBottomTabIconOn());
1660             }
1661         } else {
1662             if (iconStyles[selectedIndex].unselectedColor.has_value()) {
1663                 imagePaintProperty->UpdateSvgFillColor(iconStyles[selectedIndex].unselectedColor.value());
1664             } else {
1665                 imagePaintProperty->UpdateSvgFillColor(tabTheme->GetBottomTabIconOff());
1666             }
1667         }
1668     }
1669     imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1670 
1671     host->MarkDirtyNode();
1672     imageNode->MarkModifyDone();
1673     imageNode->MarkDirtyNode();
1674 }
1675 
ChangeMask(int32_t index,float imageSize,const OffsetF & originalMaskOffset,float opacity,float radiusRatio,bool isSelected)1676 void TabBarPattern::ChangeMask(int32_t index, float imageSize, const OffsetF& originalMaskOffset, float opacity,
1677     float radiusRatio, bool isSelected)
1678 {
1679     auto host = GetHost();
1680     CHECK_NULL_VOID(host);
1681     auto maskPosition = host->GetChildren().size() - MASK_COUNT;
1682     if (index < 0 || NearZero(imageSize) || maskPosition < 0) {
1683         return;
1684     }
1685 
1686     auto maskNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(maskPosition + !isSelected));
1687     CHECK_NULL_VOID(maskNode);
1688     auto maskImageNode = AceType::DynamicCast<FrameNode>(maskNode->GetChildren().front());
1689     CHECK_NULL_VOID(maskImageNode);
1690     auto maskImageRenderContext = maskImageNode->GetRenderContext();
1691     CHECK_NULL_VOID(maskImageRenderContext);
1692 
1693     if (NonNegative(radiusRatio)) {
1694         auto maskRenderContext = maskNode->GetRenderContext();
1695         CHECK_NULL_VOID(maskRenderContext);
1696         auto maskGeometryNode = maskNode->GetGeometryNode();
1697         CHECK_NULL_VOID(maskGeometryNode);
1698         auto tabBarNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1699         CHECK_NULL_VOID(tabBarNode);
1700         auto tabBarGeometryNode = tabBarNode->GetGeometryNode();
1701         CHECK_NULL_VOID(tabBarGeometryNode);
1702 
1703         OffsetF maskOffset = originalMaskOffset;
1704         maskOffset.AddX(-imageSize * radiusRatio);
1705         maskOffset.AddY(imageSize * (1.0f - radiusRatio));
1706         auto tabBarOffset = tabBarGeometryNode->GetMarginFrameOffset();
1707         maskGeometryNode->SetMarginFrameOffset(maskOffset + tabBarOffset);
1708         maskGeometryNode->SetFrameSize(SizeF(imageSize * radiusRatio * 2.0f, imageSize * radiusRatio * 2.0f));
1709         maskRenderContext->SavePaintRect();
1710         maskRenderContext->SyncGeometryProperties(nullptr);
1711         BorderRadiusProperty borderRadiusProperty;
1712         borderRadiusProperty.SetRadius(Dimension(imageSize * radiusRatio));
1713         maskRenderContext->UpdateBorderRadius(borderRadiusProperty);
1714         maskImageRenderContext->UpdateOffset(OffsetT<Dimension>(Dimension(imageSize * radiusRatio),
1715             Dimension(imageSize * (radiusRatio - 1.0f))));
1716         auto maskImageGeometryNode = maskImageNode->GetGeometryNode();
1717         CHECK_NULL_VOID(maskImageGeometryNode);
1718         maskImageGeometryNode->SetFrameSize(SizeF(imageSize, imageSize));
1719         auto maskImageProperty = maskImageNode->GetLayoutProperty<ImageLayoutProperty>();
1720         CHECK_NULL_VOID(maskImageProperty);
1721         maskImageProperty->UpdateUserDefinedIdealSize(
1722             CalcSize(NG::CalcLength(Dimension(imageSize)), NG::CalcLength(Dimension(imageSize))));
1723         maskImageRenderContext->SetVisible(false);
1724         maskImageRenderContext->SavePaintRect();
1725         maskImageRenderContext->SyncGeometryProperties(nullptr);
1726     }
1727     maskImageRenderContext->UpdateOpacity(opacity);
1728 }
1729 
HandleSubTabBarClick(const RefPtr<TabBarLayoutProperty> & layoutProperty,int32_t index)1730 void TabBarPattern::HandleSubTabBarClick(const RefPtr<TabBarLayoutProperty>& layoutProperty, int32_t index)
1731 {
1732     auto host = GetHost();
1733     CHECK_NULL_VOID(host);
1734     auto tabsFrameNode = AceType::DynamicCast<TabsNode>(host->GetParent());
1735     CHECK_NULL_VOID(tabsFrameNode);
1736     auto tabsPattern = tabsFrameNode->GetPattern<TabsPattern>();
1737     CHECK_NULL_VOID(tabsPattern);
1738     int32_t indicator = layoutProperty->GetIndicatorValue(0);
1739     if (!tabsPattern->GetIsCustomAnimation() && indicator == index) {
1740         return;
1741     }
1742     swiperController_->FinishAnimation();
1743     changeByClick_ = true;
1744     clickRepeat_ = true;
1745     UpdateAnimationDuration();
1746     auto duration = GetAnimationDuration().value_or(0);
1747     if (tabsPattern->GetIsCustomAnimation()) {
1748         OnCustomContentTransition(indicator, index);
1749     } else {
1750         if (duration> 0 && tabsPattern->GetAnimateMode() != TabAnimateMode::NO_ANIMATION) {
1751             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_TAB_SWITCH, PerfActionType::LAST_UP, "");
1752             tabContentWillChangeFlag_ = true;
1753             swiperController_->SwipeTo(index);
1754         } else {
1755             swiperController_->SwipeToWithoutAnimation(index);
1756         }
1757     }
1758     if (duration > 0 && CanScroll()) {
1759         targetIndex_ = index;
1760     } else if (duration <= 0) {
1761         jumpIndex_ = index;
1762     } else {
1763         TriggerTranslateAnimation(indicator, index);
1764     }
1765     swiperStartIndex_ = indicator;
1766     animationTargetIndex_ = index;
1767     UpdateTextColorAndFontWeight(index);
1768     UpdateSubTabBoard(index);
1769     layoutProperty->UpdateIndicator(index);
1770     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1771 }
1772 
HandleTouchEvent(const TouchLocationInfo & info)1773 void TabBarPattern::HandleTouchEvent(const TouchLocationInfo& info)
1774 {
1775     auto host = GetHost();
1776     CHECK_NULL_VOID(host);
1777     auto touchType = info.GetTouchType();
1778     auto index = CalculateSelectedIndex(info.GetLocalLocation());
1779     if ((touchType == TouchType::UP || touchType == TouchType::CANCEL) && dialogNode_) {
1780         HandleClick(info.GetSourceDevice(), index);
1781         CloseDialog();
1782     }
1783 
1784     if (IsContainsBuilder()) {
1785         return;
1786     }
1787 
1788     auto totalCount = host->TotalChildCount() - MASK_COUNT;
1789     if (totalCount < 0) {
1790         return;
1791     }
1792 
1793     if (touchType == TouchType::DOWN && index >= 0 && index < totalCount) {
1794         HandleTouchDown(index);
1795         touchingIndex_ = index;
1796         return;
1797     }
1798 
1799     if ((touchType == TouchType::UP || touchType == TouchType::CANCEL) && touchingIndex_.has_value()) {
1800         HandleTouchUp(index);
1801         touchingIndex_.reset();
1802     }
1803 }
1804 
CalculateSelectedIndex(const Offset & info)1805 int32_t TabBarPattern::CalculateSelectedIndex(const Offset& info)
1806 {
1807     if (visibleItemPosition_.empty()) {
1808         return -1;
1809     }
1810     auto host = GetHost();
1811     CHECK_NULL_RETURN(host, -1);
1812     auto geometryNode = host->GetGeometryNode();
1813     CHECK_NULL_RETURN(geometryNode, -1);
1814     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
1815     CHECK_NULL_RETURN(layoutProperty, -1);
1816     auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
1817     auto mainSize = geometryNode->GetFrameSize().MainSize(axis);
1818     auto local = isRTL_ && axis == Axis::HORIZONTAL ? OffsetF(mainSize - info.GetX(), info.GetY())
1819                                                     : OffsetF(info.GetX(), info.GetY());
1820     auto leftPadding = GetLeftPadding();
1821     for (auto& iter : visibleItemPosition_) {
1822         if (GreatOrEqual(local.GetMainOffset(axis), iter.second.startPos + leftPadding) &&
1823             LessOrEqual(local.GetMainOffset(axis), iter.second.endPos + leftPadding)) {
1824             return iter.first;
1825         }
1826     }
1827     return -1;
1828 }
1829 
HandleTouchDown(int32_t index)1830 void TabBarPattern::HandleTouchDown(int32_t index)
1831 {
1832     const auto& removeSwiperEventCallback = swiperController_->GetRemoveSwiperEventCallback();
1833     if (removeSwiperEventCallback) {
1834         removeSwiperEventCallback();
1835     }
1836     SetTouching(true);
1837     auto pipelineContext = PipelineContext::GetCurrentContext();
1838     CHECK_NULL_VOID(pipelineContext);
1839     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1840     CHECK_NULL_VOID(tabTheme);
1841     PlayPressAnimation(index, tabTheme->GetSubTabBarPressedColor(), AnimationType::PRESS);
1842 }
1843 
HandleTouchUp(int32_t index)1844 void TabBarPattern::HandleTouchUp(int32_t index)
1845 {
1846     const auto& addSwiperEventCallback = swiperController_->GetAddSwiperEventCallback();
1847     if (addSwiperEventCallback) {
1848         addSwiperEventCallback();
1849     }
1850     auto pipelineContext = PipelineContext::GetCurrentContext();
1851     CHECK_NULL_VOID(pipelineContext);
1852     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1853     CHECK_NULL_VOID(tabTheme);
1854     if (IsTouching()) {
1855         SetTouching(false);
1856         if (hoverIndex_.has_value() && touchingIndex_.value_or(-1) == index) {
1857             PlayPressAnimation(index, tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVERTOPRESS);
1858             return;
1859         }
1860         PlayPressAnimation(touchingIndex_.value_or(-1), Color::TRANSPARENT, AnimationType::PRESS);
1861         if (hoverIndex_.has_value()) {
1862             PlayPressAnimation(hoverIndex_.value(), tabTheme->GetSubTabBarHoverColor(), AnimationType::HOVER);
1863         }
1864     }
1865 }
1866 
PlayPressAnimation(int32_t index,const Color & pressColor,AnimationType animationType)1867 void TabBarPattern::PlayPressAnimation(int32_t index, const Color& pressColor, AnimationType animationType)
1868 {
1869     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE) &&
1870         tabBarStyle_ == TabBarStyle::BOTTOMTABBATSTYLE) {
1871         return;
1872     }
1873     auto pipelineContext = PipelineContext::GetCurrentContext();
1874     CHECK_NULL_VOID(pipelineContext);
1875     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1876     CHECK_NULL_VOID(tabTheme);
1877     AnimationOption option = AnimationOption();
1878     option.SetDuration(animationType == AnimationType::HOVERTOPRESS
1879                            ? static_cast<int32_t>(tabTheme->GetSubTabBarHoverToPressDuration())
1880                            : static_cast<int32_t>(tabTheme->GetSubTabBarHoverDuration()));
1881     option.SetDelay(0);
1882     option.SetCurve(animationType == AnimationType::PRESS   ? DurationCubicCurve
1883                     : animationType == AnimationType::HOVER ? Curves::FRICTION
1884                                                             : Curves::SHARP);
1885     option.SetFillMode(FillMode::FORWARDS);
1886     Color color = pressColor;
1887     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1888     CHECK_NULL_VOID(layoutProperty);
1889     auto totalCount = GetHost()->TotalChildCount() - MASK_COUNT;
1890     if (index < 0 || index >= totalCount || index >= static_cast<int32_t>(tabBarStyles_.size())) {
1891         return;
1892     }
1893     if (color == Color::TRANSPARENT && tabBarStyles_[index] == TabBarStyle::SUBTABBATSTYLE && index == indicator_ &&
1894         selectedModes_[index] == SelectedMode::BOARD &&
1895         layoutProperty->GetAxis().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1896         color = indicatorStyles_[index].color;
1897     }
1898     AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), selectedIndex = index, color = color]() {
1899         auto tabBar = weak.Upgrade();
1900         if (tabBar) {
1901             auto host = tabBar->GetHost();
1902             CHECK_NULL_VOID(host);
1903             auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
1904             CHECK_NULL_VOID(columnNode);
1905             auto renderContext = columnNode->GetRenderContext();
1906             CHECK_NULL_VOID(renderContext);
1907             if (tabBar->tabBarStyles_[selectedIndex] != TabBarStyle::SUBTABBATSTYLE) {
1908                 BorderRadiusProperty borderRadiusProperty;
1909                 auto pipelineContext = PipelineContext::GetCurrentContext();
1910                 CHECK_NULL_VOID(pipelineContext);
1911                 auto tabTheme = pipelineContext->GetTheme<TabTheme>();
1912                 CHECK_NULL_VOID(tabTheme);
1913                 borderRadiusProperty.SetRadius(tabTheme->GetFocusIndicatorRadius());
1914                 renderContext->UpdateBorderRadius(borderRadiusProperty);
1915             }
1916             renderContext->UpdateBackgroundColor(color);
1917             columnNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1918         }
1919     }, [weak = AceType::WeakClaim(this), selectedIndex = index]() {
1920         auto tabBar = weak.Upgrade();
1921         if (tabBar) {
1922             if (tabBar->tabBarStyles_[selectedIndex] != TabBarStyle::SUBTABBATSTYLE) {
1923                 auto host = tabBar->GetHost();
1924                 CHECK_NULL_VOID(host);
1925                 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(selectedIndex));
1926                 CHECK_NULL_VOID(columnNode);
1927                 auto renderContext = columnNode->GetRenderContext();
1928                 CHECK_NULL_VOID(renderContext);
1929                 renderContext->ResetBorderRadius();
1930                 columnNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1931             }
1932         }
1933     });
1934 }
1935 
OnTabBarIndexChange(int32_t index)1936 void TabBarPattern::OnTabBarIndexChange(int32_t index)
1937 {
1938     auto pipeline = PipelineContext::GetCurrentContext();
1939     CHECK_NULL_VOID(pipeline);
1940     pipeline->AddAfterRenderTask([weak = WeakClaim(this), index]() {
1941         auto tabBarPattern = weak.Upgrade();
1942         CHECK_NULL_VOID(tabBarPattern);
1943         auto tabBarNode = tabBarPattern->GetHost();
1944         CHECK_NULL_VOID(tabBarNode);
1945         auto tabBarLayoutProperty = tabBarPattern->GetLayoutProperty<TabBarLayoutProperty>();
1946         CHECK_NULL_VOID(tabBarLayoutProperty);
1947         if (!tabBarPattern->IsMaskAnimationByCreate()) {
1948             tabBarPattern->HandleBottomTabBarChange(index);
1949         }
1950         tabBarPattern->SetMaskAnimationByCreate(false);
1951         tabBarPattern->SetIndicator(index);
1952         tabBarPattern->UpdateSubTabBoard(index);
1953         tabBarPattern->UpdatePaintIndicator(index, true);
1954         tabBarPattern->UpdateTextColorAndFontWeight(index);
1955         tabBarPattern->StartShowTabBar();
1956         if (!tabBarPattern->GetClickRepeat() || tabBarLayoutProperty->GetIndicator().value_or(0) == index) {
1957             tabBarPattern->ResetIndicatorAnimationState();
1958             tabBarLayoutProperty->UpdateIndicator(index);
1959         }
1960         tabBarPattern->isTouchingSwiper_ = false;
1961         tabBarPattern->SetClickRepeat(false);
1962         if (tabBarPattern->GetChangeByClick()) {
1963             tabBarPattern->SetChangeByClick(false);
1964             return;
1965         }
1966         if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
1967             tabBarPattern->UpdateAnimationDuration();
1968             auto duration = tabBarPattern->GetAnimationDuration().value_or(0);
1969             if (duration > 0 && tabBarPattern->CanScroll()) {
1970                 tabBarPattern->StopTranslateAnimation();
1971                 tabBarPattern->targetIndex_ = index;
1972                 tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1973             } else {
1974                 tabBarPattern->StopTranslateAnimation();
1975                 tabBarPattern->jumpIndex_ = index;
1976                 tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1977             }
1978         }
1979     });
1980     pipeline->RequestFrame();
1981 }
1982 
UpdateCurrentOffset(float offset)1983 void TabBarPattern::UpdateCurrentOffset(float offset)
1984 {
1985     if (NearZero(offset)) {
1986         return;
1987     }
1988     auto host = GetHost();
1989     CHECK_NULL_VOID(host);
1990     currentDelta_ = offset;
1991     UpdateSubTabBoard(indicator_);
1992     UpdateIndicator(indicator_);
1993     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1994 }
1995 
UpdateIndicator(int32_t indicator)1996 void TabBarPattern::UpdateIndicator(int32_t indicator)
1997 {
1998     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
1999     CHECK_NULL_VOID(layoutProperty);
2000     layoutProperty->UpdateIndicator(indicator);
2001     clickRepeat_ = false;
2002 
2003     UpdatePaintIndicator(indicator, true);
2004 }
2005 
UpdateGradientRegions(bool needMarkDirty)2006 void TabBarPattern::UpdateGradientRegions(bool needMarkDirty)
2007 {
2008     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2009     CHECK_NULL_VOID(layoutProperty);
2010     auto barMode = layoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED);
2011     auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
2012     auto tabBarNode = GetHost();
2013     CHECK_NULL_VOID(tabBarNode);
2014     auto childCount = tabBarNode->TotalChildCount() - MASK_COUNT;
2015     auto geometryNode = tabBarNode->GetGeometryNode();
2016     CHECK_NULL_VOID(geometryNode);
2017     auto mainSize = geometryNode->GetPaddingSize().MainSize(axis);
2018 
2019     std::fill(gradientRegions_.begin(), gradientRegions_.end(), false);
2020     if (barMode == TabBarMode::SCROLLABLE && !visibleItemPosition_.empty()) {
2021         auto visibleItemStartIndex = visibleItemPosition_.begin()->first;
2022         auto visibleItemEndIndex = visibleItemPosition_.rbegin()->first;
2023         auto visibleItemStartPos = visibleItemPosition_.begin()->second.startPos;
2024         auto visibleItemEndPos = visibleItemPosition_.rbegin()->second.endPos;
2025         if (visibleItemStartIndex > 0 || LessNotEqual(visibleItemStartPos, scrollMargin_)) {
2026             auto gradientIndex = axis == Axis::HORIZONTAL ? (isRTL_ ? RIGHT_GRADIENT : LEFT_GRADIENT)
2027                                                           : TOP_GRADIENT;
2028             gradientRegions_[gradientIndex] = true;
2029         }
2030         if (visibleItemEndIndex < childCount - 1 || GreatNotEqual(visibleItemEndPos + scrollMargin_, mainSize)) {
2031             auto gradientIndex = axis == Axis::HORIZONTAL ? (isRTL_ ? LEFT_GRADIENT : RIGHT_GRADIENT)
2032                                                           : BOTTOM_GRADIENT;
2033             gradientRegions_[gradientIndex] = true;
2034         }
2035     }
2036 
2037     if (needMarkDirty) {
2038         tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2039     }
2040 }
2041 
UpdateTextColorAndFontWeight(int32_t indicator)2042 void TabBarPattern::UpdateTextColorAndFontWeight(int32_t indicator)
2043 {
2044     auto tabBarNode = GetHost();
2045     CHECK_NULL_VOID(tabBarNode);
2046     auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(indicator));
2047     CHECK_NULL_VOID(columnNode);
2048     auto selectedColumnId = columnNode->GetId();
2049     auto pipelineContext = PipelineContext::GetCurrentContext();
2050     CHECK_NULL_VOID(pipelineContext);
2051     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
2052     CHECK_NULL_VOID(tabTheme);
2053     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2054     CHECK_NULL_VOID(tabBarLayoutProperty);
2055     auto axis = tabBarLayoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
2056     int32_t index = 0;
2057     for (const auto& columnNode : tabBarNode->GetChildren()) {
2058         CHECK_NULL_VOID(columnNode);
2059         auto columnId = columnNode->GetId();
2060         auto iter = tabBarType_.find(columnId);
2061         if (iter != tabBarType_.end() && iter->second) {
2062             index++;
2063             continue;
2064         }
2065         if (labelStyles_.find(columnId) == labelStyles_.end()) {
2066             index++;
2067             continue;
2068         }
2069         auto textNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().back());
2070         CHECK_NULL_VOID(textNode);
2071         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
2072         CHECK_NULL_VOID(textLayoutProperty);
2073         auto isSelected = columnId == selectedColumnId;
2074         if (isSelected) {
2075             auto selectedColor = index < static_cast<int32_t>(selectedModes_.size()) &&
2076                                          selectedModes_[index] == SelectedMode::BOARD && axis == Axis::HORIZONTAL
2077                                      ? tabTheme->GetSubTabBoardTextOnColor()
2078                                      : tabTheme->GetSubTabTextOnColor();
2079             textLayoutProperty->UpdateTextColor(labelStyles_[columnId].selectedColor.value_or(selectedColor));
2080         } else {
2081             textLayoutProperty->UpdateTextColor(
2082                 labelStyles_[columnId].unselectedColor.value_or(tabTheme->GetSubTabTextOffColor()));
2083         }
2084         if (index < static_cast<int32_t>(tabBarStyles_.size()) && tabBarStyles_[index] == TabBarStyle::SUBTABBATSTYLE &&
2085             !labelStyles_[columnId].fontWeight.has_value()) {
2086             textLayoutProperty->UpdateFontWeight(isSelected ? FontWeight::MEDIUM : FontWeight::NORMAL);
2087         }
2088         textNode->MarkModifyDone();
2089         textNode->MarkDirtyNode();
2090         index++;
2091     }
2092 }
2093 
UpdateImageColor(int32_t indicator)2094 void TabBarPattern::UpdateImageColor(int32_t indicator)
2095 {
2096     auto tabBarNode = GetHost();
2097     CHECK_NULL_VOID(tabBarNode);
2098     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
2099     CHECK_NULL_VOID(tabBarPattern);
2100     if (tabBarPattern->IsContainsBuilder()) {
2101         return;
2102     }
2103     auto pipelineContext = PipelineContext::GetCurrentContext();
2104     CHECK_NULL_VOID(pipelineContext);
2105     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
2106     CHECK_NULL_VOID(tabTheme);
2107     int32_t index = 0;
2108     for (const auto& columnNode : tabBarNode->GetChildren()) {
2109         CHECK_NULL_VOID(columnNode);
2110         auto imageNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
2111         CHECK_NULL_VOID(imageNode);
2112         if (imageNode->GetTag() != V2::IMAGE_ETS_TAG) {
2113             index++;
2114             continue;
2115         }
2116         auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
2117         CHECK_NULL_VOID(imageLayoutProperty);
2118         auto imagePaintProperty = imageNode->GetPaintProperty<ImageRenderProperty>();
2119         CHECK_NULL_VOID(imagePaintProperty);
2120         ImageSourceInfo info;
2121         auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfo().value_or(info);
2122         if (index >= 0 && index < static_cast<int32_t>(iconStyles_.size())) {
2123             if (indicator == index) {
2124                 imagePaintProperty->UpdateSvgFillColor(iconStyles_[index].selectedColor.has_value() ?
2125                     iconStyles_[index].selectedColor.value() : tabTheme->GetBottomTabIconOn());
2126             } else {
2127                 imagePaintProperty->UpdateSvgFillColor(iconStyles_[index].unselectedColor.has_value() ?
2128                     iconStyles_[index].unselectedColor.value() : tabTheme->GetBottomTabIconOff());
2129             }
2130         }
2131         imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
2132         imageNode->MarkModifyDone();
2133         imageNode->MarkDirtyNode();
2134         index++;
2135     }
2136     SetImageColorOnIndex(indicator);
2137 }
2138 
UpdateSymbolStats(int32_t index,int32_t preIndex)2139 void TabBarPattern::UpdateSymbolStats(int32_t index, int32_t preIndex)
2140 {
2141     auto tabBarNode = GetHost();
2142     CHECK_NULL_VOID(tabBarNode);
2143     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
2144     CHECK_NULL_VOID(tabBarPattern);
2145     auto pipelineContext = PipelineContext::GetCurrentContext();
2146     CHECK_NULL_VOID(pipelineContext);
2147     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
2148     CHECK_NULL_VOID(tabTheme);
2149     if (tabBarPattern->IsContainsBuilder()) {
2150         return;
2151     }
2152     std::vector<int32_t> indexes = {index, preIndex};
2153     for (uint32_t i = 0; i < indexes.size(); i++) {
2154         if (indexes[i] < 0 || indexes[i] >= static_cast<int32_t>(symbolArray_.size())) {
2155             continue;
2156         }
2157         auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(indexes[i]));
2158         CHECK_NULL_VOID(columnNode);
2159         auto symbolNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
2160         CHECK_NULL_VOID(symbolNode);
2161         if (symbolNode->GetTag() != V2::SYMBOL_ETS_TAG) {
2162             continue;
2163         }
2164         auto symbolLayoutProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
2165         CHECK_NULL_VOID(symbolLayoutProperty);
2166         TabContentModelNG::UpdateDefaultSymbol(tabTheme, symbolLayoutProperty);
2167         if (i == 0) {
2168             symbolLayoutProperty->UpdateSymbolColorList({tabTheme->GetBottomTabSymbolOn()});
2169             auto modifierOnApply = symbolArray_[indexes[i]].onApply;
2170             UpdateSymbolApply(symbolNode, symbolLayoutProperty, indexes[i], "selected");
2171             if (preIndex != -1) {
2172                 TabContentModelNG::UpdateSymbolEffect(symbolLayoutProperty, true);
2173             }
2174         } else {
2175             symbolLayoutProperty->UpdateSymbolColorList({tabTheme->GetBottomTabSymbolOff()});
2176             UpdateSymbolApply(symbolNode, symbolLayoutProperty, indexes[i], "normal");
2177         }
2178         symbolNode->MarkModifyDone();
2179         symbolNode->MarkDirtyNode();
2180     }
2181 }
2182 
UpdateSymbolApply(const RefPtr<NG::FrameNode> & symbolNode,RefPtr<TextLayoutProperty> & symbolProperty,int32_t index,std::string type)2183 void TabBarPattern::UpdateSymbolApply(const RefPtr<NG::FrameNode>& symbolNode,
2184     RefPtr<TextLayoutProperty>& symbolProperty, int32_t index, std::string type)
2185 {
2186     auto modifierOnApply = symbolArray_[index].onApply;
2187     if (type == "selected" && !symbolArray_[index].selectedFlag) {
2188         return;
2189     }
2190     if (modifierOnApply != nullptr) {
2191         modifierOnApply(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(symbolNode)), type);
2192         TabContentModelNG::UpdateSymbolEffect(symbolProperty, false);
2193     }
2194 }
2195 
UpdateSymbolEffect(int32_t index)2196 void TabBarPattern::UpdateSymbolEffect(int32_t index)
2197 {
2198     if (index != GetImageColorOnIndex().value_or(indicator_)) {
2199         return;
2200     }
2201     auto tabBarNode = GetHost();
2202     CHECK_NULL_VOID(tabBarNode);
2203     auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(index));
2204     CHECK_NULL_VOID(columnNode);
2205     auto symbolNode = AceType::DynamicCast<FrameNode>(columnNode->GetChildren().front());
2206     CHECK_NULL_VOID(symbolNode);
2207     if (symbolNode->GetTag() == V2::SYMBOL_ETS_TAG) {
2208         auto symbolLayoutProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
2209         CHECK_NULL_VOID(symbolLayoutProperty);
2210         auto symbolEffectOptions = symbolLayoutProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
2211         symbolEffectOptions.SetIsTxtActive(false);
2212         symbolLayoutProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
2213     }
2214 }
2215 
UpdateSubTabBoard(int32_t index)2216 void TabBarPattern::UpdateSubTabBoard(int32_t index)
2217 {
2218     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2219     CHECK_NULL_VOID(layoutProperty);
2220     auto axis = layoutProperty->GetAxis().value_or(Axis::HORIZONTAL);
2221 
2222     if (index >= static_cast<int32_t>(indicatorStyles_.size()) ||
2223         index >= static_cast<int32_t>(selectedModes_.size())) {
2224         return;
2225     }
2226     auto tabBarNode = GetHost();
2227     CHECK_NULL_VOID(tabBarNode);
2228     auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
2229     CHECK_NULL_VOID(paintProperty);
2230     auto columnNode = DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(index));
2231     CHECK_NULL_VOID(columnNode);
2232     auto selectedColumnId = columnNode->GetId();
2233     auto pipelineContext = GetHost()->GetContext();
2234     CHECK_NULL_VOID(pipelineContext);
2235     for (auto& iter : visibleItemPosition_) {
2236         if (iter.first < 0 || iter.first >= static_cast<int32_t>(tabBarStyles_.size())) {
2237             break;
2238         }
2239         auto columnFrameNode = AceType::DynamicCast<FrameNode>(tabBarNode->GetChildAtIndex(iter.first));
2240         CHECK_NULL_VOID(columnFrameNode);
2241         auto renderContext = columnFrameNode->GetRenderContext();
2242         CHECK_NULL_VOID(renderContext);
2243         if (tabBarStyles_[iter.first] == TabBarStyle::SUBTABBATSTYLE) {
2244             if (selectedModes_[index] == SelectedMode::BOARD && columnFrameNode->GetId() == selectedColumnId &&
2245                 axis == Axis::HORIZONTAL) {
2246                 renderContext->UpdateBackgroundColor(indicatorStyles_[index].color);
2247             } else {
2248                 renderContext->UpdateBackgroundColor(Color::BLACK.BlendOpacity(0.0f));
2249             }
2250             columnFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2251         }
2252     }
2253 }
2254 
GetSelectedMode() const2255 SelectedMode TabBarPattern::GetSelectedMode() const
2256 {
2257     if (indicator_ >= static_cast<int32_t>(selectedModes_.size())) {
2258         return SelectedMode::INDICATOR;
2259     } else {
2260         return selectedModes_[indicator_];
2261     }
2262 }
2263 
IsContainsBuilder()2264 bool TabBarPattern::IsContainsBuilder()
2265 {
2266     return std::any_of(tabBarType_.begin(), tabBarType_.end(), [](const auto& isBuilder) { return isBuilder.second; });
2267 }
2268 
PlayTabBarTranslateAnimation(AnimationOption option,float targetCurrentOffset)2269 void TabBarPattern::PlayTabBarTranslateAnimation(AnimationOption option, float targetCurrentOffset)
2270 {
2271     auto weak = AceType::WeakClaim(this);
2272     const auto& pattern = weak.Upgrade();
2273     auto host = pattern->GetHost();
2274 
2275     currentOffset_ = 0.0f;
2276     host->CreateAnimatablePropertyFloat(TAB_BAR_PROPERTY_NAME, 0, [weak](float value) {
2277         auto tabBarPattern = weak.Upgrade();
2278         CHECK_NULL_VOID(tabBarPattern);
2279         tabBarPattern->currentDelta_ = value - tabBarPattern->currentOffset_;
2280         tabBarPattern->currentOffset_ = value;
2281         auto host = tabBarPattern->GetHost();
2282         host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
2283     });
2284     host->UpdateAnimatablePropertyFloat(TAB_BAR_PROPERTY_NAME, currentOffset_);
2285     translateAnimationIsRunning_ = true;
2286     translateAnimation_ = AnimationUtils::StartAnimation(option,
2287         [host, targetCurrentOffset]() {
2288             host->UpdateAnimatablePropertyFloat(TAB_BAR_PROPERTY_NAME, targetCurrentOffset);
2289         },
2290         [weak]() {
2291             auto tabBarPattern = weak.Upgrade();
2292             CHECK_NULL_VOID(tabBarPattern);
2293             tabBarPattern->translateAnimationIsRunning_ = false;
2294         });
2295 }
2296 
PlayIndicatorTranslateAnimation(AnimationOption option,RectF originalPaintRect,RectF targetPaintRect,float targetOffset)2297 void TabBarPattern::PlayIndicatorTranslateAnimation(AnimationOption option, RectF originalPaintRect,
2298     RectF targetPaintRect, float targetOffset)
2299 {
2300     auto weak = AceType::WeakClaim(this);
2301     const auto& pattern = weak.Upgrade();
2302     auto host = pattern->GetHost();
2303 
2304     isAnimating_ = true;
2305     turnPageRate_ = 0.0f;
2306     indicatorStartPos_ = originalPaintRect.GetX() + originalPaintRect.Width() / HALF_OF_WIDTH;
2307     indicatorEndPos_ = targetPaintRect.GetX() + targetPaintRect.Width() / HALF_OF_WIDTH + targetOffset;
2308     auto propertyName = INDICATOR_OFFSET_PROPERTY_NAME;
2309 
2310     if (NearZero(indicatorEndPos_ - indicatorStartPos_)) {
2311         indicatorStartPos_ = originalPaintRect.Width();
2312         indicatorEndPos_ = targetPaintRect.Width();
2313         propertyName = INDICATOR_WIDTH_PROPERTY_NAME;
2314         host->CreateAnimatablePropertyFloat(propertyName, 0, [weak](float value) {
2315             auto tabBarPattern = weak.Upgrade();
2316             CHECK_NULL_VOID(tabBarPattern);
2317             if (!tabBarPattern->isAnimating_ ||
2318                 NearZero(tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_)) {
2319                 return;
2320             }
2321             tabBarPattern->turnPageRate_ = (value - tabBarPattern->indicatorStartPos_) /
2322                 (tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_);
2323             tabBarPattern->UpdateIndicatorCurrentOffset(0.0f);
2324         });
2325     } else {
2326         host->CreateAnimatablePropertyFloat(propertyName, 0, [weak](float value) {
2327             auto tabBarPattern = weak.Upgrade();
2328             CHECK_NULL_VOID(tabBarPattern);
2329             if (!tabBarPattern->isAnimating_ ||
2330                 NearZero(tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_)) {
2331                 return;
2332             }
2333             tabBarPattern->turnPageRate_ = (value - tabBarPattern->indicatorStartPos_) /
2334                 (tabBarPattern->indicatorEndPos_ - tabBarPattern->indicatorStartPos_);
2335             tabBarPattern->UpdateIndicatorCurrentOffset(
2336                 static_cast<float>(value - tabBarPattern->currentIndicatorOffset_));
2337         });
2338     }
2339     host->UpdateAnimatablePropertyFloat(propertyName, indicatorStartPos_);
2340     indicatorAnimationIsRunning_ = true;
2341     tabbarIndicatorAnimation_ = AnimationUtils::StartAnimation(option,
2342         [host, propertyName, endPos = indicatorEndPos_]() {
2343             host->UpdateAnimatablePropertyFloat(propertyName, endPos);
2344         },
2345         [weak]() {
2346             auto tabBarPattern = weak.Upgrade();
2347             CHECK_NULL_VOID(tabBarPattern);
2348             tabBarPattern->indicatorAnimationIsRunning_ = false;
2349         });
2350 }
2351 
StopTranslateAnimation()2352 void TabBarPattern::StopTranslateAnimation()
2353 {
2354     if (translateAnimation_)
2355         AnimationUtils::StopAnimation(translateAnimation_);
2356 
2357     if (tabbarIndicatorAnimation_)
2358         AnimationUtils::StopAnimation(tabbarIndicatorAnimation_);
2359 
2360     if (indicatorAnimationIsRunning_)
2361         indicatorAnimationIsRunning_ = false;
2362 
2363     if (translateAnimationIsRunning_)
2364         translateAnimationIsRunning_ = false;
2365 }
2366 
TriggerTranslateAnimation(int32_t currentIndex,int32_t targetIndex)2367 void TabBarPattern::TriggerTranslateAnimation(int32_t currentIndex, int32_t targetIndex)
2368 {
2369     auto curve = DurationCubicCurve;
2370     StopTranslateAnimation();
2371     SetSwiperCurve(curve);
2372     auto pipelineContext = PipelineContext::GetCurrentContextSafely();
2373     CHECK_NULL_VOID(pipelineContext);
2374     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
2375     CHECK_NULL_VOID(tabTheme);
2376     UpdateAnimationDuration();
2377     AnimationOption option = AnimationOption();
2378     option.SetDuration(static_cast<int32_t>(GetAnimationDuration().value_or(
2379         tabTheme->GetTabContentAnimationDuration())));
2380     option.SetCurve(curve);
2381     option.SetFillMode(FillMode::FORWARDS);
2382 
2383     auto targetOffset = 0.0f;
2384     if (CanScroll()) {
2385         targetOffset = CalculateTargetOffset(targetIndex);
2386         PlayTabBarTranslateAnimation(option, targetOffset);
2387     }
2388 
2389     auto host = GetHost();
2390     CHECK_NULL_VOID(host);
2391     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
2392     CHECK_NULL_VOID(layoutProperty);
2393     if (std::count(tabBarStyles_.begin(), tabBarStyles_.end(), TabBarStyle::SUBTABBATSTYLE) !=
2394             static_cast<int32_t>(tabBarStyles_.size()) ||
2395         layoutProperty->GetAxisValue(Axis::HORIZONTAL) != Axis::HORIZONTAL) {
2396         return;
2397     }
2398     auto originalPaintRect = layoutProperty->GetIndicatorRect(currentIndex);
2399     auto targetPaintRect = layoutProperty->GetIndicatorRect(targetIndex);
2400     auto paintProperty = host->GetPaintProperty<TabBarPaintProperty>();
2401     CHECK_NULL_VOID(paintProperty);
2402     paintProperty->UpdateIndicator(targetPaintRect);
2403     if (!changeByClick_) {
2404         return;
2405     }
2406     PlayIndicatorTranslateAnimation(option, originalPaintRect, targetPaintRect, targetOffset);
2407 }
2408 
CalculateTargetOffset(int32_t targetIndex)2409 float TabBarPattern::CalculateTargetOffset(int32_t targetIndex)
2410 {
2411     auto targetOffset = 0.0f;
2412     auto space = GetSpace(targetIndex);
2413     auto startPos = 0.0f;
2414     auto endPos = 0.0f;
2415     auto iter = visibleItemPosition_.find(targetIndex);
2416     if (iter != visibleItemPosition_.end()) {
2417         startPos = iter->second.startPos;
2418         endPos = iter->second.endPos;
2419     }
2420     auto frontChildrenMainSize = CalculateFrontChildrenMainSize(targetIndex);
2421     auto backChildrenMainSize = CalculateBackChildrenMainSize(targetIndex);
2422     if (Negative(space)) {
2423         targetOffset = isRTL_ && axis_ == Axis::HORIZONTAL ? (startPos - scrollMargin_)
2424                                                             : (scrollMargin_ - startPos);
2425     } else if (LessOrEqual(frontChildrenMainSize, space)) {
2426         targetOffset = isRTL_ && axis_ == Axis::HORIZONTAL ? (startPos - frontChildrenMainSize)
2427                                                             : (frontChildrenMainSize - startPos);
2428     } else if (LessOrEqual(backChildrenMainSize, space)) {
2429         auto host = GetHost();
2430         CHECK_NULL_RETURN(host, targetOffset);
2431         auto mainSize = host->GetGeometryNode()->GetPaddingSize().MainSize(axis_);
2432         targetOffset = isRTL_ && axis_ == Axis::HORIZONTAL ? (backChildrenMainSize - (mainSize - endPos))
2433                                                             : (mainSize - backChildrenMainSize - endPos);
2434     } else {
2435         targetOffset = isRTL_ && axis_ == Axis::HORIZONTAL ? (startPos - space) : (space - startPos);
2436     }
2437     return targetOffset;
2438 }
2439 
UpdateIndicatorCurrentOffset(float offset)2440 void TabBarPattern::UpdateIndicatorCurrentOffset(float offset)
2441 {
2442     currentIndicatorOffset_ = currentIndicatorOffset_ + offset;
2443     auto host = GetHost();
2444     CHECK_NULL_VOID(host);
2445     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
2446 }
2447 
CreateNodePaintMethod()2448 RefPtr<NodePaintMethod> TabBarPattern::CreateNodePaintMethod()
2449 {
2450     if (indicator_ < 0 || indicator_ >= static_cast<int32_t>(indicatorStyles_.size()) ||
2451         indicator_ >= static_cast<int32_t>(selectedModes_.size())) {
2452         return nullptr;
2453     }
2454 
2455     if (!tabBarModifier_) {
2456         tabBarModifier_ = AceType::MakeRefPtr<TabBarModifier>();
2457     }
2458 
2459     Color bgColor = GetTabBarBackgroundColor();
2460     RectF tabBarItemRect;
2461     auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
2462     if (paintProperty) {
2463         RectF rect;
2464         tabBarItemRect = paintProperty->GetIndicator().value_or(rect);
2465     }
2466     IndicatorStyle indicatorStyle;
2467     OffsetF indicatorOffset = { currentIndicatorOffset_, tabBarItemRect.GetY() };
2468     GetIndicatorStyle(indicatorStyle, indicatorOffset);
2469     indicatorOffset.AddX(-indicatorStyle.width.ConvertToPx() / HALF_OF_WIDTH);
2470     auto hasIndicator = std::count(selectedModes_.begin(), selectedModes_.end(), SelectedMode::INDICATOR) ==
2471         static_cast<int32_t>(selectedModes_.size()) && !NearZero(tabBarItemRect.Height());
2472     return MakeRefPtr<TabBarPaintMethod>(tabBarModifier_, gradientRegions_, bgColor, indicatorStyle,
2473         indicatorOffset, hasIndicator);
2474 }
2475 
GetTabBarBackgroundColor() const2476 Color TabBarPattern::GetTabBarBackgroundColor() const
2477 {
2478     Color bgColor = Color::WHITE;
2479     auto tabBarNode = GetHost();
2480     CHECK_NULL_RETURN(tabBarNode, bgColor);
2481     auto tabBarCtx = tabBarNode->GetRenderContext();
2482     CHECK_NULL_RETURN(tabBarCtx, bgColor);
2483     if (tabBarCtx->GetBackgroundColor()) {
2484         bgColor = *tabBarCtx->GetBackgroundColor();
2485     } else {
2486         auto tabsNode = AceType::DynamicCast<FrameNode>(tabBarNode->GetParent());
2487         CHECK_NULL_RETURN(tabsNode, bgColor);
2488         auto tabsCtx = tabsNode->GetRenderContext();
2489         CHECK_NULL_RETURN(tabsCtx, bgColor);
2490         if (tabsCtx->GetBackgroundColor()) {
2491             bgColor = *tabsCtx->GetBackgroundColor();
2492         } else {
2493             auto pipeline = PipelineContext::GetCurrentContext();
2494             CHECK_NULL_RETURN(pipeline, bgColor);
2495             auto tabTheme = pipeline->GetTheme<TabTheme>();
2496             CHECK_NULL_RETURN(tabTheme, bgColor);
2497             bgColor = tabTheme->GetBackgroundColor().ChangeAlpha(0xff);
2498         }
2499     }
2500     return bgColor;
2501 }
2502 
GetIndicatorStyle(IndicatorStyle & indicatorStyle,OffsetF & indicatorOffset)2503 void TabBarPattern::GetIndicatorStyle(IndicatorStyle& indicatorStyle, OffsetF& indicatorOffset)
2504 {
2505     if (indicator_ < 0 || indicator_ >= static_cast<int32_t>(indicatorStyles_.size())) {
2506         return;
2507     }
2508     indicatorStyle = indicatorStyles_[indicator_];
2509     auto host = GetHost();
2510     CHECK_NULL_VOID(host);
2511     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
2512     CHECK_NULL_VOID(layoutProperty);
2513 
2514     if (NonPositive(indicatorStyle.width.Value())) {
2515         auto paintProperty = GetPaintProperty<TabBarPaintProperty>();
2516         if (paintProperty) {
2517             RectF rect;
2518             indicatorStyle.width = Dimension(paintProperty->GetIndicator().value_or(rect).Width());
2519         }
2520     }
2521     if ((!isTouchingSwiper_ && !isAnimating_) || axis_ != Axis::HORIZONTAL) {
2522         return;
2523     }
2524     if (LessOrEqual(turnPageRate_, 0.0f)) {
2525         turnPageRate_ = 0.0f;
2526     }
2527     if (GreatOrEqual(turnPageRate_, 1.0f)) {
2528         turnPageRate_ = 1.0f;
2529     }
2530     auto totalCount = host->TotalChildCount() - MASK_COUNT;
2531     if (swiperStartIndex_ < 0 || swiperStartIndex_ >= totalCount ||
2532         swiperStartIndex_ >= static_cast<int32_t>(tabBarStyles_.size()) ||
2533         tabBarStyles_[swiperStartIndex_] != TabBarStyle::SUBTABBATSTYLE ||
2534         swiperStartIndex_ >= static_cast<int32_t>(selectedModes_.size()) ||
2535         selectedModes_[swiperStartIndex_] != SelectedMode::INDICATOR ||
2536         swiperStartIndex_ >= static_cast<int32_t>(indicatorStyles_.size())) {
2537         return;
2538     }
2539 
2540     auto nextIndex = isTouchingSwiper_ ? swiperStartIndex_ + 1 : animationTargetIndex_.value_or(-1);
2541     if (nextIndex < 0 || nextIndex >= totalCount ||
2542         nextIndex >= static_cast<int32_t>(tabBarStyles_.size()) ||
2543         tabBarStyles_[nextIndex] != TabBarStyle::SUBTABBATSTYLE ||
2544         nextIndex >= static_cast<int32_t>(selectedModes_.size()) ||
2545         selectedModes_[nextIndex] != SelectedMode::INDICATOR ||
2546         nextIndex >= static_cast<int32_t>(indicatorStyles_.size())) {
2547         return;
2548     }
2549     CalculateIndicatorStyle(swiperStartIndex_, nextIndex, indicatorStyle, indicatorOffset);
2550 }
2551 
CalculateIndicatorStyle(int32_t startIndex,int32_t nextIndex,IndicatorStyle & indicatorStyle,OffsetF & indicatorOffset)2552 void TabBarPattern::CalculateIndicatorStyle(
2553     int32_t startIndex, int32_t nextIndex, IndicatorStyle& indicatorStyle, OffsetF& indicatorOffset)
2554 {
2555     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2556     CHECK_NULL_VOID(layoutProperty);
2557 
2558     indicatorStyle = indicatorStyles_[startIndex];
2559     auto startItemRect = layoutProperty->GetIndicatorRect(startIndex);
2560     if (NonPositive(indicatorStyle.width.Value())) {
2561         indicatorStyle.width = Dimension(startItemRect.Width());
2562     }
2563     IndicatorStyle nextIndicatorStyle = indicatorStyles_[nextIndex];
2564     auto nextItemRect = layoutProperty->GetIndicatorRect(nextIndex);
2565     if (NonPositive(nextIndicatorStyle.width.Value())) {
2566         nextIndicatorStyle.width = Dimension(nextItemRect.Width());
2567     }
2568 
2569     indicatorStyle.width = Dimension(indicatorStyle.width.ConvertToPx() +
2570         (nextIndicatorStyle.width.ConvertToPx() - indicatorStyle.width.ConvertToPx()) * turnPageRate_);
2571     indicatorStyle.marginTop = Dimension(indicatorStyle.marginTop.ConvertToPx() +
2572         (nextIndicatorStyle.marginTop.ConvertToPx() - indicatorStyle.marginTop.ConvertToPx()) * turnPageRate_);
2573     indicatorStyle.height = Dimension(indicatorStyle.height.ConvertToPx() +
2574         (nextIndicatorStyle.height.ConvertToPx() - indicatorStyle.height.ConvertToPx()) * turnPageRate_);
2575     LinearColor color = LinearColor(indicatorStyle.color) +
2576         (LinearColor(nextIndicatorStyle.color) - LinearColor(indicatorStyle.color)) * turnPageRate_;
2577     indicatorStyle.color = color.ToColor();
2578     indicatorOffset.SetY(startItemRect.GetY() + (nextItemRect.GetY() - startItemRect.GetY()) * turnPageRate_);
2579 }
2580 
GetSpace(int32_t indicator)2581 float TabBarPattern::GetSpace(int32_t indicator)
2582 {
2583     auto host = GetHost();
2584     CHECK_NULL_RETURN(host, 0.0f);
2585     auto geometryNode = host->GetGeometryNode();
2586     auto childFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(indicator));
2587     CHECK_NULL_RETURN(childFrameNode, 0.0f);
2588     auto childGeometryNode = childFrameNode->GetGeometryNode();
2589 
2590     return (geometryNode->GetPaddingSize().MainSize(axis_) - childGeometryNode->GetMarginFrameSize().MainSize(axis_)) /
2591            2;
2592 }
2593 
CalculateFrontChildrenMainSize(int32_t indicator)2594 float TabBarPattern::CalculateFrontChildrenMainSize(int32_t indicator)
2595 {
2596     float frontChildrenMainSize = scrollMargin_;
2597     if (visibleItemPosition_.empty()) {
2598         return frontChildrenMainSize;
2599     }
2600     for (auto& iter : visibleItemPosition_) {
2601         if (iter.first < indicator) {
2602             frontChildrenMainSize += iter.second.endPos - iter.second.startPos;
2603         }
2604     }
2605     return frontChildrenMainSize;
2606 }
2607 
CalculateBackChildrenMainSize(int32_t indicator)2608 float TabBarPattern::CalculateBackChildrenMainSize(int32_t indicator)
2609 {
2610     float backChildrenMainSize = scrollMargin_;
2611     if (visibleItemPosition_.empty()) {
2612         return backChildrenMainSize;
2613     }
2614     for (auto& iter : visibleItemPosition_) {
2615         if (iter.first > indicator) {
2616             backChildrenMainSize += iter.second.endPos - iter.second.startPos;
2617         }
2618     }
2619     return backChildrenMainSize;
2620 }
2621 
SetEdgeEffect(const RefPtr<GestureEventHub> & gestureHub)2622 void TabBarPattern::SetEdgeEffect(const RefPtr<GestureEventHub>& gestureHub)
2623 {
2624     CHECK_NULL_VOID(gestureHub);
2625     if (scrollEffect_) {
2626         gestureHub->RemoveScrollEdgeEffect(scrollEffect_);
2627         scrollEffect_.Reset();
2628     }
2629     if (!scrollEffect_) {
2630         auto springEffect = AceType::MakeRefPtr<ScrollSpringEffect>();
2631         CHECK_NULL_VOID(springEffect);
2632         springEffect->SetOutBoundaryCallback([weak = AceType::WeakClaim(this)]() {
2633             auto pattern = weak.Upgrade();
2634             CHECK_NULL_RETURN(pattern, false);
2635             return pattern->IsAtTop() || pattern->IsAtBottom();
2636         });
2637         // add callback to springEdgeEffect
2638         SetEdgeEffectCallback(springEffect);
2639         scrollEffect_ = springEffect;
2640         gestureHub->AddScrollEdgeEffect(axis_, scrollEffect_);
2641     }
2642 }
2643 
SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)2644 void TabBarPattern::SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect)
2645 {
2646     scrollEffect->SetCurrentPositionCallback([weak = AceType::WeakClaim(this)]() -> double {
2647         auto tabBar = weak.Upgrade();
2648         CHECK_NULL_RETURN(tabBar, 0.0);
2649         auto host = tabBar->GetHost();
2650         CHECK_NULL_RETURN(host, 0.0);
2651         auto geometryNode = host->GetGeometryNode();
2652         CHECK_NULL_RETURN(geometryNode, 0.0);
2653         if (tabBar->visibleItemPosition_.empty()) {
2654             return tabBar->scrollMargin_ + tabBar->currentDelta_;
2655         }
2656         if (tabBar->isRTL_ && tabBar->axis_ == Axis::HORIZONTAL) {
2657             return geometryNode->GetPaddingSize().Width() - tabBar->visibleItemPosition_.rbegin()->second.endPos +
2658                 tabBar->currentDelta_;
2659         } else {
2660             return tabBar->visibleItemPosition_.begin()->second.startPos + tabBar->currentDelta_;
2661         }
2662     });
2663     auto leadingCallback = [weak = AceType::WeakClaim(this)]() -> double {
2664         auto tabBar = weak.Upgrade();
2665         CHECK_NULL_RETURN(tabBar, 0.0);
2666         auto host = tabBar->GetHost();
2667         CHECK_NULL_RETURN(host, 0.0);
2668         auto geometryNode = host->GetGeometryNode();
2669         CHECK_NULL_RETURN(geometryNode, 0.0);
2670         if (tabBar->visibleItemPosition_.empty()) {
2671             return geometryNode->GetPaddingSize().MainSize(tabBar->axis_) - tabBar->scrollMargin_;
2672         }
2673         auto visibleChildrenMainSize = tabBar->visibleItemPosition_.rbegin()->second.endPos -
2674             tabBar->visibleItemPosition_.begin()->second.startPos;
2675         return geometryNode->GetPaddingSize().MainSize(tabBar->axis_) - visibleChildrenMainSize - tabBar->scrollMargin_;
2676     };
2677     auto trailingCallback = [weak = AceType::WeakClaim(this)]() -> double {
2678         auto tabBar = weak.Upgrade();
2679         CHECK_NULL_RETURN(tabBar, 0.0);
2680         return tabBar->scrollMargin_;
2681     };
2682     scrollEffect->SetLeadingCallback(leadingCallback);
2683     scrollEffect->SetTrailingCallback(trailingCallback);
2684     scrollEffect->SetInitLeadingCallback(leadingCallback);
2685     scrollEffect->SetInitTrailingCallback(trailingCallback);
2686 }
2687 
IsAtTop() const2688 bool TabBarPattern::IsAtTop() const
2689 {
2690     if (visibleItemPosition_.empty()) {
2691         return false;
2692     }
2693 
2694     auto visibleItemStartIndex = visibleItemPosition_.begin()->first;
2695     auto visibleItemStartPos = visibleItemPosition_.begin()->second.startPos;
2696     return visibleItemStartIndex == 0 && GreatOrEqual(visibleItemStartPos, scrollMargin_);
2697 }
2698 
IsAtBottom() const2699 bool TabBarPattern::IsAtBottom() const
2700 {
2701     if (visibleItemPosition_.empty()) {
2702         return false;
2703     }
2704     auto host = GetHost();
2705     CHECK_NULL_RETURN(host, false);
2706     auto geometryNode = host->GetGeometryNode();
2707     CHECK_NULL_RETURN(geometryNode, false);
2708 
2709     auto visibleItemEndIndex = visibleItemPosition_.rbegin()->first;
2710     auto visibleItemEndPos = visibleItemPosition_.rbegin()->second.endPos;
2711     auto childCount = host->TotalChildCount() - MASK_COUNT;
2712     auto mainSize = geometryNode->GetPaddingSize().MainSize(axis_);
2713     return visibleItemEndIndex == (childCount - 1) && LessOrEqual(visibleItemEndPos, mainSize - scrollMargin_);
2714 }
2715 
IsOutOfBoundary()2716 bool TabBarPattern::IsOutOfBoundary()
2717 {
2718     if (visibleItemPosition_.empty()) {
2719         return false;
2720     }
2721     auto host = GetHost();
2722     CHECK_NULL_RETURN(host, false);
2723     auto geometryNode = host->GetGeometryNode();
2724     CHECK_NULL_RETURN(geometryNode, false);
2725 
2726     auto visibleItemStartPos = visibleItemPosition_.begin()->second.startPos;
2727     auto visibleItemEndPos = visibleItemPosition_.rbegin()->second.endPos;
2728     auto mainSize = geometryNode->GetPaddingSize().MainSize(axis_);
2729     bool outOfStart = Positive(visibleItemStartPos - scrollMargin_) &&
2730         GreatNotEqual(visibleItemEndPos + scrollMargin_, mainSize);
2731     bool outOfEnd = LessNotEqual(visibleItemEndPos + scrollMargin_, mainSize) &&
2732         Negative(visibleItemStartPos - scrollMargin_);
2733     return outOfStart || outOfEnd;
2734 }
2735 
SetAccessibilityAction()2736 void TabBarPattern::SetAccessibilityAction()
2737 {
2738     auto host = GetHost();
2739     CHECK_NULL_VOID(host);
2740     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
2741     CHECK_NULL_VOID(accessibilityProperty);
2742     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
2743         const auto& pattern = weakPtr.Upgrade();
2744         CHECK_NULL_VOID(pattern);
2745         auto tabBarLayoutProperty = pattern->GetLayoutProperty<TabBarLayoutProperty>();
2746         CHECK_NULL_VOID(tabBarLayoutProperty);
2747         auto frameNode = pattern->GetHost();
2748         CHECK_NULL_VOID(frameNode);
2749         if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
2750             frameNode->TotalChildCount() - MASK_COUNT > 1) {
2751             auto index = pattern->GetIndicator() + 1;
2752             pattern->FocusIndexChange(index);
2753             // AccessibilityEventType::SCROLL_END
2754         }
2755     });
2756 
2757     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
2758         const auto& pattern = weakPtr.Upgrade();
2759         CHECK_NULL_VOID(pattern);
2760         auto tabBarLayoutProperty = pattern->GetLayoutProperty<TabBarLayoutProperty>();
2761         CHECK_NULL_VOID(tabBarLayoutProperty);
2762         auto frameNode = pattern->GetHost();
2763         CHECK_NULL_VOID(frameNode);
2764         if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE &&
2765            frameNode->TotalChildCount() - MASK_COUNT > 1) {
2766             auto index = pattern->GetIndicator() - 1;
2767             pattern->FocusIndexChange(index);
2768             // AccessibilityEventType::SCROLL_END
2769         }
2770     });
2771 }
2772 
ProvideRestoreInfo()2773 std::string TabBarPattern::ProvideRestoreInfo()
2774 {
2775     auto jsonObj = JsonUtil::Create(true);
2776     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2777     CHECK_NULL_RETURN(tabBarLayoutProperty, "");
2778     jsonObj->Put("Index", tabBarLayoutProperty->GetIndicator().value_or(0));
2779     return jsonObj->ToString();
2780 }
2781 
OnRestoreInfo(const std::string & restoreInfo)2782 void TabBarPattern::OnRestoreInfo(const std::string& restoreInfo)
2783 {
2784     auto host = GetHost();
2785     CHECK_NULL_VOID(host);
2786     auto tabBarLayoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2787     CHECK_NULL_VOID(tabBarLayoutProperty);
2788     auto info = JsonUtil::ParseJsonString(restoreInfo);
2789     if (!info->IsValid() || !info->IsObject()) {
2790         return;
2791     }
2792     auto jsonIsOn = info->GetValue("Index");
2793     auto index = jsonIsOn->GetInt();
2794     auto totalCount = host->TotalChildCount();
2795     if (index < 0 || index >= totalCount || !swiperController_ ||
2796         indicator_ >= static_cast<int32_t>(tabBarStyles_.size())) {
2797         return;
2798     }
2799     auto tabsFrameNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2800     CHECK_NULL_VOID(tabsFrameNode);
2801     auto tabsPattern = tabsFrameNode->GetPattern<TabsPattern>();
2802     tabBarLayoutProperty->UpdateIndicator(index);
2803     clickRepeat_ = false;
2804     UpdateAnimationDuration();
2805     if (GetAnimationDuration().has_value()
2806         && (!tabsPattern || tabsPattern->GetAnimateMode() != TabAnimateMode::NO_ANIMATION)) {
2807         swiperController_->SwipeTo(index);
2808     } else {
2809         swiperController_->SwipeToWithoutAnimation(index);
2810     }
2811 }
2812 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const2813 void TabBarPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
2814 {
2815     Pattern::ToJsonValue(json, filter);
2816     /* no fixed attr below, just return */
2817     if (filter.IsFastFilter()) {
2818         return;
2819     }
2820     auto selectedModes = JsonUtil::CreateArray(true);
2821     for (const auto& selectedMode : selectedModes_) {
2822         auto mode = JsonUtil::Create(true);
2823         mode->Put("mode", selectedMode == SelectedMode::INDICATOR ? "INDICATOR" : "BOARD");
2824         selectedModes->Put(mode);
2825     }
2826     json->PutExtAttr("selectedModes", selectedModes->ToString().c_str(), filter);
2827 
2828     auto indicatorStyles = JsonUtil::CreateArray(true);
2829     for (const auto& indicatorStyle : indicatorStyles_) {
2830         auto indicator = JsonUtil::Create(true);
2831         indicator->Put("color", indicatorStyle.color.ColorToString().c_str());
2832         indicator->Put("height", indicatorStyle.height.ToString().c_str());
2833         indicator->Put("width", indicatorStyle.width.ToString().c_str());
2834         indicator->Put("borderRadius", indicatorStyle.borderRadius.ToString().c_str());
2835         indicator->Put("marginTop", indicatorStyle.marginTop.ToString().c_str());
2836         indicatorStyles->Put(indicator);
2837     }
2838     json->PutExtAttr("indicatorStyles", indicatorStyles->ToString().c_str(), filter);
2839 
2840     auto tabBarStyles = JsonUtil::CreateArray(true);
2841     for (const auto& tabBarStyle : tabBarStyles_) {
2842         auto style = JsonUtil::Create(true);
2843         style->Put("style", tabBarStyle == TabBarStyle::NOSTYLE          ? "NOSTYLE"
2844                             : tabBarStyle == TabBarStyle::SUBTABBATSTYLE ? "SUBTABBATSTYLE"
2845                                                                          : "BOTTOMTABBATSTYLE");
2846         tabBarStyles->Put(style);
2847     }
2848     json->PutExtAttr("tabBarStyles", tabBarStyles->ToString().c_str(), filter);
2849 }
2850 
FromJson(const std::unique_ptr<JsonValue> & json)2851 void TabBarPattern::FromJson(const std::unique_ptr<JsonValue>& json)
2852 {
2853     auto selectedModes = JsonUtil::ParseJsonString(json->GetString("selectedModes"));
2854     for (int32_t i = 0; i < selectedModes->GetArraySize(); i++) {
2855         auto selectedMode = selectedModes->GetArrayItem(i);
2856         auto mode = selectedMode->GetString("mode");
2857         SetSelectedMode(mode == "INDICATOR" ? SelectedMode::INDICATOR : SelectedMode::BOARD, i);
2858     }
2859 
2860     auto indicatorStyles = JsonUtil::ParseJsonString(json->GetString("indicatorStyles"));
2861     for (int32_t i = 0; i < indicatorStyles->GetArraySize(); i++) {
2862         auto indicatorStyle = indicatorStyles->GetArrayItem(i);
2863         IndicatorStyle style;
2864         style.color = Color::ColorFromString(indicatorStyle->GetString("color"));
2865         style.height = Dimension::FromString(indicatorStyle->GetString("height"));
2866         style.width = Dimension::FromString(indicatorStyle->GetString("width"));
2867         style.borderRadius = Dimension::FromString(indicatorStyle->GetString("borderRadius"));
2868         style.marginTop = Dimension::FromString(indicatorStyle->GetString("marginTop"));
2869         SetIndicatorStyle(style, i);
2870     }
2871 
2872     auto tabBarStyles = JsonUtil::ParseJsonString(json->GetString("tabBarStyles"));
2873     for (int32_t i = 0; i < tabBarStyles->GetArraySize(); i++) {
2874         auto tabBarStyle = tabBarStyles->GetArrayItem(i);
2875         auto style = tabBarStyle->GetString("style");
2876         SetTabBarStyle(style == "NOSTYLE"          ? TabBarStyle::NOSTYLE
2877                        : style == "SUBTABBATSTYLE" ? TabBarStyle::SUBTABBATSTYLE
2878                                                    : TabBarStyle::BOTTOMTABBATSTYLE,
2879             i);
2880     }
2881 
2882     auto layoutProperty = GetLayoutProperty<TabBarLayoutProperty>();
2883     CHECK_NULL_VOID(layoutProperty);
2884     auto indicatorValue = layoutProperty->GetIndicatorValue(0);
2885     UpdateIndicator(indicatorValue);
2886     Pattern::FromJson(json);
2887 }
2888 
TabBarClickEvent(int32_t index) const2889 void TabBarPattern::TabBarClickEvent(int32_t index) const
2890 {
2891     auto host = GetHost();
2892     CHECK_NULL_VOID(host);
2893     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2894     CHECK_NULL_VOID(tabsNode);
2895     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
2896     CHECK_NULL_VOID(tabsPattern);
2897     auto tabBarClickEvent = tabsPattern->GetTabBarClickEvent();
2898     CHECK_NULL_VOID(tabBarClickEvent);
2899     auto event = *tabBarClickEvent;
2900     event(index);
2901 }
2902 
2903 
OnCustomContentTransition(int32_t fromIndex,int32_t toIndex)2904 void TabBarPattern::OnCustomContentTransition(int32_t fromIndex, int32_t toIndex)
2905 {
2906     auto swiperPattern = GetSwiperPattern();
2907     CHECK_NULL_VOID(swiperPattern);
2908 
2909     swiperPattern->OnCustomContentTransition(toIndex);
2910 }
2911 
GetSwiperPattern() const2912 RefPtr<SwiperPattern> TabBarPattern::GetSwiperPattern() const
2913 {
2914     auto host = GetHost();
2915     CHECK_NULL_RETURN(host, nullptr);
2916     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2917     CHECK_NULL_RETURN(tabsNode, nullptr);
2918     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2919     CHECK_NULL_RETURN(swiperNode, nullptr);
2920     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
2921     return swiperPattern;
2922 }
2923 
CheckSwiperDisable() const2924 bool TabBarPattern::CheckSwiperDisable() const
2925 {
2926     auto host = GetHost();
2927     CHECK_NULL_RETURN(host, true);
2928     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2929     CHECK_NULL_RETURN(tabsNode, true);
2930     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2931     CHECK_NULL_RETURN(swiperNode, true);
2932     auto props = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
2933     CHECK_NULL_RETURN(props, true);
2934     return props->GetDisableSwipe().value_or(false);
2935 }
2936 
SetSwiperCurve(const RefPtr<Curve> & curve) const2937 void TabBarPattern::SetSwiperCurve(const RefPtr<Curve>& curve) const
2938 {
2939     auto host = GetHost();
2940     CHECK_NULL_VOID(host);
2941     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
2942     CHECK_NULL_VOID(tabsNode);
2943     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
2944     CHECK_NULL_VOID(swiperNode);
2945     auto swiperPaintProperty = swiperNode->GetPaintProperty<SwiperPaintProperty>();
2946     CHECK_NULL_VOID(swiperPaintProperty);
2947     swiperPaintProperty->UpdateCurve(curve);
2948 }
2949 
ApplyTurnPageRateToIndicator(float turnPageRate)2950 void TabBarPattern::ApplyTurnPageRateToIndicator(float turnPageRate)
2951 {
2952     auto host = GetHost();
2953     CHECK_NULL_VOID(host);
2954     auto layoutProperty = host->GetLayoutProperty<TabBarLayoutProperty>();
2955     auto totalCount = host->TotalChildCount() - MASK_COUNT;
2956     CHECK_NULL_VOID(layoutProperty);
2957     swiperStartIndex_ = std::clamp(swiperStartIndex_, 0, totalCount - 1);
2958     CHECK_NULL_VOID(IsValidIndex(swiperStartIndex_));
2959     auto index = swiperStartIndex_ + 1;
2960     auto isRtl = ParseTabsIsRtl();
2961     if ((index >= totalCount || index >= static_cast<int32_t>(tabBarStyles_.size())) && !isRtl) {
2962         swiperStartIndex_--;
2963         index--;
2964         turnPageRate = 1.0f;
2965     }
2966     if (isRtl && (index == static_cast<int32_t>(tabBarStyles_.size()) || NearEqual(turnPageRate, 1.0f))) {
2967         return;
2968     }
2969     if (Negative(turnPageRate)) {
2970         turnPageRate = 0.0f;
2971     }
2972     CHECK_NULL_VOID(IsValidIndex(index));
2973     if (GreatOrEqual(turnPageRate, 1.0f)) {
2974         turnPageRate_ = 1.0f;
2975     } else if (LessOrEqual(turnPageRate, 0.0f)) {
2976         turnPageRate_ = 0.0f;
2977     } else {
2978         if (turnPageRate_ <= TEXT_COLOR_THREDHOLD && turnPageRate > TEXT_COLOR_THREDHOLD) {
2979             UpdateTextColorAndFontWeight(index);
2980         } else if (turnPageRate <= 1.0f - TEXT_COLOR_THREDHOLD && turnPageRate_ > 1.0f - TEXT_COLOR_THREDHOLD) {
2981             UpdateTextColorAndFontWeight(swiperStartIndex_);
2982         }
2983         turnPageRate_ = turnPageRate;
2984     }
2985     auto originalPaintRect = layoutProperty->GetIndicatorRect(swiperStartIndex_);
2986     auto targetPaintRect = layoutProperty->GetIndicatorRect(index);
2987     auto paintRectDiff = std::abs(targetPaintRect.GetX() + targetPaintRect.Width() / 2 - originalPaintRect.GetX() -
2988                                   originalPaintRect.Width() / 2);
2989 
2990     currentIndicatorOffset_ = originalPaintRect.GetX() + originalPaintRect.Width() / 2 + paintRectDiff * turnPageRate_;
2991     if (isRtl) {
2992         auto originalPaintRect = layoutProperty->GetIndicatorRect(swiperStartIndex_ + 1);
2993         auto targetPaintRect = layoutProperty->GetIndicatorRect(swiperStartIndex_ >= 0 ? swiperStartIndex_ : 0);
2994         auto paintRectDiff = std::abs(targetPaintRect.GetX() + targetPaintRect.Width() / HALF_OF_WIDTH -
2995                                       originalPaintRect.GetX() - originalPaintRect.Width() / HALF_OF_WIDTH);
2996         currentIndicatorOffset_ =
2997             originalPaintRect.GetX() + originalPaintRect.Width() / HALF_OF_WIDTH + paintRectDiff * (1 - turnPageRate_);
2998     }
2999     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
3000 }
3001 
InitTurnPageRateEvent()3002 void TabBarPattern::InitTurnPageRateEvent()
3003 {
3004     auto turnPageRateCallback = [weak = WeakClaim(this)](int32_t swipingIndex, float turnPageRate) {
3005         auto pattern = weak.Upgrade();
3006         if (pattern) {
3007             if (!pattern->CheckSwiperDisable() && pattern->axis_ == Axis::HORIZONTAL && pattern->isTouchingSwiper_) {
3008                 pattern->swiperStartIndex_ = swipingIndex;
3009                 pattern->ApplyTurnPageRateToIndicator(turnPageRate);
3010             } else if (!pattern->isAnimating_) {
3011                 pattern->turnPageRate_ = 0.0f;
3012             }
3013         }
3014     };
3015     swiperController_->SetTurnPageRateCallback(std::move(turnPageRateCallback));
3016 
3017     auto host = GetHost();
3018     CHECK_NULL_VOID(host);
3019     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
3020     CHECK_NULL_VOID(tabsNode);
3021     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
3022     CHECK_NULL_VOID(swiperNode);
3023     auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
3024     CHECK_NULL_VOID(eventHub);
3025     if (!animationStartEvent_) {
3026         AnimationStartEvent animationStartEvent =
3027             [weak = WeakClaim(this)](int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info) {
3028                 auto pattern = weak.Upgrade();
3029                 if (pattern) {
3030                     pattern->HandleBottomTabBarAnimation(targetIndex);
3031                 }
3032             };
3033         animationStartEvent_ = std::make_shared<AnimationStartEvent>(std::move(animationStartEvent));
3034         eventHub->AddAnimationStartEvent(animationStartEvent_);
3035     }
3036     if (!animationEndEvent_) {
3037         AnimationEndEvent animationEndEvent =
3038             [weak = WeakClaim(this)](int32_t index, const AnimationCallbackInfo& info) {
3039                 PerfMonitor::GetPerfMonitor()->End(PerfConstants::APP_TAB_SWITCH, true);
3040                 auto pattern = weak.Upgrade();
3041                 if (pattern && (NearZero(pattern->turnPageRate_) || NearEqual(pattern->turnPageRate_, 1.0f))) {
3042                     pattern->isTouchingSwiper_ = false;
3043                 }
3044                 pattern->SetMaskAnimationExecuted(false);
3045             };
3046         animationEndEvent_ = std::make_shared<AnimationEndEvent>(std::move(animationEndEvent));
3047         eventHub->AddAnimationEndEvent(animationEndEvent_);
3048     }
3049 }
3050 
HandleBottomTabBarAnimation(int32_t index)3051 void TabBarPattern::HandleBottomTabBarAnimation(int32_t index)
3052 {
3053     auto preIndex = GetImageColorOnIndex().value_or(indicator_);
3054     if (preIndex < 0 || preIndex >= static_cast<int32_t>(tabBarStyles_.size())
3055         || index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size())) {
3056         return;
3057     }
3058     if (tabBarStyles_[preIndex] != TabBarStyle::BOTTOMTABBATSTYLE &&
3059         tabBarStyles_[index] != TabBarStyle::BOTTOMTABBATSTYLE) {
3060         return;
3061     }
3062     if (preIndex != index) {
3063         auto host = GetHost();
3064         CHECK_NULL_VOID(host);
3065         auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
3066         CHECK_NULL_VOID(tabsNode);
3067         auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
3068         CHECK_NULL_VOID(tabsPattern);
3069         auto onChangeEvent = tabsPattern->GetChangeEvent();
3070         if (onChangeEvent) {
3071             (*onChangeEvent)(preIndex, index);
3072         }
3073         auto onIndexChangeEvent = tabsPattern->GetIndexChangeEvent();
3074         if (onIndexChangeEvent) {
3075             (*onIndexChangeEvent)(index);
3076         }
3077     }
3078     SetMaskAnimationExecuted(true);
3079 }
3080 
GetLeftPadding() const3081 float TabBarPattern::GetLeftPadding() const
3082 {
3083     auto host = GetHost();
3084     CHECK_NULL_RETURN(host, 0.0f);
3085     auto geometryNode = host->GetGeometryNode();
3086     CHECK_NULL_RETURN(geometryNode, 0.0f);
3087     if (!geometryNode->GetPadding()) {
3088         return 0.0f;
3089     }
3090     return geometryNode->GetPadding()->left.value_or(0.0f);
3091 }
3092 
UpdateAnimationDuration()3093 void TabBarPattern::UpdateAnimationDuration()
3094 {
3095     if (animationDuration_.has_value() && animationDuration_.value() >= 0) {
3096         return;
3097     }
3098 
3099     std::optional<int32_t> duration;
3100     auto pipelineContext = PipelineContext::GetCurrentContext();
3101     CHECK_NULL_VOID(pipelineContext);
3102     auto tabTheme = pipelineContext->GetTheme<TabTheme>();
3103     CHECK_NULL_VOID(tabTheme);
3104     auto host = GetHost();
3105     CHECK_NULL_VOID(host);
3106     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
3107     CHECK_NULL_VOID(tabsNode);
3108     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
3109     CHECK_NULL_VOID(swiperNode);
3110     auto swiperPaintProperty = swiperNode->GetPaintProperty<SwiperPaintProperty>();
3111     CHECK_NULL_VOID(swiperPaintProperty);
3112     duration = static_cast<int32_t>(tabTheme->GetTabContentAnimationDuration());
3113     if ((Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
3114         std::count(tabBarStyles_.begin(), tabBarStyles_.end(), TabBarStyle::BOTTOMTABBATSTYLE)) ||
3115         (!animationDuration_.has_value() && Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
3116         duration = 0;
3117     }
3118     SetAnimationDuration(duration.value());
3119     swiperPaintProperty->UpdateDuration(duration.value());
3120 }
3121 
DumpAdvanceInfo()3122 void TabBarPattern::DumpAdvanceInfo()
3123 {
3124     isRTL_ ? DumpLog::GetInstance().AddDesc("isRTL:true") : DumpLog::GetInstance().AddDesc("isRTL:false");
3125     touching_ ? DumpLog::GetInstance().AddDesc("touching:true") : DumpLog::GetInstance().AddDesc("touching:false");
3126     isMaskAnimationByCreate_ ? DumpLog::GetInstance().AddDesc("isMaskAnimationByCreate:true")
3127                              : DumpLog::GetInstance().AddDesc("isMaskAnimationByCreate:false");
3128     animationDuration_.has_value()
3129         ? DumpLog::GetInstance().AddDesc("animationDuration:" + std::to_string(animationDuration_.value()))
3130         : DumpLog::GetInstance().AddDesc("animationDuration:null");
3131     isFirstFocus_ ? DumpLog::GetInstance().AddDesc("isFirstFocus:true")
3132                   : DumpLog::GetInstance().AddDesc("isFirstFocus:false");
3133     isTouchingSwiper_ ? DumpLog::GetInstance().AddDesc("isTouchingSwiper:true")
3134                       : DumpLog::GetInstance().AddDesc("isTouchingSwiper:false");
3135     isAnimating_ ? DumpLog::GetInstance().AddDesc("isAnimating:true")
3136                  : DumpLog::GetInstance().AddDesc("isAnimating:false");
3137     changeByClick_ ? DumpLog::GetInstance().AddDesc("changeByClick:true")
3138                    : DumpLog::GetInstance().AddDesc("changeByClick:false");
3139     DumpLog::GetInstance().AddDesc("indicator:" + std::to_string(indicator_));
3140     DumpLog::GetInstance().AddDesc("focusIndicator:" + std::to_string(focusIndicator_));
3141     DumpLog::GetInstance().AddDesc("currentIndicatorOffset:" + std::to_string(currentIndicatorOffset_));
3142     DumpLog::GetInstance().AddDesc("turnPageRate:" + std::to_string(turnPageRate_));
3143     DumpLog::GetInstance().AddDesc("swiperStartIndex:" + std::to_string(swiperStartIndex_));
3144     DumpLog::GetInstance().AddDesc("scrollMargin:" + std::to_string(scrollMargin_));
3145     std::string regionString = std::string("region:");
3146     for (auto item : gradientRegions_) {
3147         item ? regionString.append("true ") : regionString.append("false ");
3148     }
3149     DumpLog::GetInstance().AddDesc(regionString);
3150     switch (axis_) {
3151         case Axis::NONE: {
3152             DumpLog::GetInstance().AddDesc("Axis:NONE");
3153             break;
3154         }
3155         case Axis::HORIZONTAL: {
3156             DumpLog::GetInstance().AddDesc("Axis:HORIZONTAL");
3157             break;
3158         }
3159         case Axis::FREE: {
3160             DumpLog::GetInstance().AddDesc("Axis:FREE");
3161             break;
3162         }
3163         case Axis::VERTICAL: {
3164             DumpLog::GetInstance().AddDesc("Axis:VERTICAL");
3165             break;
3166         }
3167         default: {
3168             break;
3169         }
3170     }
3171 }
3172 
ContentWillChange(int32_t comingIndex)3173 bool TabBarPattern::ContentWillChange(int32_t comingIndex)
3174 {
3175     auto swiperPattern = GetSwiperPattern();
3176     CHECK_NULL_RETURN(swiperPattern, true);
3177     int32_t currentIndex = swiperPattern->GetCurrentIndex();
3178     return ContentWillChange(currentIndex, comingIndex);
3179 }
3180 
ContentWillChange(int32_t currentIndex,int32_t comingIndex)3181 bool TabBarPattern::ContentWillChange(int32_t currentIndex, int32_t comingIndex)
3182 {
3183     auto host = GetHost();
3184     CHECK_NULL_RETURN(host, true);
3185     auto tabsNode = AceType::DynamicCast<TabsNode>(host->GetParent());
3186     CHECK_NULL_RETURN(tabsNode, true);
3187     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
3188     CHECK_NULL_RETURN(tabsPattern, true);
3189     if (tabsPattern->GetInterceptStatus() && currentIndex != comingIndex) {
3190         auto ret = tabsPattern->OnContentWillChange(currentIndex, comingIndex);
3191         return ret.has_value() ? ret.value() : true;
3192     }
3193     return true;
3194 }
3195 
ParseTabsIsRtl()3196 bool TabBarPattern::ParseTabsIsRtl()
3197 {
3198     auto host = GetHost();
3199     CHECK_NULL_RETURN(host, false);
3200     auto tabsNode = AceType::DynamicCast<FrameNode>(host->GetParent());
3201     CHECK_NULL_RETURN(tabsNode, false);
3202     auto tabLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
3203     CHECK_NULL_RETURN(tabLayoutProperty, false);
3204     auto isRTL = tabLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
3205     return isRTL;
3206 }
3207 
IsValidIndex(int32_t index)3208 bool TabBarPattern::IsValidIndex(int32_t index)
3209 {
3210     if (index < 0 || index >= static_cast<int32_t>(tabBarStyles_.size()) ||
3211         tabBarStyles_[index] != TabBarStyle::SUBTABBATSTYLE || index >= static_cast<int32_t>(selectedModes_.size()) ||
3212         selectedModes_[index] != SelectedMode::INDICATOR) {
3213         return false;
3214     }
3215     return true;
3216 }
3217 
GetLoopIndex(int32_t originalIndex) const3218 int32_t TabBarPattern::GetLoopIndex(int32_t originalIndex) const
3219 {
3220     auto host = GetHost();
3221     CHECK_NULL_RETURN(host, originalIndex);
3222     auto totalCount = host->TotalChildCount() - MASK_COUNT;
3223     if (totalCount <= 0) {
3224         return originalIndex;
3225     }
3226     return originalIndex % totalCount;
3227 }
3228 } // namespace OHOS::Ace::NG
3229