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