• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "core/components_ng/pattern/tabs/tabs_node.h"
41 namespace OHOS::Ace::NG {
42 namespace {
43 constexpr int32_t CHILDREN_MIN_SIZE = 2;
44 constexpr char APP_TABS_NO_ANIMATION_SWITCH[] = "APP_TABS_NO_ANIMATION_SWITCH";
45 } // namespace
46 
OnAttachToFrameNode()47 void TabsPattern::OnAttachToFrameNode()
48 {
49     auto host = GetHost();
50     CHECK_NULL_VOID(host);
51     host->GetRenderContext()->SetClipToFrame(true);
52     // expand to navigation bar by default
53     host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(
54         { .type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_BOTTOM });
55 }
56 
SetOnChangeEvent(std::function<void (const BaseEventInfo *)> && event)57 void TabsPattern::SetOnChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
58 {
59     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
60     CHECK_NULL_VOID(tabsNode);
61     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
62     CHECK_NULL_VOID(swiperNode);
63 
64     ChangeEventWithPreIndex changeEvent([weak = WeakClaim(this), jsEvent = std::move(event)](
65                                             int32_t preIndex, int32_t currentIndex) {
66         auto pattern = weak.Upgrade();
67         CHECK_NULL_VOID(pattern);
68         auto tabsNode = AceType::DynamicCast<TabsNode>(pattern->GetHost());
69         CHECK_NULL_VOID(tabsNode);
70         auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
71         CHECK_NULL_VOID(tabBarNode);
72         auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
73         CHECK_NULL_VOID(tabBarPattern);
74         if (tabBarPattern->IsMaskAnimationExecuted()) {
75             return;
76         }
77         auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
78         CHECK_NULL_VOID(tabsLayoutProperty);
79         tabsLayoutProperty->UpdateIndex(currentIndex);
80         tabBarPattern->OnTabBarIndexChange(currentIndex);
81         pattern->FireTabContentStateCallback(preIndex, currentIndex);
82 
83         /* js callback */
84         if (jsEvent && tabsNode->IsOnMainTree()) {
85             pattern->RecordChangeEvent(currentIndex);
86             auto context = tabsNode->GetContext();
87             CHECK_NULL_VOID(context);
88             TAG_LOGI(
89                 AceLogTag::ACE_TABS, "onChange preIndex:%{public}d, currentIndex:%{public}d", preIndex, currentIndex);
90             context->AddAfterLayoutTask(
91                 [currentIndex, jsEvent]() {
92                     TabContentChangeEvent eventInfo(currentIndex);
93                     jsEvent(&eventInfo);
94                 }, true);
95         }
96     });
97 
98     if (onChangeEvent_) {
99         (*onChangeEvent_).swap(changeEvent);
100     } else {
101         onChangeEvent_ = std::make_shared<ChangeEventWithPreIndex>(changeEvent);
102         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
103         CHECK_NULL_VOID(eventHub);
104         eventHub->AddOnChangeEventWithPreIndex(onChangeEvent_);
105     }
106 }
107 
FireTabContentStateCallback(int32_t oldIndex,int32_t nextIndex) const108 void TabsPattern::FireTabContentStateCallback(int32_t oldIndex, int32_t nextIndex) const
109 {
110     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
111     CHECK_NULL_VOID(tabsNode);
112     std::string id = tabsNode->GetInspectorId().value_or("");
113     int32_t uniqueId = tabsNode->GetId();
114     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
115     CHECK_NULL_VOID(swiperNode);
116 
117     auto oldTabContent = AceType::DynamicCast<TabContentNode>(swiperNode->GetChildByIndex(oldIndex));
118     if (oldTabContent) {
119         std::string oldTabContentId = oldTabContent->GetInspectorId().value_or("");
120         int32_t oldTabContentUniqueId = oldTabContent->GetId();
121         TabContentInfo oldTabContentInfo(oldTabContentId, oldTabContentUniqueId, TabContentState::ON_HIDE, oldIndex,
122             id, uniqueId);
123         UIObserverHandler::GetInstance().NotifyTabContentStateUpdate(oldTabContentInfo);
124     }
125 
126     auto nextTabContent = AceType::DynamicCast<TabContentNode>(swiperNode->GetChildByIndex(nextIndex));
127     if (nextTabContent) {
128         std::string nextTabContentId = nextTabContent->GetInspectorId().value_or("");
129         int32_t nextTabContentUniqueId = nextTabContent->GetId();
130         TabContentInfo nextTabContentInfo(nextTabContentId, nextTabContentUniqueId, TabContentState::ON_SHOW, nextIndex,
131             id, uniqueId);
132         UIObserverHandler::GetInstance().NotifyTabContentStateUpdate(nextTabContentInfo);
133     }
134 }
135 
RecordChangeEvent(int32_t index)136 void TabsPattern::RecordChangeEvent(int32_t index)
137 {
138     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
139     CHECK_NULL_VOID(tabsNode);
140     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
141         auto inspectorId = tabsNode->GetInspectorId().value_or("");
142         auto tabBarText = GetTabBarTextByIndex(index);
143         Recorder::EventParamsBuilder builder;
144         builder.SetId(inspectorId)
145             .SetType(tabsNode->GetTag())
146             .SetIndex(index)
147             .SetText(tabBarText)
148             .SetHost(tabsNode)
149             .SetDescription(tabsNode->GetAutoEventParamValue(""));
150         Recorder::EventRecorder::Get().OnChange(std::move(builder));
151         if (!inspectorId.empty()) {
152             Recorder::NodeDataCache::Get().PutMultiple(tabsNode, inspectorId, tabBarText, index);
153         }
154     }
155 }
156 
GetTabBarTextByIndex(int32_t index) const157 std::string TabsPattern::GetTabBarTextByIndex(int32_t index) const
158 {
159     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
160     CHECK_NULL_RETURN(tabsNode, "");
161     auto tabBar = tabsNode->GetTabBar();
162     CHECK_NULL_RETURN(tabBar, "");
163     auto tabBarItem = tabBar->GetChildAtIndex(index);
164     CHECK_NULL_RETURN(tabBarItem, "");
165     auto node = AceType::DynamicCast<FrameNode>(tabBarItem);
166     CHECK_NULL_RETURN(node, "");
167     return node->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetGroupText(true);
168 }
169 
SetOnTabBarClickEvent(std::function<void (const BaseEventInfo *)> && event)170 void TabsPattern::SetOnTabBarClickEvent(std::function<void(const BaseEventInfo*)>&& event)
171 {
172     ChangeEvent tabBarClickEvent([jsEvent = std::move(event)](int32_t index) {
173         /* js callback */
174         if (jsEvent) {
175             TabContentChangeEvent eventInfo(index);
176             jsEvent(&eventInfo);
177         }
178     });
179 
180     if (onTabBarClickEvent_) {
181         (*onTabBarClickEvent_).swap(tabBarClickEvent);
182     } else {
183         onTabBarClickEvent_ = std::make_shared<ChangeEvent>(tabBarClickEvent);
184     }
185 }
186 
SetAnimationStartEvent(AnimationStartEvent && event)187 void TabsPattern::SetAnimationStartEvent(AnimationStartEvent&& event)
188 {
189     if (animationStartEvent_) {
190         (*animationStartEvent_).swap(event);
191     } else {
192         auto host = GetHost();
193         CHECK_NULL_VOID(host);
194         auto tabsNode = AceType::DynamicCast<TabsNode>(host);
195         CHECK_NULL_VOID(tabsNode);
196         auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
197         CHECK_NULL_VOID(swiperNode);
198         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
199         CHECK_NULL_VOID(eventHub);
200         animationStartEvent_ = std::make_shared<AnimationStartEvent>(std::move(event));
201         eventHub->AddAnimationStartEvent(animationStartEvent_);
202     }
203 }
204 
SetAnimationEndEvent(AnimationEndEvent && event)205 void TabsPattern::SetAnimationEndEvent(AnimationEndEvent&& event)
206 {
207     if (animationEndEvent_) {
208         (*animationEndEvent_).swap(event);
209     } else {
210         auto host = GetHost();
211         CHECK_NULL_VOID(host);
212         auto tabsNode = AceType::DynamicCast<TabsNode>(host);
213         CHECK_NULL_VOID(tabsNode);
214         auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
215         CHECK_NULL_VOID(swiperNode);
216         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
217         CHECK_NULL_VOID(eventHub);
218         animationEndEvent_ = std::make_shared<AnimationEndEvent>(std::move(event));
219         eventHub->AddAnimationEndEvent(animationEndEvent_);
220     }
221 }
222 
SetOnSelectedEvent(std::function<void (const BaseEventInfo *)> && event)223 void TabsPattern::SetOnSelectedEvent(std::function<void(const BaseEventInfo*)>&& event)
224 {
225     ChangeEvent selectedEvent([jsEvent = std::move(event)](int32_t index) {
226         /* js callback */
227         if (jsEvent) {
228             TabContentChangeEvent eventInfo(index);
229             jsEvent(&eventInfo);
230         }
231     });
232     if (selectedEvent_) {
233         (*selectedEvent_).swap(selectedEvent);
234     } else {
235         auto host = GetHost();
236         CHECK_NULL_VOID(host);
237         auto tabsNode = AceType::DynamicCast<TabsNode>(host);
238         CHECK_NULL_VOID(tabsNode);
239         auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
240         CHECK_NULL_VOID(swiperNode);
241         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
242         CHECK_NULL_VOID(eventHub);
243         selectedEvent_ = std::make_shared<ChangeEvent>(std::move(selectedEvent));
244         eventHub->AddOnSlectedEvent(selectedEvent_);
245     }
246 }
247 
OnUpdateShowDivider()248 void TabsPattern::OnUpdateShowDivider()
249 {
250     auto host = AceType::DynamicCast<TabsNode>(GetHost());
251     CHECK_NULL_VOID(host);
252     auto layoutProperty = host->GetLayoutProperty<TabsLayoutProperty>();
253     TabsItemDivider defaultDivider;
254     auto divider = layoutProperty->GetDivider().value_or(defaultDivider);
255     auto children = host->GetChildren();
256     if (children.size() < CHILDREN_MIN_SIZE) {
257         return;
258     }
259 
260     auto dividerFrameNode = AceType::DynamicCast<FrameNode>(host->GetDivider());
261     CHECK_NULL_VOID(dividerFrameNode);
262     auto dividerRenderProperty = dividerFrameNode->GetPaintProperty<DividerRenderProperty>();
263     CHECK_NULL_VOID(dividerRenderProperty);
264     dividerRenderProperty->UpdateDividerColor(divider.color);
265 
266     auto dividerLayoutProperty = dividerFrameNode->GetLayoutProperty<DividerLayoutProperty>();
267     CHECK_NULL_VOID(dividerLayoutProperty);
268     dividerLayoutProperty->UpdateStrokeWidth(divider.strokeWidth);
269     dividerFrameNode->MarkModifyDone();
270 }
271 
UpdateSwiperDisableSwipe(bool disableSwipe)272 void TabsPattern::UpdateSwiperDisableSwipe(bool disableSwipe)
273 {
274     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
275     CHECK_NULL_VOID(tabsNode);
276     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
277     CHECK_NULL_VOID(swiperNode);
278     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
279     CHECK_NULL_VOID(swiperPattern);
280     auto props = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
281     CHECK_NULL_VOID(props);
282     props->UpdateDisableSwipe(disableSwipe);
283     swiperPattern->UpdateSwiperPanEvent(disableSwipe);
284     swiperPattern->SetSwiperEventCallback(disableSwipe);
285 }
286 
SetSwiperPaddingAndBorder()287 void TabsPattern::SetSwiperPaddingAndBorder()
288 {
289     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
290     CHECK_NULL_VOID(tabsNode);
291     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
292     CHECK_NULL_VOID(swiperNode);
293     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
294     CHECK_NULL_VOID(swiperPattern);
295     auto layoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
296     CHECK_NULL_VOID(layoutProperty);
297     swiperPattern->SetTabsPaddingAndBorder(layoutProperty->CreatePaddingAndBorder());
298 }
299 
OnModifyDone()300 void TabsPattern::OnModifyDone()
301 {
302     Pattern::OnModifyDone();
303     UpdateSwiperDisableSwipe(isCustomAnimation_ ? true : isDisableSwipe_);
304     SetSwiperPaddingAndBorder();
305     InitFocusEvent();
306     InitAccessibilityZIndex();
307 
308     if (onChangeEvent_) {
309         return;
310     }
311     SetOnChangeEvent(nullptr);
312     OnUpdateShowDivider();
313 }
314 
OnAfterModifyDone()315 void TabsPattern::OnAfterModifyDone()
316 {
317     auto host = GetHost();
318     CHECK_NULL_VOID(host);
319     auto inspectorId = host->GetInspectorId().value_or("");
320     if (inspectorId.empty()) {
321         return;
322     }
323     auto property = GetLayoutProperty<TabsLayoutProperty>();
324     CHECK_NULL_VOID(property);
325     auto index = property->GetIndexValue(0);
326     auto tabBarText = GetTabBarTextByIndex(index);
327     Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, tabBarText, index);
328 }
329 
SetOnIndexChangeEvent(std::function<void (const BaseEventInfo *)> && event)330 void TabsPattern::SetOnIndexChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
331 {
332     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
333     CHECK_NULL_VOID(tabsNode);
334     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
335     CHECK_NULL_VOID(swiperNode);
336 
337     ChangeEvent changeEvent([weak = WeakClaim(this), jsEvent = std::move(event)](int32_t index) {
338         auto pattern = weak.Upgrade();
339         CHECK_NULL_VOID(pattern);
340         auto tabsNode = AceType::DynamicCast<TabsNode>(pattern->GetHost());
341         CHECK_NULL_VOID(tabsNode);
342         auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
343         CHECK_NULL_VOID(tabBarNode);
344         auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
345         CHECK_NULL_VOID(tabBarPattern);
346         if (tabBarPattern->IsMaskAnimationExecuted()) {
347             return;
348         }
349 
350         /* js callback */
351         if (jsEvent) {
352             TabContentChangeEvent eventInfo(index);
353             jsEvent(&eventInfo);
354         }
355     });
356 
357     if (onIndexChangeEvent_) {
358         (*onIndexChangeEvent_).swap(changeEvent);
359     } else {
360         onIndexChangeEvent_ = std::make_shared<ChangeEvent>(changeEvent);
361         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
362         CHECK_NULL_VOID(eventHub);
363         eventHub->AddOnChangeEvent(onIndexChangeEvent_);
364     }
365 }
366 
ProvideRestoreInfo()367 std::string TabsPattern::ProvideRestoreInfo()
368 {
369     auto jsonObj = JsonUtil::Create(true);
370     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
371     CHECK_NULL_RETURN(tabsNode, "");
372     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
373     CHECK_NULL_RETURN(tabBarNode, "");
374     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
375     CHECK_NULL_RETURN(tabBarPattern, "");
376     return tabBarPattern->ProvideRestoreInfo();
377 }
378 
OnRestoreInfo(const std::string & restoreInfo)379 void TabsPattern::OnRestoreInfo(const std::string& restoreInfo)
380 {
381     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
382     CHECK_NULL_VOID(tabsNode);
383     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
384     CHECK_NULL_VOID(tabBarNode);
385     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
386     CHECK_NULL_VOID(tabBarPattern);
387     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
388     CHECK_NULL_VOID(swiperNode);
389     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
390     CHECK_NULL_VOID(swiperPattern);
391     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
392     CHECK_NULL_VOID(swiperLayoutProperty);
393     auto info = JsonUtil::ParseJsonString(restoreInfo);
394     if (!info->IsValid() || !info->IsObject()) {
395         return;
396     }
397     auto jsonIsOn = info->GetValue("Index");
398     swiperLayoutProperty->UpdateIndex(jsonIsOn->GetInt());
399 
400     swiperPattern->OnRestoreInfo(restoreInfo);
401     tabBarPattern->OnRestoreInfo(restoreInfo);
402 }
403 
AddInnerOnGestureRecognizerJudgeBegin(GestureRecognizerJudgeFunc && gestureRecognizerJudgeFunc)404 void TabsPattern::AddInnerOnGestureRecognizerJudgeBegin(GestureRecognizerJudgeFunc&& gestureRecognizerJudgeFunc)
405 {
406     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
407     CHECK_NULL_VOID(tabsNode);
408     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
409     CHECK_NULL_VOID(swiperNode);
410     auto targetComponent = swiperNode->GetTargetComponent().Upgrade();
411     CHECK_NULL_VOID(targetComponent);
412     targetComponent->SetOnGestureRecognizerJudgeBegin(std::move(gestureRecognizerJudgeFunc));
413     targetComponent->SetInnerNodeGestureRecognizerJudge(true);
414 }
415 
RecoverInnerOnGestureRecognizerJudgeBegin()416 void TabsPattern::RecoverInnerOnGestureRecognizerJudgeBegin()
417 {
418     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
419     CHECK_NULL_VOID(tabsNode);
420     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
421     CHECK_NULL_VOID(swiperNode);
422     auto targetComponent = swiperNode->GetTargetComponent().Upgrade();
423     CHECK_NULL_VOID(targetComponent);
424     targetComponent->SetOnGestureRecognizerJudgeBegin(nullptr);
425     targetComponent->SetInnerNodeGestureRecognizerJudge(false);
426 }
427 
GetScopeFocusAlgorithm()428 ScopeFocusAlgorithm TabsPattern::GetScopeFocusAlgorithm()
429 {
430     auto property = GetLayoutProperty<TabsLayoutProperty>();
431     CHECK_NULL_RETURN(property, {});
432     bool isVertical = true;
433     if (property->GetAxis().has_value()) {
434         isVertical = property->GetAxis().value() == Axis::HORIZONTAL;
435     }
436     return ScopeFocusAlgorithm(isVertical, true, ScopeType::OTHERS,
437         [wp = WeakClaim(this)](
438             FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) -> bool {
439             auto tabs = wp.Upgrade();
440             if (tabs) {
441                 nextFocusNode = tabs->GetNextFocusNode(step, currFocusNode);
442             }
443             return nextFocusNode.Upgrade() != currFocusNode.Upgrade();
444         });
445 }
446 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)447 WeakPtr<FocusHub> TabsPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
448 {
449     auto curFocusNode = currentFocusNode.Upgrade();
450     CHECK_NULL_RETURN(curFocusNode, nullptr);
451 
452     auto property = GetLayoutProperty<TabsLayoutProperty>();
453     CHECK_NULL_RETURN(property, nullptr);
454     auto axis = property->GetAxis().value_or(Axis::HORIZONTAL);
455     auto tabBarPosition = property->GetTabBarPosition().value_or(BarPosition::START);
456     auto isRTL = property->GetNonAutoLayoutDirection() == TextDirection::RTL;
457 
458     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
459     CHECK_NULL_RETURN(tabsNode, nullptr);
460     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
461     CHECK_NULL_RETURN(tabBarNode, nullptr);
462     auto tabBarFocusNode = tabBarNode->GetFocusHub();
463     CHECK_NULL_RETURN(tabBarFocusNode, nullptr);
464     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
465     CHECK_NULL_RETURN(swiperNode, nullptr);
466     auto swiperFocusNode = swiperNode->GetFocusHub();
467     CHECK_NULL_RETURN(swiperFocusNode, nullptr);
468 
469     if (curFocusNode->GetFrameName() == V2::TAB_BAR_ETS_TAG) {
470         if (tabBarPosition == BarPosition::START) {
471             if (step == FocusStep::TAB || (axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
472                 (axis == Axis::VERTICAL && (isRTL ? step == FocusStep::LEFT : step == FocusStep::RIGHT))) {
473                 return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
474             }
475         } else {
476             if (step == FocusStep::SHIFT_TAB || (axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
477                 (axis == Axis::VERTICAL && (isRTL ? step == FocusStep::RIGHT : step == FocusStep::LEFT))) {
478                 return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
479             }
480         }
481     } else if (curFocusNode->GetFrameName() == V2::SWIPER_ETS_TAG) {
482         if (tabBarPosition == BarPosition::START) {
483             if (step == FocusStep::SHIFT_TAB || (axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
484                 (axis == Axis::VERTICAL && (isRTL ? step == FocusStep::RIGHT : step == FocusStep::LEFT))) {
485                 return AceType::WeakClaim(AceType::RawPtr(tabBarFocusNode));
486             }
487         } else {
488             if (step == FocusStep::TAB || (axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
489                 (axis == Axis::VERTICAL && (isRTL ? step == FocusStep::LEFT : step == FocusStep::RIGHT))) {
490                 return AceType::WeakClaim(AceType::RawPtr(tabBarFocusNode));
491             }
492         }
493         if (step == FocusStep::LEFT_END || step == FocusStep::RIGHT_END || step == FocusStep::UP_END ||
494             step == FocusStep::DOWN_END) {
495             return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
496         }
497     }
498     return nullptr;
499 }
500 
InitFocusEvent()501 void TabsPattern::InitFocusEvent()
502 {
503     auto host = GetHost();
504     CHECK_NULL_VOID(host);
505     auto focusHub = host->GetFocusHub();
506     CHECK_NULL_VOID(focusHub);
507 
508     auto getNextFocusNodeFunc = [weak = WeakClaim(this)](
509                                     FocusReason reason, FocusIntension intension) -> RefPtr<FocusHub> {
510         if (reason != FocusReason::FOCUS_TRAVEL) {
511             return nullptr;
512         }
513         auto pattern = weak.Upgrade();
514         CHECK_NULL_RETURN(pattern, nullptr);
515         return pattern->GetCurrentFocusNode(intension);
516     };
517     focusHub->SetOnGetNextFocusNodeFunc(getNextFocusNodeFunc);
518 }
519 
GetCurrentFocusNode(FocusIntension intension)520 RefPtr<FocusHub> TabsPattern::GetCurrentFocusNode(FocusIntension intension)
521 {
522     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
523     CHECK_NULL_RETURN(tabsNode, nullptr);
524     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
525     CHECK_NULL_RETURN(tabBarNode, nullptr);
526     auto tabBarFocusHub = tabBarNode->GetFocusHub();
527     CHECK_NULL_RETURN(tabBarFocusHub, nullptr);
528     if (!tabBarFocusHub->GetFocusable()) {
529         return nullptr;
530     }
531     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
532     CHECK_NULL_RETURN(swiperNode, nullptr);
533     auto swiperFocusHub = swiperNode->GetFocusHub();
534     CHECK_NULL_RETURN(swiperFocusHub, nullptr);
535 
536     auto property = GetLayoutProperty<TabsLayoutProperty>();
537     CHECK_NULL_RETURN(property, nullptr);
538     auto axis = property->GetAxis().value_or(Axis::HORIZONTAL);
539     auto barPosition = property->GetTabBarPosition().value_or(BarPosition::START);
540     auto isRTL = property->GetNonAutoLayoutDirection() == TextDirection::RTL;
541 
542     auto focusFirstNodeIntension = intension == FocusIntension::TAB || intension == FocusIntension::SELECT ||
543                                    intension == FocusIntension::HOME;
544     auto focusLastNodeIntension = intension == FocusIntension::SHIFT_TAB || intension == FocusIntension::END;
545     auto firstFocusHub = barPosition == BarPosition::START ? tabBarFocusHub : swiperFocusHub;
546     auto lastFocusHub = barPosition == BarPosition::START ? swiperFocusHub : tabBarFocusHub;
547     if (focusFirstNodeIntension) {
548         return firstFocusHub;
549     } else if (focusLastNodeIntension) {
550         return lastFocusHub;
551     } else if (axis == Axis::HORIZONTAL) {
552         if (intension == FocusIntension::DOWN || intension == FocusIntension::LEFT ||
553             intension == FocusIntension::RIGHT) {
554             return firstFocusHub;
555         } else if (intension == FocusIntension::UP) {
556             return lastFocusHub;
557         }
558     } else {
559         if (intension == FocusIntension::DOWN || intension == FocusIntension::UP) {
560             return firstFocusHub;
561         } else if (intension == FocusIntension::LEFT) {
562             return (isRTL ? barPosition == BarPosition::END : barPosition == BarPosition::START) ? swiperFocusHub
563                                                                                                  : tabBarFocusHub;
564         } else if (intension == FocusIntension::RIGHT) {
565             return (isRTL ? barPosition == BarPosition::END : barPosition == BarPosition::START) ? tabBarFocusHub
566                                                                                                  : swiperFocusHub;
567         }
568     }
569     return nullptr;
570 }
571 
InitAccessibilityZIndex()572 void TabsPattern::InitAccessibilityZIndex()
573 {
574     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
575     CHECK_NULL_VOID(tabsNode);
576     auto tabsLayoutProperty = GetLayoutProperty<TabsLayoutProperty>();
577     CHECK_NULL_VOID(tabsLayoutProperty);
578     BarPosition barPosition = tabsLayoutProperty->GetTabBarPositionValue(BarPosition::START);
579     if (barPosition != barPosition_) {
580         auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
581         CHECK_NULL_VOID(swiperNode);
582         auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
583         CHECK_NULL_VOID(tabBarNode);
584         auto swiperAccessibilityProperty = swiperNode->GetAccessibilityProperty<NG::AccessibilityProperty>();
585         CHECK_NULL_VOID(swiperAccessibilityProperty);
586         auto tabBarAccessibilityProperty = tabBarNode->GetAccessibilityProperty<NG::AccessibilityProperty>();
587         CHECK_NULL_VOID(tabBarAccessibilityProperty);
588         if (barPosition == BarPosition::START) {
589             swiperAccessibilityProperty->SetAccessibilityZIndex(1);
590             tabBarAccessibilityProperty->SetAccessibilityZIndex(0);
591         } else {
592             swiperAccessibilityProperty->SetAccessibilityZIndex(0);
593             tabBarAccessibilityProperty->SetAccessibilityZIndex(1);
594         }
595         barPosition_ = barPosition;
596     }
597 }
598 
BeforeCreateLayoutWrapper()599 void TabsPattern::BeforeCreateLayoutWrapper()
600 {
601     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
602     CHECK_NULL_VOID(tabsNode);
603     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
604     CHECK_NULL_VOID(tabBarNode);
605     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
606     CHECK_NULL_VOID(swiperNode);
607     auto tabsLayoutProperty = GetLayoutProperty<TabsLayoutProperty>();
608     CHECK_NULL_VOID(tabsLayoutProperty);
609     UpdateIndex(tabsNode, tabBarNode, swiperNode, tabsLayoutProperty);
610 
611     if (isInit_) {
612         auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
613         CHECK_NULL_VOID(swiperPattern);
614         swiperPattern->SetOnHiddenChangeForParent();
615         auto parent = tabsNode->GetAncestorNodeOfFrame(false);
616         CHECK_NULL_VOID(parent);
617         while (parent && parent->GetTag() != V2::NAVDESTINATION_VIEW_ETS_TAG) {
618             parent = parent->GetAncestorNodeOfFrame(false);
619         }
620         if (!parent) {
621             auto willShowIndex = tabsLayoutProperty->GetIndex().value_or(0);
622             swiperPattern->FireSelectedEvent(-1, willShowIndex);
623             swiperPattern->FireWillShowEvent(willShowIndex);
624         }
625         isInit_ = false;
626     }
627 
628     auto childrenUpdated = swiperNode->GetChildrenUpdated() != -1;
629     if (childrenUpdated) {
630         HandleChildrenUpdated(swiperNode, tabBarNode);
631 
632         auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
633         CHECK_NULL_VOID(tabBarPattern);
634         auto index = tabsLayoutProperty->GetIndexValue(0);
635         auto tabContentNum = swiperNode->TotalChildCount();
636         if (index >= tabContentNum) {
637             index = 0;
638         }
639         UpdateSelectedState(swiperNode, tabBarPattern, tabsLayoutProperty, index);
640     }
641 }
642 
UpdateIndex(const RefPtr<FrameNode> & tabsNode,const RefPtr<FrameNode> & tabBarNode,const RefPtr<FrameNode> & swiperNode,const RefPtr<TabsLayoutProperty> & tabsLayoutProperty)643 void TabsPattern::UpdateIndex(const RefPtr<FrameNode>& tabsNode, const RefPtr<FrameNode>& tabBarNode,
644     const RefPtr<FrameNode>& swiperNode, const RefPtr<TabsLayoutProperty>& tabsLayoutProperty)
645 {
646     if (!tabsLayoutProperty->GetIndexSetByUser().has_value()) {
647         return;
648     }
649     auto tabsPattern = tabsNode->GetPattern<TabsPattern>();
650     CHECK_NULL_VOID(tabsPattern);
651     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
652     CHECK_NULL_VOID(tabBarPattern);
653     auto indexSetByUser = tabsLayoutProperty->GetIndexSetByUser().value();
654     auto index = indexSetByUser;
655     tabsLayoutProperty->ResetIndexSetByUser();
656     auto tabContentNum = swiperNode->TotalChildCount();
657     if (index >= tabContentNum) {
658         index = 0;
659     }
660     if (!tabsLayoutProperty->GetIndex().has_value()) {
661         UpdateSelectedState(swiperNode, tabBarPattern, tabsLayoutProperty, index);
662         tabsLayoutProperty->UpdateIndex(indexSetByUser < 0 ? 0 : indexSetByUser);
663     } else {
664         auto preIndex = tabsLayoutProperty->GetIndex().value();
665         if (preIndex == index || index < 0) {
666             return;
667         }
668         if (tabsPattern->GetInterceptStatus()) {
669             auto ret = tabsPattern->OnContentWillChange(preIndex, index);
670             if (ret.has_value() && !ret.value()) {
671                 return;
672             }
673         }
674         AceAsyncTraceBeginCommercial(0, APP_TABS_NO_ANIMATION_SWITCH);
675         tabBarPattern->SetMaskAnimationByCreate(true);
676         UpdateSelectedState(swiperNode, tabBarPattern, tabsLayoutProperty, index);
677     }
678 }
679 
SetAnimateMode(TabAnimateMode mode)680 void TabsPattern::SetAnimateMode(TabAnimateMode mode)
681 {
682     animateMode_ = mode;
683     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
684     CHECK_NULL_VOID(tabsNode);
685     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
686     CHECK_NULL_VOID(swiperNode);
687     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
688     CHECK_NULL_VOID(swiperPattern);
689     swiperPattern->SetJumpAnimationMode(mode);
690 }
691 
692 /**
693  * @brief Handles the update of children in the TabsPattern component.
694  *
695  * This function is responsible for updating the children of the TabsPattern component,
696  * specifically the swiperNode and tabBarNode. It performs the following steps:
697  * 1. Creates a map of tabBarItems using the tabBarItemNodes from the tabBarNode.
698  * 2. Traverses the tree of UINodes starting from the swiperNode using a stack.
699  * 3. For each UINode, if it is an instance of TabContentNode, it retrieves the corresponding
700  *    tabBarItem from the tabBarItems map and moves it to position 0.
701  * 4. Continues traversing the tree by pushing the children of the current UINode onto the stack.
702  *
703  * @param swiperNode The FrameNode representing the swiper component.
704  * @param tabBarNode The FrameNode representing the tab bar component.
705  */
HandleChildrenUpdated(const RefPtr<FrameNode> & swiperNode,const RefPtr<FrameNode> & tabBarNode)706 void TabsPattern::HandleChildrenUpdated(const RefPtr<FrameNode>& swiperNode, const RefPtr<FrameNode>& tabBarNode)
707 {
708     std::map<int32_t, RefPtr<FrameNode>> tabBarItems;
709     for (const auto& tabBarItemNode : tabBarNode->GetChildren()) {
710         CHECK_NULL_VOID(tabBarItemNode);
711         auto tabBarItemFrameNode = AceType::DynamicCast<FrameNode>(tabBarItemNode);
712         tabBarItems[tabBarItemFrameNode->GetId()] = tabBarItemFrameNode;
713     }
714     std::stack<RefPtr<UINode>> stack;
715     stack.push(swiperNode);
716     while (!stack.empty()) {
717         auto parent = stack.top();
718         stack.pop();
719         if (AceType::InstanceOf<TabContentNode>(parent)) {
720             auto tabContentNode = AceType::DynamicCast<TabContentNode>(parent);
721             auto tabBarItem = tabBarItems[tabContentNode->GetTabBarItemId()];
722             CHECK_NULL_VOID(tabBarItem);
723             tabBarItem->MovePosition(0);
724             continue;
725         }
726         for (const auto& child : parent->GetChildren()) {
727             stack.push(child);
728         }
729     }
730 
731     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
732     CHECK_NULL_VOID(tabBarPattern);
733     tabBarPattern->AdjustTabBarInfo();
734 }
735 
736 /**
737  * @brief Update selected state.
738  *
739  * This function is responsible for updating the indicator, text color, font weight, image color,
740  * and index of the tab bar and swiper nodes when updating children or creating a tab.
741  *
742  * @param swiperNode The node representing the swiper.
743  * @param tabBarPattern The pattern for the tab bar.
744  * @param tabsLayoutProperty The layout property for the tabs.
745  * @param index The index of the tab being created.
746  */
UpdateSelectedState(const RefPtr<FrameNode> & swiperNode,const RefPtr<TabBarPattern> & tabBarPattern,const RefPtr<TabsLayoutProperty> & tabsLayoutProperty,int index)747 void TabsPattern::UpdateSelectedState(const RefPtr<FrameNode>& swiperNode, const RefPtr<TabBarPattern>& tabBarPattern,
748     const RefPtr<TabsLayoutProperty>& tabsLayoutProperty, int index)
749 {
750     if (index < 0) {
751         index = 0;
752     }
753     tabBarPattern->UpdateIndicator(index);
754     tabBarPattern->ResetIndicatorAnimationState();
755     tabBarPattern->UpdateSubTabBoard(index);
756     tabBarPattern->UpdateTextColorAndFontWeight(index);
757     tabBarPattern->AdjustSymbolStats(index);
758     tabBarPattern->UpdateImageColor(index);
759     CHECK_NULL_VOID(swiperNode);
760     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
761     CHECK_NULL_VOID(swiperPattern);
762     if (!swiperPattern->IsInFastAnimation()) {
763         auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
764         CHECK_NULL_VOID(swiperLayoutProperty);
765         swiperLayoutProperty->UpdateIndex(index);
766     }
767     tabsLayoutProperty->UpdateIndex(index);
768 }
769 
SetOnUnselectedEvent(std::function<void (const BaseEventInfo *)> && event)770 void TabsPattern::SetOnUnselectedEvent(std::function<void(const BaseEventInfo*)>&& event)
771 {
772     ChangeEvent unselectedEvent([jsEvent = std::move(event)](int32_t index) {
773         /* js callback */
774         if (jsEvent) {
775             TabContentChangeEvent eventInfo(index);
776             jsEvent(&eventInfo);
777         }
778     });
779     if (unselectedEvent_) {
780         (*unselectedEvent_).swap(unselectedEvent);
781     } else {
782         auto host = GetHost();
783         CHECK_NULL_VOID(host);
784         auto tabsNode = AceType::DynamicCast<TabsNode>(host);
785         CHECK_NULL_VOID(tabsNode);
786         auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
787         CHECK_NULL_VOID(swiperNode);
788         auto eventHub = swiperNode->GetOrCreateEventHub<SwiperEventHub>();
789         CHECK_NULL_VOID(eventHub);
790         unselectedEvent_ = std::make_shared<ChangeEvent>(std::move(unselectedEvent));
791         eventHub->AddOnUnselectedEvent(unselectedEvent_);
792     }
793 }
794 
OnColorModeChange(uint32_t colorMode)795 void TabsPattern::OnColorModeChange(uint32_t colorMode)
796 {
797     CHECK_NULL_VOID(SystemProperties::ConfigChangePerform());
798     Pattern::OnColorModeChange(colorMode);
799     auto host = GetHost();
800     CHECK_NULL_VOID(host);
801     auto tabsNode = AceType::DynamicCast<TabsNode>(host);
802     CHECK_NULL_VOID(tabsNode);
803     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
804     CHECK_NULL_VOID(tabBarNode);
805     auto pipeline = host->GetContextWithCheck();
806     CHECK_NULL_VOID(pipeline);
807     auto theme = pipeline->GetTheme<TabTheme>();
808     CHECK_NULL_VOID(theme);
809     auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
810     CHECK_NULL_VOID(tabsLayoutProperty);
811 
812     if (!tabsLayoutProperty->HasDividerColorSetByUser() ||
813         (tabsLayoutProperty->HasDividerColorSetByUser() && !tabsLayoutProperty->GetDividerColorSetByUserValue())) {
814         auto currentDivider = tabsLayoutProperty->GetDivider().value_or(TabsItemDivider());
815         currentDivider.color = theme->GetDividerColor();
816         auto dividerFrameNode = AceType::DynamicCast<FrameNode>(tabsNode->GetDivider());
817         CHECK_NULL_VOID(dividerFrameNode);
818         auto dividerRenderProperty = dividerFrameNode->GetPaintProperty<DividerRenderProperty>();
819         CHECK_NULL_VOID(dividerRenderProperty);
820         dividerRenderProperty->UpdateDividerColor(currentDivider.color);
821     }
822     tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
823 }
824 } // namespace OHOS::Ace::NG
825