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