• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/text_field/text_field_manager.h"
17 
18 #include "base/geometry/dimension.h"
19 #include "base/memory/ace_type.h"
20 #include "base/utils/utils.h"
21 #include "core/components_ng/event/focus_hub.h"
22 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
23 #include "core/components_ng/pattern/text/text_base.h"
24 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr Dimension RESERVE_BOTTOM_HEIGHT = 24.0_vp;
29 } // namespace
30 
ClearOnFocusTextField()31 void TextFieldManagerNG::ClearOnFocusTextField()
32 {
33     onFocusTextField_ = nullptr;
34 }
35 
OnBackPressed()36 bool TextFieldManagerNG::OnBackPressed()
37 {
38     auto pattern = onFocusTextField_.Upgrade();
39     CHECK_NULL_RETURN(pattern, false);
40     auto textBasePattern = AceType::DynamicCast<TextBase>(pattern);
41     CHECK_NULL_RETURN(textBasePattern, false);
42     return textBasePattern->OnBackPressed();
43 }
44 
FindScrollableOfFocusedTextField(const RefPtr<FrameNode> & textField)45 RefPtr<FrameNode> TextFieldManagerNG::FindScrollableOfFocusedTextField(const RefPtr<FrameNode>& textField)
46 {
47     CHECK_NULL_RETURN(textField, {});
48     auto parent = textField->GetAncestorNodeOfFrame();
49     while (parent) {
50         auto pattern = parent->GetPattern<ScrollablePattern>();
51         if (pattern) {
52             return parent;
53         }
54         parent = parent->GetAncestorNodeOfFrame();
55     }
56     return {};
57 }
58 
ScrollToSafeAreaHelper(const SafeAreaInsets::Inset & bottomInset,bool isShowKeyboard)59 void TextFieldManagerNG::ScrollToSafeAreaHelper(
60     const SafeAreaInsets::Inset& bottomInset, bool isShowKeyboard)
61 {
62     auto node = onFocusTextField_.Upgrade();
63     CHECK_NULL_VOID(node);
64     auto frameNode = node->GetHost();
65     CHECK_NULL_VOID(frameNode);
66     auto textBase = DynamicCast<TextBase>(node);
67     CHECK_NULL_VOID(textBase);
68     textBase->OnVirtualKeyboardAreaChanged();
69 
70     auto scrollableNode = FindScrollableOfFocusedTextField(frameNode);
71     CHECK_NULL_VOID(scrollableNode);
72     auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
73     CHECK_NULL_VOID(scrollPattern);
74     if (scrollPattern->GetAxis() == Axis::HORIZONTAL) {
75         return;
76     }
77 
78     auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
79     if (isShowKeyboard) {
80         CHECK_NULL_VOID(scrollableRect.Top() < bottomInset.start);
81     }
82 
83     auto caretRect = textBase->GetCaretRect() + frameNode->GetOffsetRelativeToWindow();
84     auto diffTop = caretRect.Top() - scrollableRect.Top();
85     // caret height larger scroll's content region
86     if (isShowKeyboard) {
87         if (diffTop <= 0 &&
88             LessNotEqual(bottomInset.start, (caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()))) {
89             return;
90         }
91     }
92 
93     // caret above scroll's content region
94     if (diffTop < 0) {
95         scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() + diffTop);
96         return;
97     }
98 
99     // caret inner scroll's content region
100     if (isShowKeyboard) {
101         if (LessNotEqual((caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()), bottomInset.start)) {
102             return;
103         }
104     }
105 
106     // caret below safeArea
107     float diffBot = 0.0f;
108     if (isShowKeyboard) {
109         diffBot = bottomInset.start - caretRect.Bottom() - RESERVE_BOTTOM_HEIGHT.ConvertToPx();
110     } else {
111         diffBot = scrollableRect.Bottom() - caretRect.Bottom() - RESERVE_BOTTOM_HEIGHT.ConvertToPx();
112     }
113     CHECK_NULL_VOID(diffBot < 0);
114     scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() - diffBot);
115 }
116 
ScrollTextFieldToSafeArea()117 void TextFieldManagerNG::ScrollTextFieldToSafeArea()
118 {
119     auto pipeline = PipelineContext::GetCurrentContext();
120     CHECK_NULL_VOID(pipeline);
121     auto keyboardInset = pipeline->GetSafeAreaManager()->GetKeyboardInset();
122     bool isShowKeyboard = keyboardInset.IsValid();
123     if (isShowKeyboard) {
124         auto bottomInset = pipeline->GetSafeArea().bottom_.Combine(keyboardInset);
125         CHECK_NULL_VOID(bottomInset.IsValid());
126         ScrollToSafeAreaHelper(bottomInset, isShowKeyboard);
127     } else if (pipeline->GetSafeAreaManager()->KeyboardSafeAreaEnabled()) {
128         // hide keyboard only scroll when keyboard avoid mode is resize
129         ScrollToSafeAreaHelper({0, 0}, isShowKeyboard);
130     }
131 }
132 
SetHeight(float height)133 void TextFieldManagerNG::SetHeight(float height)
134 {
135     height_ = height + RESERVE_BOTTOM_HEIGHT.ConvertToPx();
136 }
137 
UpdateScrollableParentViewPort(const RefPtr<FrameNode> & node)138 void TextFieldManagerNG::UpdateScrollableParentViewPort(const RefPtr<FrameNode>& node)
139 {
140     CHECK_NULL_VOID(node);
141     auto scrollableNode = FindScrollableOfFocusedTextField(node);
142     CHECK_NULL_VOID(scrollableNode);
143     auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
144     CHECK_NULL_VOID(scrollPattern);
145     if (scrollPattern->GetAxis() == Axis::HORIZONTAL) {
146         return;
147     }
148     auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
149     scrollableNode->SetViewPort(scrollableRect);
150 }
ProcessNavKeyboard()151 void TextFieldManagerNG::ProcessNavKeyboard()
152 {
153     if (imeShow_ || uiExtensionImeShow_) {
154         TAG_LOGI(AceLogTag::ACE_KEYBOARD, "Nav notNeedSoftKeyboard.");
155         FocusHub::NavCloseKeyboard();
156     }
157 }
158 } // namespace OHOS::Ace::NG
159