1 /*
2 * Copyright (c) 2022-2024 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/tabs_pattern.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/dimension.h"
20 #include "base/log/log_wrapper.h"
21 #include "base/utils/utils.h"
22 #include "core/common/recorder/event_recorder.h"
23 #include "core/common/recorder/node_data_cache.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components/tab_bar/tabs_event.h"
26 #include "core/components_ng/base/observer_handler.h"
27 #include "core/components_ng/pattern/divider/divider_layout_property.h"
28 #include "core/components_ng/pattern/divider/divider_render_property.h"
29 #include "core/components_ng/pattern/swiper/swiper_model.h"
30 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
31 #include "core/components_ng/pattern/tabs/tab_bar_layout_property.h"
32 #include "core/components_ng/pattern/tabs/tab_bar_paint_property.h"
33 #include "core/components_ng/pattern/tabs/tab_bar_pattern.h"
34 #include "core/components_ng/pattern/tabs/tab_content_node.h"
35 #include "core/components_ng/pattern/tabs/tabs_layout_property.h"
36 #include "core/components_ng/pattern/tabs/tabs_node.h"
37 #include "core/components_ng/property/property.h"
38 #include "core/components_v2/inspector/inspector_constants.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40
41 namespace OHOS::Ace::NG {
42 namespace {
43 constexpr int32_t CHILDREN_MIN_SIZE = 2;
44 } // namespace
45
OnAttachToFrameNode()46 void TabsPattern::OnAttachToFrameNode()
47 {
48 auto host = GetHost();
49 CHECK_NULL_VOID(host);
50 host->GetRenderContext()->SetClipToFrame(true);
51 // expand to navigation bar by default
52 host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(
53 { .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_BOTTOM });
54 }
55
SetOnChangeEvent(std::function<void (const BaseEventInfo *)> && event)56 void TabsPattern::SetOnChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
57 {
58 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
59 CHECK_NULL_VOID(tabsNode);
60 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
61 CHECK_NULL_VOID(tabBarNode);
62 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
63 CHECK_NULL_VOID(tabBarPattern);
64 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
65 CHECK_NULL_VOID(swiperNode);
66
67 ChangeEventWithPreIndex changeEvent([weak = WeakClaim(this), tabBarNode, tabBarPattern, jsEvent = std::move(event)](
68 int32_t preIndex, int32_t currentIndex) {
69 auto pattern = weak.Upgrade();
70 CHECK_NULL_VOID(pattern);
71 if (tabBarPattern->IsMaskAnimationExecuted()) {
72 return;
73 }
74 auto tabsNode = AceType::DynamicCast<TabsNode>(tabBarNode->GetParent());
75 CHECK_NULL_VOID(tabsNode);
76 auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
77 CHECK_NULL_VOID(tabsLayoutProperty);
78 tabsLayoutProperty->UpdateIndex(currentIndex);
79 tabBarPattern->OnTabBarIndexChange(currentIndex);
80 pattern->FireTabContentStateCallback(preIndex, currentIndex);
81
82 /* js callback */
83 if (jsEvent && tabsNode->IsOnMainTree()) {
84 pattern->RecordChangeEvent(currentIndex);
85 auto context = PipelineContext::GetCurrentContext();
86 CHECK_NULL_VOID(context);
87 context->AddAfterLayoutTask(
88 [currentIndex, jsEvent]() {
89 TabContentChangeEvent eventInfo(currentIndex);
90 jsEvent(&eventInfo);
91 }, true);
92 }
93 });
94
95 if (onChangeEvent_) {
96 (*onChangeEvent_).swap(changeEvent);
97 } else {
98 onChangeEvent_ = std::make_shared<ChangeEventWithPreIndex>(changeEvent);
99 auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
100 CHECK_NULL_VOID(eventHub);
101 eventHub->AddOnChangeEventWithPreIndex(onChangeEvent_);
102 }
103 }
104
FireTabContentStateCallback(int32_t oldIndex,int32_t nextIndex) const105 void TabsPattern::FireTabContentStateCallback(int32_t oldIndex, int32_t nextIndex) const
106 {
107 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
108 CHECK_NULL_VOID(tabsNode);
109 std::string id = tabsNode->GetInspectorId().value_or("");
110 int32_t uniqueId = tabsNode->GetId();
111 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
112 CHECK_NULL_VOID(swiperNode);
113
114 auto oldTabContent = AceType::DynamicCast<TabContentNode>(swiperNode->GetChildByIndex(oldIndex));
115 if (oldTabContent) {
116 std::string oldTabContentId = oldTabContent->GetInspectorId().value_or("");
117 int32_t oldTabContentUniqueId = oldTabContent->GetId();
118 TabContentInfo oldTabContentInfo(oldTabContentId, oldTabContentUniqueId, TabContentState::ON_HIDE, oldIndex,
119 id, uniqueId);
120 UIObserverHandler::GetInstance().NotifyTabContentStateUpdate(oldTabContentInfo);
121 }
122
123 auto nextTabContent = AceType::DynamicCast<TabContentNode>(swiperNode->GetChildByIndex(nextIndex));
124 if (nextTabContent) {
125 std::string nextTabContentId = nextTabContent->GetInspectorId().value_or("");
126 int32_t nextTabContentUniqueId = nextTabContent->GetId();
127 TabContentInfo nextTabContentInfo(nextTabContentId, nextTabContentUniqueId, TabContentState::ON_SHOW, nextIndex,
128 id, uniqueId);
129 UIObserverHandler::GetInstance().NotifyTabContentStateUpdate(nextTabContentInfo);
130 }
131 }
132
RecordChangeEvent(int32_t index)133 void TabsPattern::RecordChangeEvent(int32_t index)
134 {
135 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
136 CHECK_NULL_VOID(tabsNode);
137 if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
138 auto inspectorId = tabsNode->GetInspectorId().value_or("");
139 auto tabBarText = GetTabBarTextByIndex(index);
140 Recorder::EventParamsBuilder builder;
141 builder.SetId(inspectorId)
142 .SetType(tabsNode->GetTag())
143 .SetIndex(index)
144 .SetText(tabBarText)
145 .SetDescription(tabsNode->GetAutoEventParamValue(""));
146 Recorder::EventRecorder::Get().OnChange(std::move(builder));
147 if (!inspectorId.empty()) {
148 Recorder::NodeDataCache::Get().PutMultiple(tabsNode, inspectorId, tabBarText, index);
149 }
150 }
151 }
152
GetTabBarTextByIndex(int32_t index) const153 std::string TabsPattern::GetTabBarTextByIndex(int32_t index) const
154 {
155 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
156 CHECK_NULL_RETURN(tabsNode, "");
157 auto tabBar = tabsNode->GetTabBar();
158 CHECK_NULL_RETURN(tabBar, "");
159 auto tabBarItem = tabBar->GetChildAtIndex(index);
160 CHECK_NULL_RETURN(tabBarItem, "");
161 auto node = AceType::DynamicCast<FrameNode>(tabBarItem);
162 CHECK_NULL_RETURN(node, "");
163 return node->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetGroupText(true);
164 }
165
SetOnTabBarClickEvent(std::function<void (const BaseEventInfo *)> && event)166 void TabsPattern::SetOnTabBarClickEvent(std::function<void(const BaseEventInfo*)>&& event)
167 {
168 ChangeEvent tabBarClickEvent([jsEvent = std::move(event)](int32_t index) {
169 /* js callback */
170 if (jsEvent) {
171 TabContentChangeEvent eventInfo(index);
172 jsEvent(&eventInfo);
173 }
174 });
175
176 if (onTabBarClickEvent_) {
177 (*onTabBarClickEvent_).swap(tabBarClickEvent);
178 } else {
179 onTabBarClickEvent_ = std::make_shared<ChangeEvent>(tabBarClickEvent);
180 }
181 }
182
SetAnimationStartEvent(AnimationStartEvent && event)183 void TabsPattern::SetAnimationStartEvent(AnimationStartEvent&& event)
184 {
185 if (animationStartEvent_) {
186 (*animationStartEvent_).swap(event);
187 } else {
188 auto host = GetHost();
189 CHECK_NULL_VOID(host);
190 auto tabsNode = AceType::DynamicCast<TabsNode>(host);
191 CHECK_NULL_VOID(tabsNode);
192 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
193 CHECK_NULL_VOID(swiperNode);
194 auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
195 CHECK_NULL_VOID(eventHub);
196 animationStartEvent_ = std::make_shared<AnimationStartEvent>(std::move(event));
197 eventHub->AddAnimationStartEvent(animationStartEvent_);
198 }
199 }
200
SetAnimationEndEvent(AnimationEndEvent && event)201 void TabsPattern::SetAnimationEndEvent(AnimationEndEvent&& event)
202 {
203 if (animationEndEvent_) {
204 (*animationEndEvent_).swap(event);
205 } else {
206 auto host = GetHost();
207 CHECK_NULL_VOID(host);
208 auto tabsNode = AceType::DynamicCast<TabsNode>(host);
209 CHECK_NULL_VOID(tabsNode);
210 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
211 CHECK_NULL_VOID(swiperNode);
212 auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
213 CHECK_NULL_VOID(eventHub);
214 animationEndEvent_ = std::make_shared<AnimationEndEvent>(std::move(event));
215 eventHub->AddAnimationEndEvent(animationEndEvent_);
216 }
217 }
218
OnUpdateShowDivider()219 void TabsPattern::OnUpdateShowDivider()
220 {
221 auto host = AceType::DynamicCast<TabsNode>(GetHost());
222 CHECK_NULL_VOID(host);
223 auto layoutProperty = host->GetLayoutProperty<TabsLayoutProperty>();
224 TabsItemDivider defaultDivider;
225 auto divider = layoutProperty->GetDivider().value_or(defaultDivider);
226 auto children = host->GetChildren();
227 if (children.size() < CHILDREN_MIN_SIZE) {
228 return;
229 }
230
231 auto dividerFrameNode = AceType::DynamicCast<FrameNode>(host->GetDivider());
232 CHECK_NULL_VOID(dividerFrameNode);
233 auto dividerRenderProperty = dividerFrameNode->GetPaintProperty<DividerRenderProperty>();
234 CHECK_NULL_VOID(dividerRenderProperty);
235 dividerRenderProperty->UpdateDividerColor(divider.color);
236
237 auto dividerLayoutProperty = dividerFrameNode->GetLayoutProperty<DividerLayoutProperty>();
238 CHECK_NULL_VOID(dividerLayoutProperty);
239 dividerLayoutProperty->UpdateStrokeWidth(divider.strokeWidth);
240 dividerFrameNode->MarkModifyDone();
241 }
242
UpdateSwiperDisableSwipe(bool disableSwipe)243 void TabsPattern::UpdateSwiperDisableSwipe(bool disableSwipe)
244 {
245 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
246 CHECK_NULL_VOID(tabsNode);
247 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
248 CHECK_NULL_VOID(swiperNode);
249 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
250 CHECK_NULL_VOID(swiperPattern);
251 auto props = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
252 CHECK_NULL_VOID(props);
253 props->UpdateDisableSwipe(disableSwipe);
254 swiperPattern->UpdateSwiperPanEvent(disableSwipe);
255 swiperPattern->SetSwiperEventCallback(disableSwipe);
256 }
257
SetSwiperPaddingAndBorder()258 void TabsPattern::SetSwiperPaddingAndBorder()
259 {
260 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
261 CHECK_NULL_VOID(tabsNode);
262 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
263 CHECK_NULL_VOID(swiperNode);
264 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
265 CHECK_NULL_VOID(swiperPattern);
266 auto layoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
267 CHECK_NULL_VOID(layoutProperty);
268 swiperPattern->SetTabsPaddingAndBorder(layoutProperty->CreatePaddingAndBorder());
269 }
270
OnModifyDone()271 void TabsPattern::OnModifyDone()
272 {
273 Pattern::OnModifyDone();
274 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
275 CHECK_NULL_VOID(tabsNode);
276 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
277 CHECK_NULL_VOID(tabBarNode);
278 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
279 CHECK_NULL_VOID(tabBarPattern);
280 auto tabBarPaintProperty = tabBarPattern->GetPaintProperty<TabBarPaintProperty>();
281 if (tabBarPaintProperty->GetTabBarBlurStyle().has_value() &&
282 Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
283 auto tabBarRenderContext = tabBarNode->GetRenderContext();
284 CHECK_NULL_VOID(tabBarRenderContext);
285 BlurStyleOption styleOption;
286 styleOption.blurStyle = tabBarPaintProperty->GetTabBarBlurStyle().value();
287 tabBarRenderContext->UpdateBackBlurStyle(styleOption);
288 }
289
290 UpdateSwiperDisableSwipe(isCustomAnimation_ ? true : isDisableSwipe_);
291 SetSwiperPaddingAndBorder();
292
293 if (onChangeEvent_) {
294 return;
295 }
296 SetOnChangeEvent(nullptr);
297 OnUpdateShowDivider();
298 }
299
OnAfterModifyDone()300 void TabsPattern::OnAfterModifyDone()
301 {
302 auto host = GetHost();
303 CHECK_NULL_VOID(host);
304 auto inspectorId = host->GetInspectorId().value_or("");
305 if (inspectorId.empty()) {
306 return;
307 }
308 auto property = GetLayoutProperty<TabsLayoutProperty>();
309 CHECK_NULL_VOID(property);
310 auto index = property->GetIndexValue(0);
311 auto tabBarText = GetTabBarTextByIndex(index);
312 Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, tabBarText, index);
313 }
314
SetOnIndexChangeEvent(std::function<void (const BaseEventInfo *)> && event)315 void TabsPattern::SetOnIndexChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
316 {
317 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
318 CHECK_NULL_VOID(tabsNode);
319 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
320 CHECK_NULL_VOID(tabBarNode);
321 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
322 CHECK_NULL_VOID(tabBarPattern);
323 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
324 CHECK_NULL_VOID(swiperNode);
325
326 ChangeEvent changeEvent([tabBarPattern, jsEvent = std::move(event)](int32_t index) {
327 if (tabBarPattern->IsMaskAnimationExecuted()) {
328 return;
329 }
330
331 /* js callback */
332 if (jsEvent) {
333 TabContentChangeEvent eventInfo(index);
334 jsEvent(&eventInfo);
335 }
336 });
337
338 if (onIndexChangeEvent_) {
339 (*onIndexChangeEvent_).swap(changeEvent);
340 } else {
341 onIndexChangeEvent_ = std::make_shared<ChangeEvent>(changeEvent);
342 auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
343 CHECK_NULL_VOID(eventHub);
344 eventHub->AddOnChangeEvent(onIndexChangeEvent_);
345 }
346 }
347
ProvideRestoreInfo()348 std::string TabsPattern::ProvideRestoreInfo()
349 {
350 auto jsonObj = JsonUtil::Create(true);
351 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
352 CHECK_NULL_RETURN(tabsNode, "");
353 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
354 CHECK_NULL_RETURN(tabBarNode, "");
355 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
356 CHECK_NULL_RETURN(tabBarPattern, "");
357 return tabBarPattern->ProvideRestoreInfo();
358 }
359
OnRestoreInfo(const std::string & restoreInfo)360 void TabsPattern::OnRestoreInfo(const std::string& restoreInfo)
361 {
362 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
363 CHECK_NULL_VOID(tabsNode);
364 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
365 CHECK_NULL_VOID(tabBarNode);
366 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
367 CHECK_NULL_VOID(tabBarPattern);
368 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
369 CHECK_NULL_VOID(swiperNode);
370 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
371 CHECK_NULL_VOID(swiperPattern);
372 auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
373 CHECK_NULL_VOID(swiperLayoutProperty);
374 auto info = JsonUtil::ParseJsonString(restoreInfo);
375 if (!info->IsValid() || !info->IsObject()) {
376 return;
377 }
378 auto jsonIsOn = info->GetValue("Index");
379 swiperLayoutProperty->UpdateIndex(jsonIsOn->GetInt());
380
381 swiperPattern->OnRestoreInfo(restoreInfo);
382 tabBarPattern->OnRestoreInfo(restoreInfo);
383 }
384
AddInnerOnGestureRecognizerJudgeBegin(GestureRecognizerJudgeFunc && gestureRecognizerJudgeFunc)385 void TabsPattern::AddInnerOnGestureRecognizerJudgeBegin(GestureRecognizerJudgeFunc&& gestureRecognizerJudgeFunc)
386 {
387 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
388 CHECK_NULL_VOID(tabsNode);
389 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
390 CHECK_NULL_VOID(swiperNode);
391 auto targetComponent = swiperNode->GetTargetComponent().Upgrade();
392 CHECK_NULL_VOID(targetComponent);
393 targetComponent->SetOnGestureRecognizerJudgeBegin(std::move(gestureRecognizerJudgeFunc));
394 targetComponent->SetInnerNodeGestureRecognizerJudge();
395 }
396
GetScopeFocusAlgorithm()397 ScopeFocusAlgorithm TabsPattern::GetScopeFocusAlgorithm()
398 {
399 auto property = GetLayoutProperty<TabsLayoutProperty>();
400 CHECK_NULL_RETURN(property, {});
401 bool isVertical = true;
402 if (property->GetAxis().has_value()) {
403 isVertical = property->GetAxis().value() == Axis::HORIZONTAL;
404 }
405 return ScopeFocusAlgorithm(isVertical, true, ScopeType::OTHERS,
406 [wp = WeakClaim(this)](
407 FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) {
408 auto tabs = wp.Upgrade();
409 if (tabs) {
410 nextFocusNode = tabs->GetNextFocusNode(step, currFocusNode);
411 }
412 });
413 }
414
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)415 WeakPtr<FocusHub> TabsPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
416 {
417 auto curFocusNode = currentFocusNode.Upgrade();
418 CHECK_NULL_RETURN(curFocusNode, nullptr);
419
420 auto property = GetLayoutProperty<TabsLayoutProperty>();
421 CHECK_NULL_RETURN(property, nullptr);
422 auto axis = property->GetAxis().value_or(Axis::HORIZONTAL);
423 auto tabBarPosition = property->GetTabBarPosition().value_or(BarPosition::START);
424
425 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
426 CHECK_NULL_RETURN(tabsNode, nullptr);
427 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
428 CHECK_NULL_RETURN(tabBarNode, nullptr);
429 auto tabBarFocusNode = tabBarNode->GetFocusHub();
430 CHECK_NULL_RETURN(tabBarFocusNode, nullptr);
431 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
432 CHECK_NULL_RETURN(swiperNode, nullptr);
433 auto swiperFocusNode = swiperNode->GetFocusHub();
434 CHECK_NULL_RETURN(swiperFocusNode, nullptr);
435
436 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
437 CHECK_NULL_RETURN(tabBarPattern, nullptr);
438 tabBarPattern->SetFirstFocus(true);
439 auto tabsLayoutProperty = AceType::DynamicCast<TabsLayoutProperty>(tabsNode->GetLayoutProperty());
440 CHECK_NULL_RETURN(tabsLayoutProperty, nullptr);
441 auto isRTL_ = tabsLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
442 if (curFocusNode->GetFrameName() == V2::TAB_BAR_ETS_TAG &&
443 ((tabBarPosition == BarPosition::START && axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
444 (tabBarPosition == BarPosition::START && axis == Axis::VERTICAL &&
445 (isRTL_ ? step == FocusStep::LEFT : step == FocusStep::RIGHT)) ||
446 (tabBarPosition == BarPosition::END && axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
447 (tabBarPosition == BarPosition::END && axis == Axis::VERTICAL &&
448 (isRTL_ ? step == FocusStep::RIGHT : step == FocusStep::LEFT)))) {
449 return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
450 }
451 if (curFocusNode->GetFrameName() == V2::SWIPER_ETS_TAG) {
452 if ((tabBarPosition == BarPosition::START && axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
453 (tabBarPosition == BarPosition::START && axis == Axis::VERTICAL &&
454 (isRTL_ ? step == FocusStep::RIGHT : step == FocusStep::LEFT)) ||
455 (tabBarPosition == BarPosition::END && axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
456 (tabBarPosition == BarPosition::END && axis == Axis::VERTICAL &&
457 (isRTL_ ? step == FocusStep::LEFT : step == FocusStep::RIGHT))) {
458 return AceType::WeakClaim(AceType::RawPtr(tabBarFocusNode));
459 }
460 if (step == FocusStep::LEFT_END || step == FocusStep::RIGHT_END || step == FocusStep::UP_END ||
461 step == FocusStep::DOWN_END) {
462 return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
463 }
464 }
465 return nullptr;
466 }
467
BeforeCreateLayoutWrapper()468 void TabsPattern::BeforeCreateLayoutWrapper()
469 {
470 auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
471 CHECK_NULL_VOID(tabsNode);
472 auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
473 CHECK_NULL_VOID(swiperNode);
474 auto tabContentNum = swiperNode->TotalChildCount();
475 auto tabsLayoutProperty = GetLayoutProperty<TabsLayoutProperty>();
476 CHECK_NULL_VOID(tabsLayoutProperty);
477 auto index = tabsLayoutProperty->GetIndex().value_or(0);
478 if (index > tabContentNum - 1) {
479 index = 0;
480 }
481
482 if (isInit_) {
483 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
484 CHECK_NULL_VOID(swiperPattern);
485 swiperPattern->SetOnHiddenChangeForParent();
486 auto parent = tabsNode->GetAncestorNodeOfFrame();
487 CHECK_NULL_VOID(parent);
488 while (parent && parent->GetTag() != V2::NAVDESTINATION_VIEW_ETS_TAG) {
489 parent = parent->GetAncestorNodeOfFrame();
490 }
491 if (!parent) {
492 auto willShowIndex = tabsLayoutProperty->GetIndex().value_or(0);
493 swiperPattern->FireWillShowEvent(willShowIndex);
494 }
495 isInit_ = false;
496 }
497
498 auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
499 CHECK_NULL_VOID(tabBarNode);
500 auto childrenUpdated = swiperNode->GetChildrenUpdated() != -1;
501 if (childrenUpdated) {
502 HandleChildrenUpdated(swiperNode, tabBarNode);
503 }
504
505 auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
506 CHECK_NULL_VOID(tabBarPattern);
507 if (!childrenUpdated && !tabBarPattern->IsMaskAnimationByCreate()) {
508 return;
509 }
510 UpdateSelectedState(tabBarNode, swiperNode, tabBarPattern, tabsLayoutProperty, index);
511 }
512
513 /**
514 * @brief Handles the update of children in the TabsPattern component.
515 *
516 * This function is responsible for updating the children of the TabsPattern component,
517 * specifically the swiperNode and tabBarNode. It performs the following steps:
518 * 1. Creates a map of tabBarItems using the tabBarItemNodes from the tabBarNode.
519 * 2. Traverses the tree of UINodes starting from the swiperNode using a stack.
520 * 3. For each UINode, if it is an instance of TabContentNode, it retrieves the corresponding
521 * tabBarItem from the tabBarItems map and moves it to position 0.
522 * 4. Continues traversing the tree by pushing the children of the current UINode onto the stack.
523 *
524 * @param swiperNode The FrameNode representing the swiper component.
525 * @param tabBarNode The FrameNode representing the tab bar component.
526 */
HandleChildrenUpdated(const RefPtr<FrameNode> & swiperNode,const RefPtr<FrameNode> & tabBarNode)527 void TabsPattern::HandleChildrenUpdated(const RefPtr<FrameNode>& swiperNode, const RefPtr<FrameNode>& tabBarNode)
528 {
529 std::map<int32_t, RefPtr<FrameNode>> tabBarItems;
530 for (const auto& tabBarItemNode : tabBarNode->GetChildren()) {
531 CHECK_NULL_VOID(tabBarItemNode);
532 auto tabBarItemFrameNode = AceType::DynamicCast<FrameNode>(tabBarItemNode);
533 tabBarItems[tabBarItemFrameNode->GetId()] = tabBarItemFrameNode;
534 }
535 std::stack<RefPtr<UINode>> stack;
536 stack.push(swiperNode);
537 while (!stack.empty()) {
538 auto parent = stack.top();
539 stack.pop();
540 if (AceType::InstanceOf<TabContentNode>(parent)) {
541 auto tabContentNode = AceType::DynamicCast<TabContentNode>(parent);
542 auto tabBarItem = tabBarItems[tabContentNode->GetTabBarItemId()];
543 CHECK_NULL_VOID(tabBarItem);
544 tabBarItem->MovePosition(0);
545 continue;
546 }
547 for (const auto& child : parent->GetChildren()) {
548 stack.push(child);
549 }
550 }
551 }
552
553 /**
554 * @brief Update selected state.
555 *
556 * This function is responsible for updating the indicator, text color, font weight, image color,
557 * and index of the tab bar and swiper nodes when updating children or creating a tab.
558 *
559 * @param tabBarNode The node representing the tab bar.
560 * @param swiperNode The node representing the swiper.
561 * @param tabBarPattern The pattern for the tab bar.
562 * @param tabsLayoutProperty The layout property for the tabs.
563 * @param index The index of the tab being created.
564 */
UpdateSelectedState(const RefPtr<FrameNode> & tabBarNode,const RefPtr<FrameNode> & swiperNode,const RefPtr<TabBarPattern> & tabBarPattern,const RefPtr<TabsLayoutProperty> & tabsLayoutProperty,int index)565 void TabsPattern::UpdateSelectedState(const RefPtr<FrameNode>& tabBarNode, const RefPtr<FrameNode>& swiperNode,
566 const RefPtr<TabBarPattern>& tabBarPattern, const RefPtr<TabsLayoutProperty>& tabsLayoutProperty, int index)
567 {
568 auto tabBarLayoutProperty = tabBarNode->GetLayoutProperty<TabBarLayoutProperty>();
569 CHECK_NULL_VOID(tabBarLayoutProperty);
570 tabBarLayoutProperty->UpdateIndicator(index);
571 tabBarPattern->SetClickRepeat(false);
572 tabBarPattern->UpdateTextColorAndFontWeight(index);
573 tabBarPattern->UpdateImageColor(index);
574 auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
575 CHECK_NULL_VOID(swiperLayoutProperty);
576 swiperLayoutProperty->UpdateIndex(index);
577 tabsLayoutProperty->UpdateIndex(index);
578 }
579 } // namespace OHOS::Ace::NG
580