• 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_picker/textpicker_column_pattern.h"
17 
18 #include <cstdint>
19 #include <cstdlib>
20 
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/utils/measure_util.h"
24 #include "base/utils/utils.h"
25 #include "bridge/common/utils/utils.h"
26 #include "core/common/container.h"
27 #include "core/common/font_manager.h"
28 #include "core/components/picker/picker_theme.h"
29 #include "core/components_ng/base/frame_scene_status.h"
30 #include "core/components_ng/pattern/image/image_layout_property.h"
31 #include "core/components_ng/pattern/image/image_pattern.h"
32 #include "core/components_ng/pattern/text/text_pattern.h"
33 #include "core/components_ng/pattern/text_picker/textpicker_event_hub.h"
34 #include "core/components_ng/pattern/text_picker/textpicker_layout_property.h"
35 #include "core/components_ng/pattern/text_picker/textpicker_pattern.h"
36 #include "core/components_ng/pattern/text_picker/toss_animation_controller.h"
37 #include "core/pipeline_ng/ui_task_scheduler.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 const Dimension FONT_SIZE = Dimension(2.0);
42 const Dimension FOCUS_SIZE = Dimension(1.0);
43 const float MOVE_DISTANCE = 5.0f;
44 const double MOVE_THRESHOLD = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? 2.0 : 1.0;
45 constexpr float FONTWEIGHT = 0.5f;
46 constexpr float FONT_SIZE_PERCENT = 1.0f;
47 constexpr int32_t HOVER_ANIMATION_DURATION = 40;
48 constexpr int32_t CLICK_ANIMATION_DURATION = 300;
49 constexpr size_t MIXTURE_CHILD_COUNT = 2;
50 const int32_t OPTION_COUNT_PHONE_LANDSCAPE = 3;
51 const Dimension ICON_SIZE = 24.0_vp;
52 const Dimension ICON_TEXT_SPACE = 8.0_vp;
53 const std::vector<std::string> FONT_FAMILY_DEFAULT = { "sans-serif" };
54 const std::string MEASURE_STRING = "TEST";
55 const int32_t HALF_NUMBER = 2;
56 const int32_t BUFFER_NODE_NUMBER = 2;
57 const double CURVE_MOVE_THRESHOLD = 0.5;
58 constexpr char PICKER_DRAG_SCENE[] = "picker_drag_scene";
59 } // namespace
60 
OnAttachToFrameNode()61 void TextPickerColumnPattern::OnAttachToFrameNode()
62 {
63     auto host = GetHost();
64     CHECK_NULL_VOID(host);
65 
66     auto context = host->GetContextRefPtr();
67     CHECK_NULL_VOID(context);
68     auto pickerTheme = context->GetTheme<PickerTheme>();
69     CHECK_NULL_VOID(pickerTheme);
70     auto hub = host->GetEventHub<EventHub>();
71     CHECK_NULL_VOID(hub);
72     auto gestureHub = hub->GetOrCreateGestureEventHub();
73     CHECK_NULL_VOID(gestureHub);
74     tossAnimationController_->SetPipelineContext(context);
75     tossAnimationController_->SetColumn(AceType::WeakClaim(this));
76     overscroller_.SetColumn(AceType::WeakClaim(this));
77     jumpInterval_ = pickerTheme->GetJumpInterval().ConvertToPx();
78     CreateAnimation();
79     InitPanEvent(gestureHub);
80     host->GetRenderContext()->SetClipToFrame(true);
81 }
82 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)83 bool TextPickerColumnPattern::OnDirtyLayoutWrapperSwap(
84     const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
85 {
86     bool isChange =
87         config.frameSizeChange || config.frameOffsetChange || config.contentSizeChange || config.contentOffsetChange;
88 
89     CHECK_NULL_RETURN(isChange, false);
90     CHECK_NULL_RETURN(dirty, false);
91     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
92     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
93     auto layoutAlgorithm = DynamicCast<TextPickerLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
94     CHECK_NULL_RETURN(layoutAlgorithm, false);
95     halfDisplayCounts_ = layoutAlgorithm->GetHalfDisplayCounts();
96     return true;
97 }
98 
OnModifyDone()99 void TextPickerColumnPattern::OnModifyDone()
100 {
101     auto pipeline = PipelineContext::GetCurrentContext();
102     CHECK_NULL_VOID(pipeline);
103     auto theme = pipeline->GetTheme<PickerTheme>();
104     pressColor_ = theme->GetPressColor();
105     hoverColor_ = theme->GetHoverColor();
106     auto showCount = GetShowOptionCount();
107     InitMouseAndPressEvent();
108     SetAccessibilityAction();
109     if (optionProperties_.size() <= 0) {
110         auto midIndex = showCount / HALF_NUMBER;
111         auto host = GetHost();
112         CHECK_NULL_VOID(host);
113         dividerSpacing_ = pipeline->NormalizeToPx(theme->GetDividerSpacing());
114         gradientHeight_ = static_cast<float>(pipeline->NormalizeToPx(theme->GetGradientHeight()));
115         MeasureContext measureContext;
116         measureContext.textContent = MEASURE_STRING;
117         uint32_t childIndex = 0;
118         TextPickerOptionProperty prop;
119         while (childIndex < showCount) {
120             if (childIndex == midIndex) {
121                 auto selectedOptionSize = theme->GetOptionStyle(true, false).GetFontSize();
122                 measureContext.fontSize = selectedOptionSize;
123                 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
124             } else if ((childIndex == (midIndex + 1)) || (childIndex == (midIndex - 1))) {
125                 auto focusOptionSize = theme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
126                 measureContext.fontSize = focusOptionSize;
127                 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
128             } else {
129                 auto normalOptionSize = theme->GetOptionStyle(false, false).GetFontSize();
130                 measureContext.fontSize = normalOptionSize;
131                 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
132             }
133             if (childIndex == midIndex) {
134                 prop.height = dividerSpacing_;
135             } else {
136                 prop.height = gradientHeight_;
137             }
138             Size size = MeasureUtil::MeasureTextSize(measureContext);
139             prop.fontheight = size.Height();
140             optionProperties_.emplace_back(prop);
141             childIndex++;
142         }
143         SetOptionShiftDistance();
144     }
145 }
146 
OnMiddleButtonTouchDown()147 void TextPickerColumnPattern::OnMiddleButtonTouchDown()
148 {
149     PlayPressAnimation(pressColor_);
150 }
151 
OnMiddleButtonTouchMove()152 void TextPickerColumnPattern::OnMiddleButtonTouchMove()
153 {
154     PlayPressAnimation(Color::TRANSPARENT);
155 }
156 
OnMiddleButtonTouchUp()157 void TextPickerColumnPattern::OnMiddleButtonTouchUp()
158 {
159     PlayPressAnimation(Color::TRANSPARENT);
160 }
161 
GetMiddleButtonIndex()162 int32_t TextPickerColumnPattern::GetMiddleButtonIndex()
163 {
164     return GetShowOptionCount() / 2;
165 }
166 
CreateItemTouchEventListener()167 RefPtr<TouchEventImpl> TextPickerColumnPattern::CreateItemTouchEventListener()
168 {
169     auto toss = GetToss();
170     CHECK_NULL_RETURN(toss, nullptr);
171     auto touchCallback = [weak = WeakClaim(this), toss](const TouchEventInfo& info) {
172         auto pattern = weak.Upgrade();
173         CHECK_NULL_VOID(pattern);
174         auto isToss = pattern->GetTossStatus();
175         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
176             if (isToss) {
177                 pattern->touchBreak_ = true;
178                 pattern->animationBreak_ = true;
179                 pattern->clickBreak_ = true;
180                 auto TossEndPosition = toss->GetTossEndPosition();
181                 pattern->SetYLast(TossEndPosition);
182                 toss->StopTossAnimation();
183             } else {
184                 pattern->animationBreak_ = false;
185                 pattern->clickBreak_ = false;
186             }
187         }
188         if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
189             pattern->touchBreak_ = false;
190             if (pattern->animationBreak_) {
191                 pattern->PlayResetAnimation();
192                 pattern->yOffset_ = 0.0;
193             }
194         }
195     };
196     auto listener = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
197     return listener;
198 }
199 
CreateItemClickEventListener(RefPtr<EventParam> param)200 RefPtr<ClickEvent> TextPickerColumnPattern::CreateItemClickEventListener(RefPtr<EventParam> param)
201 {
202     auto clickEventHandler = [param, weak = WeakClaim(this)](const GestureEvent& /* info */) {
203         auto pattern = weak.Upgrade();
204         pattern->OnAroundButtonClick(param);
205     };
206 
207     auto listener = AceType::MakeRefPtr<NG::ClickEvent>(clickEventHandler);
208     return listener;
209 }
210 
CreateMouseHoverEventListener(RefPtr<EventParam> param)211 RefPtr<InputEvent> TextPickerColumnPattern::CreateMouseHoverEventListener(RefPtr<EventParam> param)
212 {
213     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
214         auto pattern = weak.Upgrade();
215         if (pattern) {
216             pattern->HandleMouseEvent(isHover);
217         }
218     };
219     auto hoverEventListener = MakeRefPtr<InputEvent>(std::move(mouseTask));
220     return hoverEventListener;
221 }
222 
ParseTouchListener()223 void TextPickerColumnPattern::ParseTouchListener()
224 {
225     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
226         auto pattern = weak.Upgrade();
227         CHECK_NULL_VOID(pattern);
228         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
229             pattern->SetLocalDownDistance(info.GetTouches().front().GetLocalLocation().GetDistance());
230             pattern->OnMiddleButtonTouchDown();
231             return;
232         }
233         if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
234             pattern->OnMiddleButtonTouchUp();
235             pattern->SetLocalDownDistance(0.0f);
236             return;
237         }
238         if (info.GetTouches().front().GetTouchType() == TouchType::MOVE) {
239             if (std::abs(info.GetTouches().front().GetLocalLocation().GetDistance() - pattern->GetLocalDownDistance()) >
240                 MOVE_DISTANCE) {
241                 pattern->OnMiddleButtonTouchUp();
242             }
243         }
244     };
245     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
246 }
247 
ParseMouseEvent()248 void TextPickerColumnPattern::ParseMouseEvent()
249 {
250     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
251         auto pattern = weak.Upgrade();
252         CHECK_NULL_VOID(pattern);
253         pattern->HandleMouseEvent(isHover);
254     };
255     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
256 }
257 
InitMouseAndPressEvent()258 void TextPickerColumnPattern::InitMouseAndPressEvent()
259 {
260     if (mouseEvent_ || touchListener_) {
261         return;
262     }
263     auto host = GetHost();
264     CHECK_NULL_VOID(host);
265     auto columnEventHub = host->GetEventHub<EventHub>();
266     CHECK_NULL_VOID(columnEventHub);
267     RefPtr<TouchEventImpl> touchListener = CreateItemTouchEventListener();
268     CHECK_NULL_VOID(touchListener);
269     auto columnGesture = columnEventHub->GetOrCreateGestureEventHub();
270     CHECK_NULL_VOID(columnGesture);
271     columnGesture->AddTouchEvent(touchListener);
272     auto childSize = static_cast<int32_t>(host->GetChildren().size());
273     RefPtr<FrameNode> middleChild = nullptr;
274     auto midSize = childSize / 2;
275     middleChild = DynamicCast<FrameNode>(host->GetChildAtIndex(midSize));
276     CHECK_NULL_VOID(middleChild);
277     auto eventHub = middleChild->GetEventHub<EventHub>();
278     CHECK_NULL_VOID(eventHub);
279     auto inputHub = eventHub->GetOrCreateInputEventHub();
280     ParseMouseEvent();
281     inputHub->AddOnHoverEvent(mouseEvent_);
282     auto gesture = middleChild->GetOrCreateGestureEventHub();
283     CHECK_NULL_VOID(gesture);
284     ParseTouchListener();
285     gesture->AddTouchEvent(touchListener_);
286     int32_t i = 0;
287     for (const auto& child : host->GetChildren()) {
288         RefPtr<FrameNode> childNode = DynamicCast<FrameNode>(child);
289         CHECK_NULL_VOID(childNode);
290         RefPtr<EventParam> param = MakeRefPtr<EventParam>();
291         param->instance = childNode;
292         param->itemIndex = i;
293         param->itemTotalCounts = childSize;
294         auto eventHub = childNode->GetEventHub<EventHub>();
295         CHECK_NULL_VOID(eventHub);
296         if (i != midSize) {
297             RefPtr<ClickEvent> clickListener = CreateItemClickEventListener(param);
298             CHECK_NULL_VOID(clickListener);
299             auto gesture = eventHub->GetOrCreateGestureEventHub();
300             CHECK_NULL_VOID(gesture);
301             gesture->AddClickEvent(clickListener);
302         }
303         i++;
304     }
305 }
306 
HandleMouseEvent(bool isHover)307 void TextPickerColumnPattern::HandleMouseEvent(bool isHover)
308 {
309     if (isHover) {
310         PlayPressAnimation(hoverColor_);
311     } else {
312         PlayPressAnimation(Color::TRANSPARENT);
313     }
314     isHover_ = isHover;
315 }
316 
SetButtonBackgroundColor(const Color & pressColor)317 void TextPickerColumnPattern::SetButtonBackgroundColor(const Color& pressColor)
318 {
319     auto host = GetHost();
320     CHECK_NULL_VOID(host);
321     auto blend = host->GetParent();
322     CHECK_NULL_VOID(blend);
323     auto stack = blend->GetParent();
324     CHECK_NULL_VOID(stack);
325     auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
326     auto renderContext = buttonNode->GetRenderContext();
327     renderContext->UpdateBackgroundColor(pressColor);
328     buttonNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
329 }
330 
PlayPressAnimation(const Color & pressColor)331 void TextPickerColumnPattern::PlayPressAnimation(const Color& pressColor)
332 {
333     AnimationOption option = AnimationOption();
334     option.SetDuration(HOVER_ANIMATION_DURATION);
335     option.SetFillMode(FillMode::FORWARDS);
336     AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), pressColor]() {
337         auto picker = weak.Upgrade();
338         if (picker) {
339             picker->SetButtonBackgroundColor(pressColor);
340         }
341     });
342 }
343 
GetShowOptionCount() const344 uint32_t TextPickerColumnPattern::GetShowOptionCount() const
345 {
346     auto context = PipelineContext::GetCurrentContext();
347     CHECK_NULL_RETURN(context, 0);
348     auto pickerTheme = context->GetTheme<PickerTheme>();
349     CHECK_NULL_RETURN(pickerTheme, 0);
350     auto showCount = pickerTheme->GetShowOptionCount() + BUFFER_NODE_NUMBER;
351     return showCount;
352 }
353 
ResetOptionPropertyHeight()354 void TextPickerColumnPattern::ResetOptionPropertyHeight()
355 {
356     if (needOptionPropertyHeightReset_) {
357         auto host = GetHost();
358         CHECK_NULL_VOID(host);
359         auto blendNode = DynamicCast<FrameNode>(host->GetParent());
360         CHECK_NULL_VOID(blendNode);
361         auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
362         CHECK_NULL_VOID(stackNode);
363         auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
364         CHECK_NULL_VOID(parentNode);
365         auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
366         CHECK_NULL_VOID(textPickerLayoutProperty);
367         bool isDefaultPickerItemHeight_ = false;
368         if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
369             auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
370             isDefaultPickerItemHeight_ = LessOrEqual(defaultPickerItemHeightValue.Value(), 0.0) ? false : true;
371         }
372         if (isDefaultPickerItemHeight_) {
373             auto pickerItemHeight = 0.0;
374             auto pattern = parentNode->GetPattern<TextPickerPattern>();
375             CHECK_NULL_VOID(pattern);
376             pickerItemHeight = pattern->GetResizeFlag() ? pattern->GetResizePickerItemHeight()
377                                                         : pattern->GetDefaultPickerItemHeight();
378             int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
379             for (int32_t i = 0; i < itemCounts; i++) {
380                 TextPickerOptionProperty& prop = optionProperties_[i];
381                 prop.height = pickerItemHeight;
382             }
383             SetOptionShiftDistance();
384         }
385         needOptionPropertyHeightReset_ = false;
386     }
387 }
388 
InitTextFontFamily()389 void TextPickerColumnPattern::InitTextFontFamily()
390 {
391     auto host = GetHost();
392     CHECK_NULL_VOID(host);
393     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
394     CHECK_NULL_VOID(blendNode);
395     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
396     CHECK_NULL_VOID(stackNode);
397     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
398     CHECK_NULL_VOID(parentNode);
399     auto pipeline = parentNode->GetContext();
400     CHECK_NULL_VOID(pipeline);
401     auto pattern = parentNode->GetPattern<TextPickerPattern>();
402     CHECK_NULL_VOID(pattern);
403     auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
404     CHECK_NULL_VOID(textPickerLayoutProperty);
405     hasUserDefinedDisappearFontFamily_ = pattern->GetHasUserDefinedDisappearFontFamily();
406     hasUserDefinedNormalFontFamily_ = pattern->GetHasUserDefinedNormalFontFamily();
407     hasUserDefinedSelectedFontFamily_ = pattern->GetHasUserDefinedSelectedFontFamily();
408     auto fontManager = pipeline->GetFontManager();
409     CHECK_NULL_VOID(fontManager);
410     if (!(fontManager->GetAppCustomFont().empty())) {
411         hasAppCustomFont_ = true;
412     }
413     auto appCustomFontFamily = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
414     if (hasAppCustomFont_ && !hasUserDefinedDisappearFontFamily_) {
415         textPickerLayoutProperty->UpdateDisappearFontFamily(appCustomFontFamily);
416     }
417     if (hasAppCustomFont_ && !hasUserDefinedNormalFontFamily_) {
418         textPickerLayoutProperty->UpdateFontFamily(appCustomFontFamily);
419     }
420     if (hasAppCustomFont_ && !hasUserDefinedSelectedFontFamily_) {
421         textPickerLayoutProperty->UpdateSelectedFontFamily(appCustomFontFamily);
422     }
423 }
424 
FlushCurrentOptions(bool isDown,bool isUpateTextContentOnly,bool isDirectlyClear,bool isUpdateAnimationProperties)425 void TextPickerColumnPattern::FlushCurrentOptions(
426     bool isDown, bool isUpateTextContentOnly, bool isDirectlyClear, bool isUpdateAnimationProperties)
427 {
428     ResetOptionPropertyHeight();
429 
430     auto host = GetHost();
431     CHECK_NULL_VOID(host);
432     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
433     CHECK_NULL_VOID(blendNode);
434     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
435     CHECK_NULL_VOID(stackNode);
436     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
437     CHECK_NULL_VOID(parentNode);
438     auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
439     CHECK_NULL_VOID(textPickerLayoutProperty);
440 
441     InitTextFontFamily();
442 
443     if (!isUpateTextContentOnly) {
444         animationProperties_.clear();
445     }
446     if (columnkind_ == TEXT) {
447         FlushCurrentTextOptions(textPickerLayoutProperty, isUpateTextContentOnly, isDirectlyClear);
448     } else if (columnkind_ == ICON) {
449         FlushCurrentImageOptions();
450     } else if (columnkind_ == MIXTURE) {
451         FlushCurrentMixtureOptions(textPickerLayoutProperty, isUpateTextContentOnly);
452     }
453     if (isUpateTextContentOnly && isUpdateAnimationProperties) {
454         FlushAnimationTextProperties(isDown);
455     }
456 }
457 
ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpateTextContentOnly,bool isDirectlyClear)458 void TextPickerColumnPattern::ClearCurrentTextOptions(
459     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpateTextContentOnly, bool isDirectlyClear)
460 {
461     if (isDirectlyClear) {
462         auto host = GetHost();
463         CHECK_NULL_VOID(host);
464         auto child = host->GetChildren();
465         for (auto iter = child.begin(); iter != child.end(); iter++) {
466             auto textNode = DynamicCast<FrameNode>(*iter);
467             CHECK_NULL_VOID(textNode);
468             auto textPattern = textNode->GetPattern<TextPattern>();
469             CHECK_NULL_VOID(textPattern);
470             auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
471             CHECK_NULL_VOID(textLayoutProperty);
472             textLayoutProperty->UpdateContent("");
473             textNode->GetRenderContext()->SetClipToFrame(true);
474             textNode->MarkModifyDone();
475             textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
476         }
477         selectedIndex_ = 0;
478     }
479 }
480 
FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpateTextContentOnly,bool isDirectlyClear)481 void TextPickerColumnPattern::FlushCurrentTextOptions(
482     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpateTextContentOnly, bool isDirectlyClear)
483 {
484     ClearCurrentTextOptions(textPickerLayoutProperty, isUpateTextContentOnly, isDirectlyClear);
485     uint32_t totalOptionCount = GetOptionCount();
486     if (totalOptionCount == 0) {
487         return;
488     }
489     uint32_t currentIndex = GetCurrentIndex();
490     currentIndex = currentIndex % totalOptionCount;
491     uint32_t showCount = GetShowOptionCount();
492     auto middleIndex = showCount / 2; // the center option is selected.
493     auto host = GetHost();
494     CHECK_NULL_VOID(host);
495     auto child = host->GetChildren();
496     auto iter = child.begin();
497     if (child.size() != showCount) {
498         return;
499     }
500     for (uint32_t index = 0; index < showCount; index++) {
501         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
502         RangeContent optionValue = options_[optionIndex];
503         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
504         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
505         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
506         auto textNode = DynamicCast<FrameNode>(*iter);
507         CHECK_NULL_VOID(textNode);
508         auto textPattern = textNode->GetPattern<TextPattern>();
509         CHECK_NULL_VOID(textPattern);
510         auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
511         CHECK_NULL_VOID(textLayoutProperty);
512         if (!isUpateTextContentOnly) {
513             UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
514         }
515         if (NotLoopOptions() && !virtualIndexValidate) {
516             textLayoutProperty->UpdateContent("");
517         } else {
518             textLayoutProperty->UpdateContent(optionValue.text_);
519             textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
520         }
521         UpdateTextAccessibilityProperty(textNode, virtualIndex, iter, virtualIndexValidate);
522         textNode->GetRenderContext()->SetClipToFrame(true);
523         textNode->MarkModifyDone();
524         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
525         iter++;
526     }
527     selectedIndex_ = currentIndex;
528 }
529 
UpdateTextAccessibilityProperty(RefPtr<FrameNode> & textNode,int32_t virtualIndex,std::list<RefPtr<UINode>>::iterator & iter,bool virtualIndexValidate)530 void TextPickerColumnPattern::UpdateTextAccessibilityProperty(RefPtr<FrameNode>& textNode, int32_t virtualIndex,
531     std::list<RefPtr<UINode>>::iterator& iter, bool virtualIndexValidate)
532 {
533     auto accessibilityProperty = textNode->GetAccessibilityProperty<AccessibilityProperty>();
534     CHECK_NULL_VOID(accessibilityProperty);
535     if (!NotLoopOptions() || virtualIndexValidate) {
536         accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::AUTO);
537         return;
538     }
539     accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
540     auto isFocus = accessibilityProperty->GetAccessibilityFocusState();
541     if (virtualIndex == -1 && isFocus) {
542         auto nextTextNode = DynamicCast<FrameNode>(*(++iter));
543         CHECK_NULL_VOID(nextTextNode);
544         nextTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
545         --iter;
546     } else if (virtualIndex == static_cast<int32_t>(GetOptionCount()) && isFocus) {
547         auto preTextNode = DynamicCast<FrameNode>(*(--iter));
548         CHECK_NULL_VOID(preTextNode);
549         preTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
550         ++iter;
551     }
552 }
553 
FlushCurrentImageOptions()554 void TextPickerColumnPattern::FlushCurrentImageOptions()
555 {
556     uint32_t totalOptionCount = GetOptionCount();
557     if (totalOptionCount == 0) {
558         return;
559     }
560     uint32_t currentIndex = GetCurrentIndex();
561     currentIndex = currentIndex % totalOptionCount;
562     uint32_t showCount = GetShowOptionCount();
563     auto middleIndex = showCount / 2; // the center option is selected.
564     auto host = GetHost();
565     CHECK_NULL_VOID(host);
566     auto child = host->GetChildren();
567     auto iter = child.begin();
568     if (child.size() != showCount) {
569         return;
570     }
571     for (uint32_t index = 0; index < showCount; index++) {
572         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
573         RangeContent optionValue = options_[optionIndex];
574         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
575         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
576         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
577         auto rangeNode = DynamicCast<FrameNode>(*iter);
578         CHECK_NULL_VOID(rangeNode);
579         auto iconNode = DynamicCast<FrameNode>(rangeNode->GetFirstChild());
580         CHECK_NULL_VOID(iconNode);
581         auto iconPattern = iconNode->GetPattern<ImagePattern>();
582         CHECK_NULL_VOID(iconPattern);
583         auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
584         CHECK_NULL_VOID(iconLayoutProperty);
585         CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
586         MeasureProperty layoutConstraint;
587         layoutConstraint.selfIdealSize = idealSize;
588         iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
589         if (NotLoopOptions() && !virtualIndexValidate) {
590             iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
591         } else {
592             iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
593             iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
594         }
595         UpdateTextAccessibilityProperty(rangeNode, virtualIndex, iter, virtualIndexValidate);
596         iconNode->MarkModifyDone();
597         iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
598 
599         rangeNode->GetRenderContext()->SetClipToFrame(true);
600         rangeNode->MarkModifyDone();
601         rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
602         iter++;
603     }
604     selectedIndex_ = currentIndex;
605 }
606 
FlushCurrentMixtureOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpateTextContentOnly)607 void TextPickerColumnPattern::FlushCurrentMixtureOptions(
608     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpateTextContentOnly)
609 {
610     uint32_t totalOptionCount = GetOptionCount();
611     if (totalOptionCount == 0) {
612         return;
613     }
614     uint32_t currentIndex = GetCurrentIndex();
615     currentIndex = currentIndex % totalOptionCount;
616     uint32_t showCount = GetShowOptionCount();
617     auto middleIndex = showCount / 2; // the center option is selected.
618     auto host = GetHost();
619     CHECK_NULL_VOID(host);
620     auto child = host->GetChildren();
621     auto iter = child.begin();
622     if (child.size() != showCount) {
623         return;
624     }
625     for (uint32_t index = 0; index < showCount; index++) {
626         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
627         RangeContent optionValue = options_[optionIndex];
628         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
629         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
630         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
631         auto linearLayoutNode = DynamicCast<FrameNode>(*iter);
632         CHECK_NULL_VOID(linearLayoutNode);
633         auto children = linearLayoutNode->GetChildren();
634         if (children.size() != MIXTURE_CHILD_COUNT) {
635             continue;
636         }
637         auto iconNode = DynamicCast<FrameNode>(linearLayoutNode->GetFirstChild());
638         auto iconPattern = iconNode->GetPattern<ImagePattern>();
639         CHECK_NULL_VOID(iconPattern);
640         auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
641         CHECK_NULL_VOID(iconLayoutProperty);
642         auto iconLayoutDirection = iconLayoutProperty->GetNonAutoLayoutDirection();
643         CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
644         MeasureProperty layoutConstraint;
645         layoutConstraint.selfIdealSize = idealSize;
646         iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
647         MarginProperty margin;
648         margin.right = CalcLength(ICON_TEXT_SPACE);
649         bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
650         if (isRtl || iconLayoutDirection == TextDirection::RTL) {
651             margin.left = CalcLength(ICON_TEXT_SPACE);
652         }
653         iconLayoutProperty->UpdateMargin(margin);
654 
655         auto textNode = DynamicCast<FrameNode>(linearLayoutNode->GetLastChild());
656         auto textPattern = textNode->GetPattern<TextPattern>();
657         CHECK_NULL_VOID(textPattern);
658         auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
659         CHECK_NULL_VOID(textLayoutProperty);
660         if (!isUpateTextContentOnly) {
661             UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
662         }
663         if (NotLoopOptions() && !virtualIndexValidate) {
664             iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
665             textLayoutProperty->UpdateContent("");
666         } else {
667             textLayoutProperty->UpdateContent(optionValue.text_);
668             iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
669             iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
670         }
671         UpdateTextAccessibilityProperty(linearLayoutNode, virtualIndex, iter, virtualIndexValidate);
672         iconNode->MarkModifyDone();
673         iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
674         textNode->MarkModifyDone();
675         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
676 
677         linearLayoutNode->GetRenderContext()->SetClipToFrame(true);
678         linearLayoutNode->MarkModifyDone();
679         linearLayoutNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
680         iter++;
681     }
682     selectedIndex_ = currentIndex;
683 }
684 
FlushAnimationTextProperties(bool isDown)685 void TextPickerColumnPattern::FlushAnimationTextProperties(bool isDown)
686 {
687     const size_t size = animationProperties_.size();
688     if (size == 0) {
689         return;
690     }
691     if (isDown) {
692         for (size_t i = 0; i < size; i++) {
693             if (i > 0) {
694                 animationProperties_[i - 1].upFontSize = animationProperties_[i].upFontSize;
695                 animationProperties_[i - 1].fontSize = animationProperties_[i].fontSize;
696                 animationProperties_[i - 1].downFontSize = animationProperties_[i].downFontSize;
697                 animationProperties_[i - 1].upColor = animationProperties_[i].upColor;
698                 animationProperties_[i - 1].currentColor = animationProperties_[i].currentColor;
699                 animationProperties_[i - 1].downColor = animationProperties_[i].downColor;
700             }
701             if (i + 1 == size) {
702                 animationProperties_[i].upFontSize = animationProperties_[i].fontSize;
703                 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
704                 animationProperties_[i].downFontSize = Dimension();
705                 animationProperties_[i].upColor = animationProperties_[i].currentColor;
706                 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
707                 animationProperties_[i].currentColor =
708                     colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
709                 animationProperties_[i].downColor = Color();
710             }
711         }
712     } else {
713         for (size_t i = size - 1;; i--) {
714             if (i == 0) {
715                 animationProperties_[i].upFontSize = Dimension();
716                 animationProperties_[i].downFontSize = animationProperties_[i].fontSize;
717                 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
718                 animationProperties_[i].upColor = Color();
719                 animationProperties_[i].downColor = animationProperties_[i].currentColor;
720                 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
721                 animationProperties_[i].currentColor =
722                     colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
723                 break;
724             } else {
725                 animationProperties_[i].upFontSize = animationProperties_[i - 1].upFontSize;
726                 animationProperties_[i].fontSize = animationProperties_[i - 1].fontSize;
727                 animationProperties_[i].downFontSize = animationProperties_[i - 1].downFontSize;
728                 animationProperties_[i].upColor = animationProperties_[i - 1].upColor;
729                 animationProperties_[i].currentColor = animationProperties_[i - 1].currentColor;
730                 animationProperties_[i].downColor = animationProperties_[i - 1].downColor;
731             }
732         }
733     }
734 }
735 
UpdateDisappearTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)736 void TextPickerColumnPattern::UpdateDisappearTextProperties(const RefPtr<PickerTheme>& pickerTheme,
737     const RefPtr<TextLayoutProperty>& textLayoutProperty,
738     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
739 {
740     auto normalOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize();
741     textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDisappearColor().value_or(
742         pickerTheme->GetOptionStyle(false, false).GetTextColor()));
743     if (textPickerLayoutProperty->HasDisappearFontSize()) {
744         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetDisappearFontSize().value());
745         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
746         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
747     } else {
748         textLayoutProperty->UpdateAdaptMaxFontSize(normalOptionSize);
749         textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(false, false).GetAdaptMinFontSize());
750     }
751     textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetDisappearWeight().value_or(
752         pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
753     auto fontFamilyVector = textPickerLayoutProperty->GetDisappearFontFamily().value_or(
754         pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
755     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
756     textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetDisappearFontStyle().value_or(
757         pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
758 }
759 
UpdateCandidateTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)760 void TextPickerColumnPattern::UpdateCandidateTextProperties(const RefPtr<PickerTheme>& pickerTheme,
761     const RefPtr<TextLayoutProperty>& textLayoutProperty,
762     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
763 {
764     auto focusOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
765     textLayoutProperty->UpdateTextColor(
766         textPickerLayoutProperty->GetColor().value_or(pickerTheme->GetOptionStyle(false, false).GetTextColor()));
767     if (textPickerLayoutProperty->HasFontSize()) {
768         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetFontSize().value());
769         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
770         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
771     } else {
772         textLayoutProperty->UpdateAdaptMaxFontSize(focusOptionSize);
773         textLayoutProperty->UpdateAdaptMinFontSize(
774             pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize() - FOCUS_SIZE);
775     }
776     textLayoutProperty->UpdateFontWeight(
777         textPickerLayoutProperty->GetWeight().value_or(pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
778     auto fontFamilyVector = textPickerLayoutProperty->GetFontFamily().value_or(
779         pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
780     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
781     textLayoutProperty->UpdateItalicFontStyle(
782         textPickerLayoutProperty->GetFontStyle().value_or(pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
783 }
784 
UpdateSelectedTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)785 void TextPickerColumnPattern::UpdateSelectedTextProperties(const RefPtr<PickerTheme>& pickerTheme,
786     const RefPtr<TextLayoutProperty>& textLayoutProperty,
787     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
788 {
789     auto selectedOptionSize = pickerTheme->GetOptionStyle(true, false).GetFontSize();
790     textLayoutProperty->UpdateTextColor(
791         textPickerLayoutProperty->GetSelectedColor().value_or(pickerTheme->GetOptionStyle(true, false).GetTextColor()));
792     if (textPickerLayoutProperty->HasSelectedFontSize()) {
793         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetSelectedFontSize().value());
794         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
795         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
796     } else {
797         textLayoutProperty->UpdateAdaptMaxFontSize(selectedOptionSize);
798         textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize());
799     }
800     textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetSelectedWeight().value_or(
801         pickerTheme->GetOptionStyle(true, false).GetFontWeight()));
802     auto fontFamilyVector = textPickerLayoutProperty->GetSelectedFontFamily().value_or(
803         pickerTheme->GetOptionStyle(true, false).GetFontFamilies());
804     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
805     textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetSelectedFontStyle().value_or(
806         pickerTheme->GetOptionStyle(true, false).GetFontStyle()));
807 }
808 
UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)809 void TextPickerColumnPattern::UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
810     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
811 {
812     CHECK_NULL_VOID(textLayoutProperty);
813     CHECK_NULL_VOID(textPickerLayoutProperty);
814     auto host = GetHost();
815     CHECK_NULL_VOID(host);
816     auto context = host->GetContext();
817     CHECK_NULL_VOID(context);
818     auto theme = context->GetTheme<TextTheme>();
819     CHECK_NULL_VOID(theme);
820     auto textStyle = theme->GetTextStyle();
821     textLayoutProperty->UpdateFontSize(
822         textPickerLayoutProperty->GetDefaultFontSize().value_or(textStyle.GetFontSize()));
823     textLayoutProperty->UpdateFontWeight(
824         textPickerLayoutProperty->GetDefaultWeight().value_or(textStyle.GetFontWeight()));
825     textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDefaultColor().value_or(textStyle.GetTextColor()));
826     textLayoutProperty->UpdateFontFamily(
827         textPickerLayoutProperty->GetDefaultFontFamily().value_or(textStyle.GetFontFamilies()));
828     textLayoutProperty->UpdateItalicFontStyle(
829         textPickerLayoutProperty->GetDefaultFontStyle().value_or(textStyle.GetFontStyle()));
830     textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetDefaultMinFontSize().value_or(Dimension()));
831     textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetDefaultMaxFontSize().value_or(Dimension()));
832     if (textPickerLayoutProperty->GetDefaultTextOverflow().has_value() &&
833         textPickerLayoutProperty->GetDefaultTextOverflow().value() != TextOverflow::MARQUEE) {
834         textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetDefaultTextOverflow().value());
835     } else {
836         textLayoutProperty->UpdateTextOverflow(textStyle.GetTextOverflow());
837     }
838     textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
839     textLayoutProperty->UpdateMaxLines(1);
840 }
841 
AddAnimationTextProperties(uint32_t currentIndex,const RefPtr<TextLayoutProperty> & textLayoutProperty)842 void TextPickerColumnPattern::AddAnimationTextProperties(
843     uint32_t currentIndex, const RefPtr<TextLayoutProperty>& textLayoutProperty)
844 {
845     TextProperties properties{};
846     if (textLayoutProperty->HasFontSize()) {
847         MeasureContext measureContext;
848         measureContext.textContent = MEASURE_STRING;
849         measureContext.fontSize = textLayoutProperty->GetFontSize().value();
850         if (textLayoutProperty->HasFontFamily()) {
851             auto fontFamilyVector = textLayoutProperty->GetFontFamily().value();
852             if (fontFamilyVector.empty()) {
853                 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
854             } else {
855                 measureContext.fontFamily = fontFamilyVector[0];
856             }
857         } else {
858             measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
859         }
860         auto size = MeasureUtil::MeasureTextSize(measureContext);
861         if (!optionProperties_.empty()) {
862             optionProperties_[currentIndex].fontheight = size.Height();
863             if (optionProperties_[currentIndex].fontheight > optionProperties_[currentIndex].height) {
864                 optionProperties_[currentIndex].fontheight = optionProperties_[currentIndex].height;
865             }
866         }
867         SetOptionShiftDistance();
868         properties.fontSize = Dimension(textLayoutProperty->GetFontSize().value().ConvertToPx());
869     }
870     if (textLayoutProperty->HasTextColor()) {
871         properties.currentColor = textLayoutProperty->GetTextColor().value();
872     }
873     if (textLayoutProperty->HasFontWeight()) {
874         properties.fontWeight = textLayoutProperty->GetFontWeight().value();
875     }
876     if (currentIndex > 0) {
877         properties.upFontSize = animationProperties_[currentIndex - 1].fontSize;
878         animationProperties_[currentIndex - 1].downFontSize = properties.fontSize;
879 
880         properties.upColor = animationProperties_[currentIndex - 1].currentColor;
881         animationProperties_[currentIndex - 1].downColor = properties.currentColor;
882 
883         properties.upFontWeight = animationProperties_[currentIndex - 1].fontWeight;
884         animationProperties_[currentIndex - 1].downFontWeight = properties.fontWeight;
885     }
886     animationProperties_.emplace_back(properties);
887 }
888 
UpdatePickerTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,uint32_t currentIndex,uint32_t middleIndex,uint32_t showCount)889 void TextPickerColumnPattern::UpdatePickerTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
890     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex,
891     uint32_t showCount)
892 {
893     if (textPickerLayoutProperty && textPickerLayoutProperty->GetDisableTextStyleAnimation().value_or(false)) {
894         UpdateDefaultTextProperties(textLayoutProperty, textPickerLayoutProperty);
895         return;
896     }
897     auto host = GetHost();
898     CHECK_NULL_VOID(host);
899     auto context = host->GetContext();
900     CHECK_NULL_VOID(context);
901     auto pickerTheme = context->GetTheme<PickerTheme>();
902     CHECK_NULL_VOID(pickerTheme);
903     if (currentIndex == middleIndex) {
904         UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
905         textLayoutProperty->UpdateAlignment(Alignment::CENTER);
906     } else if ((currentIndex == middleIndex + 1) || (currentIndex == middleIndex - 1)) {
907         UpdateCandidateTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
908     } else {
909         UpdateDisappearTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
910     }
911     if (currentIndex < middleIndex) {
912         textLayoutProperty->UpdateAlignment(Alignment::TOP_CENTER);
913     } else if (currentIndex > middleIndex) {
914         textLayoutProperty->UpdateAlignment(Alignment::BOTTOM_CENTER);
915     }
916     textLayoutProperty->UpdateMaxLines(1);
917     textLayoutProperty->UpdateTextOverflow(TextOverflow::CLIP);
918     AddAnimationTextProperties(currentIndex, textLayoutProperty);
919 }
920 
TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty> & textLayoutProperty,uint32_t idx,uint32_t showCount,bool isDown,double scaleSize)921 void TextPickerColumnPattern::TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty>& textLayoutProperty,
922     uint32_t idx, uint32_t showCount, bool isDown, double scaleSize)
923 {
924     uint32_t deltaIdx = static_cast<uint32_t>(GetOverScrollDeltaIndex());
925     auto index = idx;
926     if (GreatNotEqual(scrollDelta_, 0.0f)) {
927         index = index + deltaIdx;
928     } else {
929         if (index < deltaIdx) {
930             return;
931         }
932         index = index - deltaIdx;
933     }
934 
935     auto percent = distancePercent_ - deltaIdx;
936     auto scale = scaleSize - deltaIdx;
937 
938     if (index >= animationProperties_.size()) {
939         return;
940     }
941     Dimension startFontSize = animationProperties_[index].fontSize;
942     Color startColor = animationProperties_[index].currentColor;
943     if ((!index && isDown) || ((index == (showCount - 1)) && !isDown)) {
944         textLayoutProperty->UpdateFontSize(startFontSize);
945         textLayoutProperty->UpdateTextColor(startColor);
946         return;
947     }
948     Dimension endFontSize;
949     Color endColor;
950     if (GreatNotEqual(scrollDelta_, 0.0)) {
951         endFontSize = animationProperties_[index].downFontSize;
952         endColor = animationProperties_[index].downColor;
953         if (GreatOrEqual(scale, FONTWEIGHT)) {
954             textLayoutProperty->UpdateFontWeight(animationProperties_[index].downFontWeight);
955         }
956     } else {
957         endFontSize = animationProperties_[index].upFontSize;
958         endColor = animationProperties_[index].upColor;
959         if (GreatOrEqual(scale, FONTWEIGHT)) {
960             textLayoutProperty->UpdateFontWeight(animationProperties_[index].upFontWeight);
961         }
962     }
963     Dimension updateSize = LinearFontSize(startFontSize, endFontSize, percent);
964     textLayoutProperty->UpdateFontSize(updateSize);
965     auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
966     Color updateColor = colorEvaluator->Evaluate(startColor, endColor, std::abs(percent));
967     textLayoutProperty->UpdateTextColor(updateColor);
968     if (scale < FONTWEIGHT) {
969         textLayoutProperty->UpdateFontWeight(animationProperties_[index].fontWeight);
970     }
971 }
972 
GetOverScrollDeltaIndex() const973 int32_t TextPickerColumnPattern::GetOverScrollDeltaIndex() const
974 {
975     auto deltaIdx = 0;
976     if (NotLoopOptions() && overscroller_.IsOverScroll()) {
977         auto midIndex = GetShowOptionCount() / HALF_NUMBER;
978         auto shiftDistance = optionProperties_[midIndex].nextDistance;
979         for (auto idx = midIndex; idx < GetShowOptionCount(); idx++) {
980             if (shiftDistance > std::abs(scrollDelta_)) {
981                 break;
982             }
983             shiftDistance += optionProperties_[idx].nextDistance;
984             deltaIdx++;
985         }
986     }
987     return deltaIdx;
988 }
989 
UpdateTextPropertiesLinear(bool isDown,double scale)990 void TextPickerColumnPattern::UpdateTextPropertiesLinear(bool isDown, double scale)
991 {
992     if (columnkind_ == ICON) {
993         return;
994     }
995     auto host = GetHost();
996     CHECK_NULL_VOID(host);
997     uint32_t showCount = GetShowOptionCount();
998     auto child = host->GetChildren();
999     auto iter = child.begin();
1000     if (child.size() != showCount) {
1001         return;
1002     }
1003     for (uint32_t index = 0; index < showCount; index++) {
1004         auto rangeNode = DynamicCast<FrameNode>(*iter);
1005         CHECK_NULL_VOID(rangeNode);
1006         RefPtr<TextLayoutProperty> textLayoutProperty;
1007         if (columnkind_ == TEXT) {
1008             auto textPattern = rangeNode->GetPattern<TextPattern>();
1009             CHECK_NULL_VOID(textPattern);
1010             textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1011             CHECK_NULL_VOID(textLayoutProperty);
1012             TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1013         } else if (columnkind_ == MIXTURE) {
1014             auto children = rangeNode->GetChildren();
1015             if (children.size() != MIXTURE_CHILD_COUNT) {
1016                 continue;
1017             }
1018             auto textNode = DynamicCast<FrameNode>(rangeNode->GetLastChild());
1019             auto textPattern = textNode->GetPattern<TextPattern>();
1020             textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1021             CHECK_NULL_VOID(textLayoutProperty);
1022             TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1023             textNode->MarkModifyDone();
1024             textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1025         }
1026         rangeNode->MarkModifyDone();
1027         rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1028         iter++;
1029     }
1030 }
1031 
LinearFontSize(const Dimension & startFontSize,const Dimension & endFontSize,double percent)1032 Dimension TextPickerColumnPattern::LinearFontSize(
1033     const Dimension& startFontSize, const Dimension& endFontSize, double percent)
1034 {
1035     if (percent > FONT_SIZE_PERCENT) {
1036         return startFontSize + (endFontSize - startFontSize);
1037     } else {
1038         return startFontSize + (endFontSize - startFontSize) * std::abs(percent);
1039     }
1040 }
1041 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1042 void TextPickerColumnPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1043 {
1044     CHECK_NULL_VOID(!panEvent_);
1045     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1046         auto pattern = weak.Upgrade();
1047         CHECK_NULL_VOID(pattern);
1048         if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1049             return;
1050         }
1051         pattern->HandleDragStart(event);
1052     };
1053     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1054         auto pattern = weak.Upgrade();
1055         CHECK_NULL_VOID(pattern);
1056         pattern->SetMainVelocity(event.GetMainVelocity());
1057         pattern->HandleDragMove(event);
1058     };
1059     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1060         auto pattern = weak.Upgrade();
1061         CHECK_NULL_VOID(pattern);
1062         if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1063             return;
1064         }
1065         pattern->SetMainVelocity(info.GetMainVelocity());
1066         pattern->HandleDragEnd();
1067     };
1068     auto actionCancelTask = [weak = WeakClaim(this)]() {
1069         auto pattern = weak.Upgrade();
1070         CHECK_NULL_VOID(pattern);
1071         pattern->HandleDragEnd();
1072     };
1073     PanDirection panDirection;
1074     panDirection.type = PanDirection::VERTICAL;
1075     panEvent_ = MakeRefPtr<PanEvent>(
1076         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1077     gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
1078 }
1079 
GetParentLayout() const1080 RefPtr<TextPickerLayoutProperty> TextPickerColumnPattern::GetParentLayout() const
1081 {
1082     auto host = GetHost();
1083     CHECK_NULL_RETURN(host, nullptr);
1084     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
1085     CHECK_NULL_RETURN(blendNode, nullptr);
1086     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
1087     CHECK_NULL_RETURN(stackNode, nullptr);
1088     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
1089     CHECK_NULL_RETURN(parentNode, nullptr);
1090 
1091     auto property = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
1092     return property;
1093 }
1094 
HandleDragStart(const GestureEvent & event)1095 void TextPickerColumnPattern::HandleDragStart(const GestureEvent& event)
1096 {
1097     CHECK_NULL_VOID(GetToss());
1098     auto toss = GetToss();
1099     auto offsetY = event.GetGlobalPoint().GetY();
1100     toss->SetStart(offsetY);
1101     yLast_ = offsetY;
1102     overscroller_.SetStart(offsetY);
1103     pressed_ = true;
1104     auto frameNode = GetHost();
1105     CHECK_NULL_VOID(frameNode);
1106     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::START);
1107     // AccessibilityEventType::SCROLL_START
1108 
1109     if (animation_) {
1110         AnimationUtils::StopAnimation(animation_);
1111     }
1112 
1113     if (NotLoopOptions() && reboundAnimation_) {
1114         AnimationUtils::StopAnimation(reboundAnimation_);
1115         isReboundInProgress_ = false;
1116         overscroller_.ResetVelocity();
1117         overscroller_.SetOverScroll(scrollDelta_);
1118     }
1119 }
1120 
HandleDragMove(const GestureEvent & event)1121 void TextPickerColumnPattern::HandleDragMove(const GestureEvent& event)
1122 {
1123     if (event.GetFingerList().size() > 1) {
1124         return;
1125     }
1126     if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1127         if (InnerHandleScroll(LessNotEqual(event.GetDelta().GetY(), 0.0), true)) {
1128             HandleScrollStopEventCallback(true);
1129         }
1130         return;
1131     }
1132     animationBreak_ = false;
1133     CHECK_NULL_VOID(pressed_);
1134     CHECK_NULL_VOID(GetHost());
1135     CHECK_NULL_VOID(GetToss());
1136     auto toss = GetToss();
1137     auto offsetY =
1138         event.GetGlobalPoint().GetY() + (event.GetInputEventType() == InputEventType::AXIS ? event.GetOffsetY() : 0.0);
1139     if (NearEqual(offsetY, yLast_, MOVE_THRESHOLD)) { // if changing less than MOVE_THRESHOLD, no need to handle
1140         return;
1141     }
1142     toss->SetEnd(offsetY);
1143     UpdateColumnChildPosition(offsetY);
1144     auto frameNode = GetHost();
1145     CHECK_NULL_VOID(frameNode);
1146     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::RUNNING);
1147 }
1148 
HandleDragEnd()1149 void TextPickerColumnPattern::HandleDragEnd()
1150 {
1151     pressed_ = false;
1152     CHECK_NULL_VOID(GetToss());
1153     auto toss = GetToss();
1154     auto frameNode = GetHost();
1155     CHECK_NULL_VOID(frameNode);
1156     if (NotLoopOptions()) {
1157         frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1158         if (overscroller_.IsOverScroll()) { // Start rebound animation. Higher priority than fling
1159             CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
1160             HandleScrollStopEventCallback(true);
1161             return;
1162         }
1163     }
1164     if (toss->Play()) { // Start fling animation
1165         frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1166         // AccessibilityEventType::SCROLL_END
1167         return;
1168     }
1169     yOffset_ = 0.0;
1170     yLast_ = 0.0;
1171     if (!animationCreated_) {
1172         ScrollOption(0.0);
1173         return;
1174     }
1175     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
1176     ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1177     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
1178                                                       : optionProperties_[middleIndex].nextDistance;
1179     auto shiftThreshold = shiftDistance / HALF_NUMBER;
1180     if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
1181         InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
1182         scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
1183         if (NearZero(scrollDelta_)) {
1184             HandleScrollStopEventCallback(true);
1185         }
1186     }
1187     CreateAnimation(scrollDelta_, 0.0);
1188     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1189     if (!NearZero(scrollDelta_)) {
1190         HandleScrollStopEventCallback(true);
1191     }
1192     // AccessibilityEventType::SCROLL_END
1193 }
1194 
CreateAnimation()1195 void TextPickerColumnPattern::CreateAnimation()
1196 {
1197     CHECK_NULL_VOID(!animationCreated_);
1198     auto host = GetHost();
1199     CHECK_NULL_VOID(host);
1200     auto renderContext = host->GetRenderContext();
1201     CHECK_NULL_VOID(renderContext);
1202     auto propertyCallback = [weak = AceType::WeakClaim(this)](float value) {
1203         auto column = weak.Upgrade();
1204         CHECK_NULL_VOID(column);
1205         column->ScrollOption(value);
1206     };
1207     scrollProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
1208     renderContext->AttachNodeAnimatableProperty(scrollProperty_);
1209 
1210     auto aroundClickCallback = [weak = AceType::WeakClaim(this)](float value) {
1211         auto column = weak.Upgrade();
1212         CHECK_NULL_VOID(column);
1213         column->UpdateColumnChildPosition(value);
1214     };
1215     aroundClickProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(aroundClickCallback));
1216     renderContext->AttachNodeAnimatableProperty(aroundClickProperty_);
1217     animationCreated_ = true;
1218 }
1219 
CreateAnimation(double from,double to)1220 void TextPickerColumnPattern::CreateAnimation(double from, double to)
1221 {
1222     AnimationOption option;
1223     option.SetCurve(Curves::FAST_OUT_SLOW_IN);
1224     option.SetDuration(CLICK_ANIMATION_DURATION);
1225     scrollProperty_->Set(from);
1226     AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), to]() {
1227         auto column = weak.Upgrade();
1228         CHECK_NULL_VOID(column);
1229         column->scrollProperty_->Set(to);
1230     });
1231 }
1232 
CreateReboundAnimation(double from,double to)1233 void TextPickerColumnPattern::CreateReboundAnimation(double from, double to)
1234 {
1235     isReboundInProgress_ = true;
1236     AnimationOption option;
1237     option.SetCurve(overscroller_.GetReboundCurve());
1238     option.SetDuration(CLICK_ANIMATION_DURATION);
1239     scrollProperty_->Set(from);
1240     reboundAnimation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), to]() {
1241         auto column = weak.Upgrade();
1242         CHECK_NULL_VOID(column);
1243         column->scrollProperty_->Set(to);
1244     }, [weak = AceType::WeakClaim(this)]() { // On Finish
1245         auto column = weak.Upgrade();
1246         CHECK_NULL_VOID(column);
1247         if (column->isReboundInProgress_) {
1248             column->isReboundInProgress_ = false;
1249             column->overscroller_.Reset();
1250             column->yLast_ = 0.0;
1251             column->yOffset_ = 0.0;
1252         }
1253     });
1254 }
1255 
ScrollOption(double delta)1256 void TextPickerColumnPattern::ScrollOption(double delta)
1257 {
1258     scrollDelta_ = delta;
1259     auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1260     ScrollDirection dir = GreatNotEqual(delta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1261     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1262                                                       : optionProperties_[midIndex].nextDistance;
1263     distancePercent_ = delta / shiftDistance;
1264     auto textLinearPercent = 0.0;
1265     textLinearPercent = (std::abs(delta)) / (optionProperties_[midIndex].height);
1266     UpdateTextPropertiesLinear(LessNotEqual(delta, 0.0), textLinearPercent);
1267     CalcAlgorithmOffset(dir, distancePercent_);
1268     auto host = GetHost();
1269     CHECK_NULL_VOID(host);
1270     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1271 }
1272 
ResetAlgorithmOffset()1273 void TextPickerColumnPattern::ResetAlgorithmOffset()
1274 {
1275     algorithmOffset_.clear();
1276 
1277     uint32_t counts = GetShowOptionCount();
1278     for (uint32_t i = 0; i < counts; i++) {
1279         algorithmOffset_.emplace_back(0.0);
1280     }
1281 }
1282 
UpdateScrollDelta(double delta)1283 void TextPickerColumnPattern::UpdateScrollDelta(double delta)
1284 {
1285     SetCurrentOffset(delta);
1286     auto host = GetHost();
1287     CHECK_NULL_VOID(host);
1288     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1289 }
1290 
CalcAlgorithmOffset(ScrollDirection dir,double distancePercent)1291 void TextPickerColumnPattern::CalcAlgorithmOffset(ScrollDirection dir, double distancePercent)
1292 {
1293     algorithmOffset_.clear();
1294 
1295     uint32_t counts = GetShowOptionCount();
1296 
1297     for (uint32_t i = 0; i < counts; i++) {
1298         auto distance = (dir == ScrollDirection::UP) ? optionProperties_[i].prevDistance
1299                                                      : optionProperties_[i].nextDistance;
1300         auto val  = std::trunc(distance * distancePercent);
1301         algorithmOffset_.emplace_back(static_cast<int32_t>(val));
1302     }
1303 }
1304 
GetShiftDistance(int32_t index,ScrollDirection dir)1305 double TextPickerColumnPattern::GetShiftDistance(int32_t index, ScrollDirection dir)
1306 {
1307     if (optionProperties_.empty()) {
1308         return 0.0;
1309     }
1310     int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1311     if (optionCounts == 0) {
1312         return 0.0;
1313     }
1314     int32_t nextIndex = 0;
1315     auto isDown = dir == ScrollDirection::DOWN;
1316     nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1317     double distance = 0.0;
1318     switch (static_cast<OptionIndex>(index)) {
1319         case OptionIndex::COLUMN_INDEX_0: // first
1320             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1321                                                       : (0.0 - optionProperties_[index].height);
1322             break;
1323         case OptionIndex::COLUMN_INDEX_1:
1324             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1325                                                       : (0.0 - optionProperties_[nextIndex].height);
1326             break;
1327         case OptionIndex::COLUMN_INDEX_2:
1328             distance = GetUpCandidateDistance(index, nextIndex, dir);
1329             break;
1330 
1331         case OptionIndex::COLUMN_INDEX_3:
1332             distance = GetSelectedDistance(index, nextIndex, dir);
1333             break;
1334 
1335         case OptionIndex::COLUMN_INDEX_4:
1336             distance = GetDownCandidateDistance(index, nextIndex, dir);
1337             break;
1338         case OptionIndex::COLUMN_INDEX_5:
1339             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1340                                                       : (0.0 - optionProperties_[nextIndex].height);
1341             break;
1342         case OptionIndex::COLUMN_INDEX_6: // last
1343             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1344                                                       : (0.0 - optionProperties_[nextIndex].height);
1345             break;
1346         default:
1347             break;
1348     }
1349 
1350     return distance;
1351 }
1352 
GetSelectedDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1353 double TextPickerColumnPattern::GetSelectedDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1354 {
1355     double distance = 0.0;
1356     double val = 0.0;
1357     if (columnkind_ == TEXT) {
1358         if (GreatOrEqual(optionProperties_[nextIndex].fontheight, optionProperties_[nextIndex].height)) {
1359             distance = (dir == ScrollDirection::UP) ?
1360                 - optionProperties_[nextIndex].height : optionProperties_[index].height;
1361         } else {
1362             val = optionProperties_[index].height / HALF_NUMBER + optionProperties_[nextIndex].height -
1363                   optionProperties_[nextIndex].fontheight / HALF_NUMBER;
1364             val = std::round(val);
1365             distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1366         }
1367     } else {
1368         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1369         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1370     }
1371     return distance;
1372 }
1373 
GetUpCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1374 double TextPickerColumnPattern::GetUpCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1375 {
1376     double distance = 0.0;
1377     double val = 0.0;
1378     // the index of last element in optionProperties_. return -1 while the arraySize equals 0.
1379     auto maxIndex = static_cast<int32_t>(optionProperties_.size()) - 1;
1380     auto minIndex = 0;
1381     if (index > maxIndex || index < minIndex || nextIndex > maxIndex || nextIndex < minIndex) {
1382         return distance;
1383     }
1384     if (columnkind_ == TEXT) {
1385         if (dir == ScrollDirection::UP) {
1386             distance = -optionProperties_[nextIndex].height;
1387         } else {
1388             val = optionProperties_[index].height +
1389                   (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1390             distance = std::round(val);
1391         }
1392     } else {
1393         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1394         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1395     }
1396     return distance;
1397 }
1398 
GetDownCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1399 double TextPickerColumnPattern::GetDownCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1400 {
1401     double distance = 0.0;
1402     double val = 0.0;
1403     if (columnkind_ == TEXT) {
1404         if (dir == ScrollDirection::DOWN) {
1405             distance = optionProperties_[index].height;
1406         } else {
1407             val = optionProperties_[index].height +
1408                   (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1409             if (GreatNotEqual(optionProperties_[nextIndex].fontheight, optionProperties_[index].height)) {
1410                 val = val + (optionProperties_[nextIndex].fontheight - optionProperties_[index].height);
1411             }
1412             distance = - std::round(val);
1413         }
1414     } else {
1415         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1416         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1417     }
1418     return distance;
1419 }
1420 
GetShiftDistanceForLandscape(int32_t index,ScrollDirection dir)1421 double TextPickerColumnPattern::GetShiftDistanceForLandscape(int32_t index, ScrollDirection dir)
1422 {
1423     int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1424     if (optionCounts == 0) {
1425         return 0.0;
1426     }
1427     int32_t nextIndex = 0;
1428     auto isDown = dir == ScrollDirection::DOWN;
1429     nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1430     double distance = 0.0;
1431     switch (static_cast<OptionIndex>(index)) {
1432         case OptionIndex::COLUMN_INDEX_0:
1433             distance = GetUpCandidateDistance(index, nextIndex, dir);
1434             break;
1435 
1436         case OptionIndex::COLUMN_INDEX_1:
1437             distance = GetSelectedDistance(index, nextIndex, dir);
1438             break;
1439 
1440         case OptionIndex::COLUMN_INDEX_2:
1441             distance = GetDownCandidateDistance(index, nextIndex, dir);
1442             break;
1443         default:
1444             break;
1445     }
1446 
1447     return distance;
1448 }
1449 
SetOptionShiftDistance()1450 void TextPickerColumnPattern::SetOptionShiftDistance()
1451 {
1452     CHECK_EQUAL_VOID(optionProperties_.empty(), true);
1453     int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
1454     bool isLanscape = (itemCounts == OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER);
1455     for (int32_t i = 0; i < static_cast<int32_t>(itemCounts); i++) {
1456         TextPickerOptionProperty& prop = optionProperties_[i];
1457         if (isLanscape) {
1458             prop.prevDistance = GetShiftDistanceForLandscape(i, ScrollDirection::UP);
1459             prop.nextDistance = GetShiftDistanceForLandscape(i, ScrollDirection::DOWN);
1460         } else {
1461             prop.prevDistance = GetShiftDistance(i, ScrollDirection::UP);
1462             prop.nextDistance = GetShiftDistance(i, ScrollDirection::DOWN);
1463         }
1464     }
1465 }
1466 
UpdateToss(double offsetY)1467 void TextPickerColumnPattern::UpdateToss(double offsetY)
1468 {
1469     UpdateColumnChildPosition(offsetY);
1470 }
1471 
TossStoped()1472 void TextPickerColumnPattern::TossStoped()
1473 {
1474     yOffset_ = 0.0;
1475     yLast_ = 0.0;
1476     ScrollOption(0.0);
1477 }
1478 
TossAnimationStoped()1479 void TextPickerColumnPattern::TossAnimationStoped()
1480 {
1481     yLast_ = 0.0;
1482 }
1483 
GetSelectedObject(bool isColumnChange,int32_t status) const1484 std::string TextPickerColumnPattern::GetSelectedObject(bool isColumnChange, int32_t status) const
1485 {
1486     auto host = GetHost();
1487     CHECK_NULL_RETURN(host, "");
1488     auto value = GetOption(GetSelected());
1489     auto index = GetSelected();
1490     if (isColumnChange) {
1491         value = GetCurrentText();
1492         index = GetCurrentIndex();
1493     }
1494 
1495     auto context = host->GetContext();
1496     CHECK_NULL_RETURN(context, "");
1497 
1498     if (context->GetIsDeclarative()) {
1499         return std::string("{\"value\":") + "\"" + value + "\"" + ",\"index\":" + std::to_string(index) +
1500                ",\"status\":" + std::to_string(status) + "}";
1501     } else {
1502         return std::string("{\"newValue\":") + "\"" + value + "\"" + ",\"newSelected\":" + std::to_string(index) +
1503                ",\"status\":" + std::to_string(status) + "}";
1504     }
1505 }
1506 
ResetTotalDelta()1507 void TextPickerColumnPattern::ResetTotalDelta()
1508 {
1509     totalDragDelta_ = 0.0;
1510 }
1511 
SpringCurveTailMoveProcess(bool useRebound,double & dragDelta)1512 bool TextPickerColumnPattern::SpringCurveTailMoveProcess(bool useRebound, double& dragDelta)
1513 {
1514     if (useRebound) {
1515         return false;
1516     }
1517     auto toss = GetToss();
1518     if (toss && toss->GetTossPlaying()) {
1519         if (std::abs(dragDelta) < CURVE_MOVE_THRESHOLD) {
1520             dragDelta = dragDelta > 0 ? CURVE_MOVE_THRESHOLD : -CURVE_MOVE_THRESHOLD;
1521         }
1522         totalDragDelta_ += dragDelta;
1523         if (std::abs(totalDragDelta_) >= std::abs(toss->GetTossEndPosition())) {
1524             dragDelta -= (totalDragDelta_ - toss->GetTossEndPosition());
1525             ResetTotalDelta();
1526             return true;
1527         }
1528     }
1529     return false;
1530 }
1531 
SpringCurveTailEndProcess(bool useRebound,bool stopMove)1532 void TextPickerColumnPattern::SpringCurveTailEndProcess(bool useRebound, bool stopMove)
1533 {
1534     if (useRebound || !stopMove) {
1535         return;
1536     }
1537     auto toss = GetToss();
1538     if (toss) {
1539         toss->SetTossPlaying(false);
1540         toss->StopTossAnimation();
1541     }
1542 }
1543 
UpdateColumnChildPosition(double offsetY)1544 void TextPickerColumnPattern::UpdateColumnChildPosition(double offsetY)
1545 {
1546     double dragDelta = offsetY - yLast_;
1547     auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1548     ScrollDirection dir = GreatNotEqual(dragDelta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1549     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1550                                                       : optionProperties_[midIndex].nextDistance;
1551     auto useRebound = NotLoopOptions();
1552     auto stopMove = SpringCurveTailMoveProcess(useRebound, dragDelta);
1553     offsetCurSet_ = 0.0;
1554 
1555     // the abs of drag delta is less than jump interval.
1556     dragDelta = dragDelta + yOffset_;
1557     auto isOverScroll = useRebound && overscroller_.IsOverScroll();
1558     if ((std::abs(dragDelta) >= std::abs(shiftDistance)) && !isOverScroll) {
1559         int32_t shiftDistanceCount = static_cast<int>(std::abs(dragDelta) / std::abs(shiftDistance));
1560         double additionalShift = dragDelta - shiftDistanceCount * shiftDistance;
1561         if (GreatNotEqual(std::abs(additionalShift), std::abs(dragDelta))) {
1562             additionalShift = dragDelta + shiftDistanceCount * shiftDistance;
1563         }
1564         for (int32_t i = 0; i < shiftDistanceCount; i++) {
1565             ScrollOption(shiftDistance);
1566             InnerHandleScroll(dragDelta < 0, true, false);
1567         }
1568         dragDelta = additionalShift;
1569         if (NearZero(dragDelta)) {
1570             HandleScrollStopEventCallback(true);
1571         }
1572     }
1573     if (useRebound && !isReboundInProgress_) {
1574         if (overscroller_.ApplyCurrentOffset(yLast_, offsetY, dragDelta)) {
1575             dragDelta =
1576                 overscroller_.IsBackOverScroll() ? overscroller_.GetBackScroll() : overscroller_.GetOverScroll();
1577         }
1578     }
1579 
1580     // Set options position
1581     ScrollOption(dragDelta);
1582     offsetCurSet_ = dragDelta;
1583     yOffset_ = dragDelta;
1584     yLast_ = offsetY;
1585 
1586     if (useRebound && !pressed_ && isTossStatus_ && !isReboundInProgress_ && overscroller_.IsOverScroll()) {
1587         overscroller_.UpdateTossSpring(offsetY);
1588         if (overscroller_.ShouldStartRebound()) {
1589             auto toss = GetToss();
1590             CHECK_NULL_VOID(toss);
1591             toss->StopTossAnimation(); // Stop fling animation and start rebound animation implicitly
1592         }
1593     }
1594     SpringCurveTailEndProcess(useRebound, stopMove);
1595 }
1596 
CanMove(bool isDown) const1597 bool TextPickerColumnPattern::CanMove(bool isDown) const
1598 {
1599     if (!NotLoopOptions()) {
1600         return true;
1601     }
1602     auto host = GetHost();
1603     CHECK_NULL_RETURN(host, false);
1604     int totalOptionCount = static_cast<int>(GetOptionCount());
1605     int currentIndex = static_cast<int>(GetCurrentIndex());
1606     int nextVirtualIndex = isDown ? currentIndex + 1 : currentIndex - 1;
1607     return nextVirtualIndex >= 0 && nextVirtualIndex < totalOptionCount;
1608 }
1609 
NotLoopOptions() const1610 bool TextPickerColumnPattern::NotLoopOptions() const
1611 {
1612     RefPtr<TextPickerLayoutProperty> layout = GetParentLayout();
1613     CHECK_NULL_RETURN(layout, false);
1614     bool canLoop = layout->GetCanLoop().value_or(true);
1615     return !canLoop;
1616 }
1617 
InnerHandleScroll(bool isDown,bool isUpatePropertiesOnly,bool isUpdateAnimationProperties)1618 bool TextPickerColumnPattern::InnerHandleScroll(
1619     bool isDown, bool isUpatePropertiesOnly, bool isUpdateAnimationProperties)
1620 {
1621     auto host = GetHost();
1622     CHECK_NULL_RETURN(host, false);
1623     auto totalOptionCount = GetOptionCount();
1624     if (totalOptionCount == 0) {
1625         return false;
1626     }
1627 
1628     if (NotLoopOptions() && ((isDown && currentIndex_ == totalOptionCount - 1) || (!isDown && currentIndex_ == 0))) {
1629         return false;
1630     }
1631 
1632     uint32_t currentIndex = GetCurrentIndex();
1633     if (isDown) {
1634         currentIndex = (totalOptionCount + currentIndex + 1) % totalOptionCount; // index add one
1635     } else {
1636         auto totalCountAndIndex = totalOptionCount + currentIndex;
1637         currentIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount; // index reduce one
1638     }
1639     SetCurrentIndex(currentIndex);
1640     FlushCurrentOptions(isDown, isUpatePropertiesOnly, isUpdateAnimationProperties);
1641     HandleChangeCallback(isDown, true);
1642     HandleEventCallback(true);
1643 
1644     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1645     host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE);
1646     return true;
1647 }
1648 
OnKeyEvent(const KeyEvent & event)1649 bool TextPickerColumnPattern::OnKeyEvent(const KeyEvent& event)
1650 {
1651     if (event.action != KeyAction::DOWN) {
1652         return false;
1653     }
1654     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
1655         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
1656         HandleDirectionKey(event.code);
1657         return true;
1658     }
1659     return false;
1660 }
1661 
HandleDirectionKey(KeyCode code)1662 bool TextPickerColumnPattern::HandleDirectionKey(KeyCode code)
1663 {
1664     auto host = GetHost();
1665     CHECK_NULL_RETURN(host, false);
1666     auto currentIndex = GetCurrentIndex();
1667     auto totalOptionCount = GetOptionCount();
1668     if (totalOptionCount == 0) {
1669         return false;
1670     }
1671     if (code == KeyCode::KEY_DPAD_UP) {
1672         auto totalCountAndIndex = totalOptionCount + currentIndex;
1673         SetCurrentIndex((totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount);
1674         FlushCurrentOptions();
1675         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1676         return true;
1677     }
1678     if (code == KeyCode::KEY_DPAD_DOWN) {
1679         SetCurrentIndex((totalOptionCount + currentIndex + 1) % totalOptionCount);
1680         FlushCurrentOptions(true);
1681         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1682         return true;
1683     }
1684     return false;
1685 }
SetAccessibilityAction()1686 void TextPickerColumnPattern::SetAccessibilityAction()
1687 {
1688     auto host = GetHost();
1689     CHECK_NULL_VOID(host);
1690     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1691     CHECK_NULL_VOID(accessibilityProperty);
1692     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1693         const auto& pattern = weakPtr.Upgrade();
1694         CHECK_NULL_VOID(pattern);
1695         CHECK_NULL_VOID(pattern->animationCreated_);
1696         if (!pattern->CanMove(true)) {
1697             return;
1698         }
1699         pattern->InnerHandleScroll(true);
1700         pattern->CreateAnimation(0.0 - pattern->jumpInterval_, 0.0);
1701         pattern->HandleScrollStopEventCallback(true);
1702         // AccessibilityEventType::SCROLL_END
1703     });
1704 
1705     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
1706         const auto& pattern = weakPtr.Upgrade();
1707         CHECK_NULL_VOID(pattern);
1708         CHECK_NULL_VOID(pattern->animationCreated_);
1709         if (!pattern->CanMove(false)) {
1710             return;
1711         }
1712         pattern->InnerHandleScroll(false);
1713         pattern->CreateAnimation(pattern->jumpInterval_, 0.0);
1714         pattern->HandleScrollStopEventCallback(true);
1715         // AccessibilityEventType::SCROLL_END
1716     });
1717 }
1718 
OnAroundButtonClick(RefPtr<EventParam> param)1719 void TextPickerColumnPattern::OnAroundButtonClick(RefPtr<EventParam> param)
1720 {
1721     if (clickBreak_) {
1722         return;
1723     }
1724     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
1725     int32_t step = param->itemIndex - middleIndex;
1726     auto overFirst = static_cast<int32_t>(currentIndex_) + step < 0 && step < 0;
1727     auto overLast =
1728         (static_cast<int32_t>(currentIndex_) + step > static_cast<int32_t>(GetOptionCount()) - 1) && step > 0;
1729     if (NotLoopOptions() && (overscroller_.IsOverScroll() || overFirst || overLast)) {
1730         return;
1731     }
1732     if (step != 0) {
1733         if (animation_) {
1734             AnimationUtils::StopAnimation(animation_);
1735             yOffset_ = 0.0;
1736         }
1737         double distance =
1738             (step > 0 ? optionProperties_[middleIndex].prevDistance : optionProperties_[middleIndex].nextDistance) *
1739             std::abs(step);
1740         AnimationOption option;
1741         option.SetCurve(Curves::FAST_OUT_SLOW_IN);
1742         option.SetDuration(CLICK_ANIMATION_DURATION);
1743         yLast_ = 0.0;
1744         aroundClickProperty_->Set(0.0);
1745         animation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), step, distance]() {
1746             auto column = weak.Upgrade();
1747             CHECK_NULL_VOID(column);
1748             column->aroundClickProperty_->Set(step > 0 ? 0.0 - std::abs(distance) : std::abs(distance));
1749         });
1750         auto host = GetHost();
1751         CHECK_NULL_VOID(host);
1752         auto pipeline = host->GetContext();
1753         CHECK_NULL_VOID(pipeline);
1754         pipeline->RequestFrame();
1755     }
1756 }
1757 
PlayResetAnimation()1758 void TextPickerColumnPattern::PlayResetAnimation()
1759 {
1760     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
1761     ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1762     double shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
1763                                                         : optionProperties_[middleIndex].nextDistance;
1764     double shiftThreshold = shiftDistance / HALF_NUMBER;
1765     if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
1766         InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
1767         scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
1768         if (NearZero(scrollDelta_)) {
1769             HandleScrollStopEventCallback(true);
1770         }
1771     }
1772     CreateAnimation(scrollDelta_, 0.0);
1773     if (!NearZero(scrollDelta_)) {
1774         HandleScrollStopEventCallback(true);
1775     }
1776 }
1777 
SetCanLoop(bool isLoop)1778 void TextPickerColumnPattern::SetCanLoop(bool isLoop)
1779 {
1780     if (isLoop_ == isLoop) {
1781         return;
1782     }
1783 
1784     isLoop_ = isLoop;
1785     if (overscroller_.IsOverScroll()) {
1786         overscroller_.Reset();
1787         isReboundInProgress_ = false;
1788         yOffset_ = 0.0;
1789         ScrollOption(0.0);
1790     }
1791 
1792     if (!isLoop && isTossStatus_) {
1793         auto toss = GetToss();
1794         CHECK_NULL_VOID(toss);
1795         overscroller_.SetLoopTossOffset(toss->GetTossOffset());
1796     }
1797 }
1798 } // namespace OHOS::Ace::NG
1799