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