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