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