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