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