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/common/ime/text_input_type.h"
22 #include "core/components_ng/event/focus_hub.h"
23 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
24 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
25 #include "core/components_ng/pattern/text/text_base.h"
26 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
27
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr Dimension RESERVE_BOTTOM_HEIGHT = 24.0_vp;
31 } // namespace
32
ClearOnFocusTextField()33 void TextFieldManagerNG::ClearOnFocusTextField()
34 {
35 onFocusTextField_ = nullptr;
36 }
37
ClearOnFocusTextField(int32_t id)38 void TextFieldManagerNG::ClearOnFocusTextField(int32_t id)
39 {
40 if (onFocusTextFieldId == id) {
41 onFocusTextField_ = nullptr;
42 focusFieldIsInline = false;
43 optionalPosition_ = std::nullopt;
44 usingCustomKeyboardAvoid_ = false;
45 isScrollableChild_ = false;
46 }
47 }
48
OnBackPressed()49 bool TextFieldManagerNG::OnBackPressed()
50 {
51 auto pattern = onFocusTextField_.Upgrade();
52 CHECK_NULL_RETURN(pattern, false);
53 auto textBasePattern = AceType::DynamicCast<TextBase>(pattern);
54 CHECK_NULL_RETURN(textBasePattern, false);
55 return textBasePattern->OnBackPressed();
56 }
57
SetClickPosition(const Offset & position)58 void TextFieldManagerNG::SetClickPosition(const Offset& position)
59 {
60 auto pipeline = PipelineContext::GetCurrentContextSafely();
61 CHECK_NULL_VOID(pipeline);
62 auto rootHeight = pipeline->GetRootHeight();
63 if (GreatOrEqual(position.GetY(), rootHeight)) {
64 auto pattern = onFocusTextField_.Upgrade();
65 CHECK_NULL_VOID(pattern);
66 auto host = pattern->GetHost();
67 CHECK_NULL_VOID(host);
68 auto parent = host->GetAncestorNodeOfFrame();
69 while (parent) {
70 if (parent->GetTag() == "Panel" || parent->GetTag() == "SheetPage") {
71 return;
72 }
73 parent = parent->GetAncestorNodeOfFrame();
74 }
75 }
76 if (LessOrEqual(position.GetY(), 0.0f)) {
77 return;
78 }
79 auto rootWidth = pipeline->GetRootWidth();
80 if (GreatOrEqual(position.GetX(), rootWidth) || LessNotEqual(position.GetX(), 0.0f)) {
81 return;
82 }
83 position_ = position;
84 optionalPosition_ = position;
85 }
86
FindScrollableOfFocusedTextField(const RefPtr<FrameNode> & textField)87 RefPtr<FrameNode> TextFieldManagerNG::FindScrollableOfFocusedTextField(const RefPtr<FrameNode>& textField)
88 {
89 CHECK_NULL_RETURN(textField, {});
90 auto parent = textField->GetAncestorNodeOfFrame();
91 while (parent) {
92 auto pattern = parent->GetPattern<ScrollablePattern>();
93 if (pattern) {
94 return parent;
95 }
96 parent = parent->GetAncestorNodeOfFrame();
97 }
98 return {};
99 }
100
GetFocusedNodeCaretRect()101 RectF TextFieldManagerNG::GetFocusedNodeCaretRect()
102 {
103 auto node = onFocusTextField_.Upgrade();
104 CHECK_NULL_RETURN(node, RectF());
105 auto frameNode = node->GetHost();
106 CHECK_NULL_RETURN(frameNode, RectF());
107 auto textBase = DynamicCast<TextBase>(node);
108 CHECK_NULL_RETURN(textBase, RectF());
109 auto caretRect = textBase->GetCaretRect() + frameNode->GetTransformRectRelativeToWindow();
110 return caretRect;
111 }
112
TriggerCustomKeyboardAvoid()113 void TextFieldManagerNG::TriggerCustomKeyboardAvoid()
114 {
115 CHECK_NULL_VOID(UsingCustomKeyboardAvoid());
116 auto pattern = onFocusTextField_.Upgrade();
117 CHECK_NULL_VOID(pattern);
118 auto curPattern = DynamicCast<TextFieldPattern>(pattern);
119 CHECK_NULL_VOID(curPattern);
120 if (!curPattern->GetIsCustomKeyboardAttached()) {
121 return;
122 }
123 auto caretHeight = curPattern->GetCaretRect().Height();
124 auto safeHeight = caretHeight + curPattern->GetCaretRect().GetY();
125 if (curPattern->GetCaretRect().GetY() > caretHeight) {
126 safeHeight = caretHeight;
127 }
128 auto keyboardOverLay = curPattern->GetKeyboardOverLay();
129 CHECK_NULL_VOID(keyboardOverLay);
130 auto host = curPattern->GetHost();
131 CHECK_NULL_VOID(host);
132 auto nodeId = host->GetId();
133 keyboardOverLay->AvoidCustomKeyboard(nodeId, safeHeight);
134 }
135
TriggerAvoidOnCaretChange()136 void TextFieldManagerNG::TriggerAvoidOnCaretChange()
137 {
138 auto pattern = onFocusTextField_.Upgrade();
139 CHECK_NULL_VOID(pattern);
140 auto host = pattern->GetHost();
141 CHECK_NULL_VOID(host);
142 auto pipeline = host->GetContext();
143 CHECK_NULL_VOID(pipeline);
144 auto safeAreaManager = pipeline->GetSafeAreaManager();
145 CHECK_NULL_VOID(safeAreaManager);
146 if (!pipeline->UsingCaretAvoidMode() || NearEqual(safeAreaManager->GetKeyboardInset().Length(), 0)) {
147 return;
148 }
149 if (UsingCustomKeyboardAvoid()) {
150 ScrollTextFieldToSafeArea();
151 TriggerCustomKeyboardAvoid();
152 } else {
153 ScrollTextFieldToSafeArea();
154 auto keyboardInset = safeAreaManager->GetKeyboardInset();
155 lastKeyboardOffset_ = safeAreaManager->GetKeyboardOffsetDirectly();
156 Rect keyboardRect;
157 keyboardRect.SetRect(0, 0, 0, keyboardInset.Length());
158 pipeline->OnVirtualKeyboardAreaChange(keyboardRect,
159 GetFocusedNodeCaretRect().Top(), GetHeight());
160 }
161 auto currentKeyboardOffset = safeAreaManager->GetKeyboardOffsetDirectly();
162 if (currentKeyboardOffset != lastKeyboardOffset_) {
163 AvoidKeyboardInSheet(host);
164 }
165 }
166
GetOnFocusTextFieldInfo(const WeakPtr<Pattern> & onFocusTextField)167 void TextFieldManagerNG::GetOnFocusTextFieldInfo(const WeakPtr<Pattern>& onFocusTextField)
168 {
169 auto node = onFocusTextField.Upgrade();
170 CHECK_NULL_VOID(node);
171 auto frameNode = node->GetHost();
172 CHECK_NULL_VOID(frameNode);
173 auto scrollableNode = FindScrollableOfFocusedTextField(frameNode);
174 CHECK_NULL_VOID(scrollableNode);
175 auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
176 CHECK_NULL_VOID(scrollPattern);
177 isScrollableChild_ = scrollPattern->IsScrollToSafeAreaHelper();
178 TAG_LOGI(ACE_KEYBOARD, "isScrollableChild_: %{public}d", isScrollableChild_);
179 }
180
ScrollToSafeAreaHelper(const SafeAreaInsets::Inset & bottomInset,bool isShowKeyboard)181 bool TextFieldManagerNG::ScrollToSafeAreaHelper(
182 const SafeAreaInsets::Inset& bottomInset, bool isShowKeyboard)
183 {
184 auto node = onFocusTextField_.Upgrade();
185 CHECK_NULL_RETURN(node, false);
186 auto frameNode = node->GetHost();
187 CHECK_NULL_RETURN(frameNode, false);
188 auto textBase = DynamicCast<TextBase>(node);
189 CHECK_NULL_RETURN(textBase, false);
190 textBase->OnVirtualKeyboardAreaChanged();
191
192 auto scrollableNode = FindScrollableOfFocusedTextField(frameNode);
193 CHECK_NULL_RETURN(scrollableNode, false);
194 auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
195 CHECK_NULL_RETURN(scrollPattern && scrollPattern->IsScrollToSafeAreaHelper(), false);
196 CHECK_NULL_RETURN(scrollPattern->GetAxis() != Axis::HORIZONTAL, false);
197
198 auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
199 if (isShowKeyboard) {
200 CHECK_NULL_RETURN(scrollableRect.Top() < bottomInset.start, false);
201 }
202
203 auto pipeline = frameNode->GetContext();
204 CHECK_NULL_RETURN(pipeline, false);
205 auto safeAreaManager = pipeline->GetSafeAreaManager();
206 CHECK_NULL_RETURN(safeAreaManager, false);
207 if (pipeline->UsingCaretAvoidMode()) {
208 scrollableRect.SetTop(scrollableRect.Top() - safeAreaManager->GetKeyboardOffset());
209 }
210
211 auto caretRect = textBase->GetCaretRect() + frameNode->GetPositionToWindowWithTransform();
212 auto diffTop = caretRect.Top() - scrollableRect.Top();
213 // caret height larger scroll's content region
214 if (isShowKeyboard && diffTop <= 0 && LessNotEqual(bottomInset.start,
215 (caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()))) {
216 return false;
217 }
218
219 // caret above scroll's content region
220 if (diffTop < 0) {
221 TAG_LOGI(ACE_KEYBOARD, "scrollRect:%{public}s caretRect:%{public}s totalOffset()=%{public}f diffTop=%{public}f",
222 scrollableRect.ToString().c_str(), caretRect.ToString().c_str(), scrollPattern->GetTotalOffset(), diffTop);
223 scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() + diffTop);
224 return true;
225 }
226
227 // caret inner scroll's content region
228 if (isShowKeyboard && LessNotEqual((caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()), bottomInset.start)) {
229 return false;
230 }
231
232 // caret below safeArea
233 float diffBot = 0.0f;
234
235 auto scrollBottom = isShowKeyboard && GreatOrEqual(scrollableRect.Bottom(), bottomInset.start) ?
236 bottomInset.start : scrollableRect.Bottom();
237 diffBot = scrollBottom - caretRect.Bottom() - RESERVE_BOTTOM_HEIGHT.ConvertToPx();
238 CHECK_NULL_RETURN(diffBot < 0, false);
239 TAG_LOGI(ACE_KEYBOARD, "scrollRect:%{public}s caretRect:%{public}s totalOffset()=%{public}f diffBot=%{public}f",
240 scrollableRect.ToString().c_str(), caretRect.ToString().c_str(), scrollPattern->GetTotalOffset(), diffBot);
241 scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() - diffBot);
242 return true;
243 }
244
ScrollTextFieldToSafeArea()245 bool TextFieldManagerNG::ScrollTextFieldToSafeArea()
246 {
247 auto pipeline = PipelineContext::GetCurrentContext();
248 CHECK_NULL_RETURN(pipeline, false);
249 auto keyboardInset = pipeline->GetSafeAreaManager()->GetKeyboardInset();
250 bool isShowKeyboard = keyboardInset.IsValid();
251 if (isShowKeyboard) {
252 auto bottomInset = pipeline->GetSafeArea().bottom_.Combine(keyboardInset);
253 CHECK_NULL_RETURN(bottomInset.IsValid(), false);
254 return ScrollToSafeAreaHelper(bottomInset, isShowKeyboard);
255 } else if (pipeline->GetSafeAreaManager()->KeyboardSafeAreaEnabled()) {
256 // hide keyboard only scroll when keyboard avoid mode is resize
257 return ScrollToSafeAreaHelper({0, 0}, isShowKeyboard);
258 }
259 return false;
260 }
261
SetHeight(float height)262 void TextFieldManagerNG::SetHeight(float height)
263 {
264 height_ = height + RESERVE_BOTTOM_HEIGHT.ConvertToPx();
265 }
266
UpdateScrollableParentViewPort(const RefPtr<FrameNode> & node)267 void TextFieldManagerNG::UpdateScrollableParentViewPort(const RefPtr<FrameNode>& node)
268 {
269 CHECK_NULL_VOID(node);
270 auto scrollableNode = FindScrollableOfFocusedTextField(node);
271 CHECK_NULL_VOID(scrollableNode);
272 auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
273 CHECK_NULL_VOID(scrollPattern);
274 if (scrollPattern->GetAxis() == Axis::HORIZONTAL) {
275 return;
276 }
277 auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
278 scrollableNode->SetViewPort(scrollableRect);
279 }
280
AvoidKeyBoardInNavigation()281 void TextFieldManagerNG::AvoidKeyBoardInNavigation()
282 {
283 auto node = onFocusTextField_.Upgrade();
284 auto pipeline = PipelineContext::GetCurrentContext();
285 CHECK_NULL_VOID(pipeline);
286 auto manager = pipeline->GetSafeAreaManager();
287 auto avoidKeyboardOffset = manager ? manager->GetKeyboardOffset() : 0.0f;
288 if (!node) {
289 auto navNode = weakNavNode_.Upgrade();
290 CHECK_NULL_VOID(navNode);
291 SetNavContentAvoidKeyboardOffset(navNode, avoidKeyboardOffset);
292 return;
293 }
294 auto frameNode = node->GetHost();
295 CHECK_NULL_VOID(frameNode);
296 auto preNavNode = weakNavNode_.Upgrade();
297 if (preNavNode) {
298 SetNavContentAvoidKeyboardOffset(preNavNode, 0.0f);
299 }
300 auto navNode = FindNavNode(frameNode);
301 CHECK_NULL_VOID(navNode);
302 weakNavNode_ = navNode;
303 SetNavContentAvoidKeyboardOffset(navNode, avoidKeyboardOffset);
304 }
305
AvoidKeyboardInSheet(const RefPtr<FrameNode> & textField)306 void TextFieldManagerNG::AvoidKeyboardInSheet(const RefPtr<FrameNode>& textField)
307 {
308 CHECK_NULL_VOID(textField);
309 auto parent = textField->GetAncestorNodeOfFrame();
310 bool findSheet = false;
311 while (parent) {
312 if (parent->GetHostTag() == V2::SHEET_PAGE_TAG) {
313 findSheet = true;
314 break;
315 }
316 parent = parent->GetAncestorNodeOfFrame();
317 }
318 CHECK_NULL_VOID(parent);
319 auto sheetNodePattern = parent->GetPattern<SheetPresentationPattern>();
320 CHECK_NULL_VOID(sheetNodePattern);
321 TAG_LOGI(ACE_KEYBOARD, "Force AvoidKeyboard in sheet");
322 sheetNodePattern->AvoidSafeArea(true);
323 }
324
FindNavNode(const RefPtr<FrameNode> & textField)325 RefPtr<FrameNode> TextFieldManagerNG::FindNavNode(const RefPtr<FrameNode>& textField)
326 {
327 CHECK_NULL_RETURN(textField, nullptr);
328 auto parent = textField->GetAncestorNodeOfFrame();
329 RefPtr<FrameNode> ret = nullptr;
330 while (parent) {
331 // when the sheet showed in navdestination, sheet replaced navdestination to do avoid keyboard.
332 if (parent->GetHostTag() == V2::SHEET_WRAPPER_TAG) {
333 auto sheetNode = parent->GetChildAtIndex(0);
334 CHECK_NULL_RETURN(sheetNode, nullptr);
335 return AceType::DynamicCast<FrameNode>(sheetNode);
336 }
337 if (parent->GetHostTag() == V2::NAVDESTINATION_VIEW_ETS_TAG ||
338 parent->GetHostTag() == V2::NAVBAR_ETS_TAG) {
339 ret = parent;
340 break;
341 }
342 parent = parent->GetAncestorNodeOfFrame();
343 }
344 CHECK_NULL_RETURN(ret, nullptr);
345
346 // return navdestination or navBar if the closest ancestor navigation can expandKeyboard
347 // if can't, recursively find the ancestor navigation can expandKeyboard.
348 auto navigationNode = ret->GetAncestorNodeOfFrame();
349 while (navigationNode) {
350 if (navigationNode->GetHostTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
351 break;
352 }
353 navigationNode = navigationNode->GetAncestorNodeOfFrame();
354 }
355 CHECK_NULL_RETURN(navigationNode, nullptr);
356 auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
357 CHECK_NULL_RETURN(layoutProperty, nullptr);
358 auto& opts = layoutProperty->GetSafeAreaExpandOpts();
359
360 // if the extended keyboard area is set for the navigation, top navdestination or navbar need to avoid keyboard,
361 // otherwise don't aovid, following parent navigation.
362 bool isExpandKeyboard = opts && (opts->type & SAFE_AREA_TYPE_KEYBOARD) && (opts->edges & SAFE_AREA_EDGE_BOTTOM);
363 if (isExpandKeyboard) {
364 return ret;
365 }
366 auto mayAvoidNavContentNode = FindNavNode(navigationNode);
367 if (mayAvoidNavContentNode) {
368 return mayAvoidNavContentNode;
369 }
370 SetNavContentAvoidKeyboardOffset(ret, 0.0f);
371 return nullptr;
372 }
373
SetNavContentAvoidKeyboardOffset(RefPtr<FrameNode> navNode,float avoidKeyboardOffset)374 void TextFieldManagerNG::SetNavContentAvoidKeyboardOffset(RefPtr<FrameNode> navNode, float avoidKeyboardOffset)
375 {
376 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(navNode);
377 if (navDestinationNode) {
378 TAG_LOGI(ACE_KEYBOARD, "navNode id:%{public}d, avoidKeyboardOffset:%{public}f", navNode->GetId(),
379 avoidKeyboardOffset);
380 auto pattern = navDestinationNode->GetPattern<NavDestinationPattern>();
381 if (pattern) {
382 avoidKeyboardOffset = pattern->NeedIgnoreKeyboard() ? 0.0f : avoidKeyboardOffset;
383 pattern->SetAvoidKeyboardOffset(avoidKeyboardOffset);
384 }
385 }
386 auto navBarNode = AceType::DynamicCast<NavBarNode>(navNode);
387 if (navBarNode) {
388 auto pattern = navBarNode->GetPattern<NavBarPattern>();
389 if (pattern) {
390 pattern->SetAvoidKeyboardOffset(avoidKeyboardOffset);
391 }
392 }
393 navNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
394 }
395
AddTextFieldInfo(const TextFieldInfo & textFieldInfo)396 void TextFieldManagerNG::AddTextFieldInfo(const TextFieldInfo& textFieldInfo)
397 {
398 if (textFieldInfo.nodeId == -1 || textFieldInfo.autoFillContainerNodeId == -1) {
399 return;
400 }
401
402 auto containerNodeIter = textFieldInfoMap_.find(textFieldInfo.autoFillContainerNodeId);
403 if (containerNodeIter != textFieldInfoMap_.end()) {
404 auto& innerTextFieldMap = containerNodeIter->second;
405 innerTextFieldMap[textFieldInfo.nodeId] = textFieldInfo;
406 } else {
407 std::unordered_map<int32_t, TextFieldInfo> innerTextFieldInfoMap;
408 innerTextFieldInfoMap[textFieldInfo.nodeId] = textFieldInfo;
409 textFieldInfoMap_[textFieldInfo.autoFillContainerNodeId] = innerTextFieldInfoMap;
410 }
411 }
412
RemoveTextFieldInfo(const int32_t & autoFillContainerNodeId,const int32_t & nodeId)413 void TextFieldManagerNG::RemoveTextFieldInfo(const int32_t& autoFillContainerNodeId, const int32_t& nodeId)
414 {
415 auto containerNodeIter = textFieldInfoMap_.find(autoFillContainerNodeId);
416 if (containerNodeIter != textFieldInfoMap_.end()) {
417 auto& innerTextFieldInfoMap = containerNodeIter->second;
418 auto textFieldNodeIter = innerTextFieldInfoMap.find(nodeId);
419 if (textFieldNodeIter != innerTextFieldInfoMap.end()) {
420 innerTextFieldInfoMap.erase(textFieldNodeIter);
421 }
422 }
423 }
424
UpdateTextFieldInfo(const TextFieldInfo & textFieldInfo)425 void TextFieldManagerNG::UpdateTextFieldInfo(const TextFieldInfo& textFieldInfo)
426 {
427 if (textFieldInfo.nodeId == -1 || textFieldInfo.autoFillContainerNodeId == -1) {
428 return;
429 }
430 auto containerNodeIter = textFieldInfoMap_.find(textFieldInfo.autoFillContainerNodeId);
431 if (containerNodeIter != textFieldInfoMap_.end()) {
432 auto& innerTextFieldInfoMap = containerNodeIter->second;
433 auto textFieldNodeIter = innerTextFieldInfoMap.find(textFieldInfo.nodeId);
434 if (textFieldNodeIter != innerTextFieldInfoMap.end()) {
435 innerTextFieldInfoMap.erase(textFieldNodeIter);
436 }
437 innerTextFieldInfoMap[textFieldInfo.nodeId] = textFieldInfo;
438 } else {
439 AddTextFieldInfo(textFieldInfo);
440 }
441 }
442
HasAutoFillPasswordNodeInContainer(const int32_t & autoFillContainerNodeId,const int32_t & nodeId)443 bool TextFieldManagerNG::HasAutoFillPasswordNodeInContainer(
444 const int32_t& autoFillContainerNodeId, const int32_t& nodeId)
445 {
446 auto containerNodeIter = textFieldInfoMap_.find(autoFillContainerNodeId);
447 if (containerNodeIter == textFieldInfoMap_.end()) {
448 return false;
449 }
450
451 auto& innerTextFieldInfoMap = containerNodeIter->second;
452 auto textFieldNodeIter = innerTextFieldInfoMap.find(nodeId);
453 if (textFieldNodeIter == innerTextFieldInfoMap.end()) {
454 return false;
455 }
456
457 for (const auto& textField : innerTextFieldInfoMap) {
458 auto textFieldId = textField.first;
459 auto textFieldInfo = textField.second;
460 if (textFieldId == nodeId) {
461 continue;
462 }
463
464 auto isPasswordType = IsAutoFillPasswordType(textFieldInfo);
465 if (isPasswordType && textFieldInfo.enableAutoFill) {
466 return true;
467 }
468 }
469
470 return false;
471 }
472
IsAutoFillPasswordType(const TextFieldInfo & textFieldInfo)473 bool TextFieldManagerNG::IsAutoFillPasswordType(const TextFieldInfo& textFieldInfo)
474 {
475 return textFieldInfo.inputType == TextInputType::VISIBLE_PASSWORD ||
476 textFieldInfo.inputType == TextInputType::NEW_PASSWORD ||
477 textFieldInfo.inputType == TextInputType::NUMBER_PASSWORD ||
478 textFieldInfo.contentType == TextContentType::VISIBLE_PASSWORD ||
479 textFieldInfo.contentType == TextContentType::NEW_PASSWORD;
480 }
481
~TextFieldManagerNG()482 TextFieldManagerNG::~TextFieldManagerNG()
483 {
484 textFieldInfoMap_.clear();
485 }
486 } // namespace OHOS::Ace::NG
487