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