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