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