• 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 "adapter/ohos/entrance/picker/picker_haptic_factory.h"
22 #include "base/geometry/dimension.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/utils/measure_util.h"
25 #include "base/utils/utils.h"
26 #include "bridge/common/utils/utils.h"
27 #include "core/common/container.h"
28 #include "core/common/font_manager.h"
29 #include "core/components/picker/picker_theme.h"
30 #include "core/components_ng/base/frame_scene_status.h"
31 #include "core/components_ng/pattern/image/image_layout_property.h"
32 #include "core/components_ng/pattern/image/image_pattern.h"
33 #include "core/components_ng/pattern/text/text_pattern.h"
34 #include "core/components_ng/pattern/text_picker/textpicker_event_hub.h"
35 #include "core/components_ng/pattern/button/button_layout_property.h"
36 
37 namespace OHOS::Ace::NG {
38 namespace {
39 const Dimension FONT_SIZE = Dimension(2.0);
40 const Dimension FOCUS_SIZE = Dimension(1.0);
41 const float MOVE_DISTANCE = 5.0f;
42 const double MOVE_THRESHOLD = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? 2.0 : 1.0;
43 constexpr float FONTWEIGHT = 0.5f;
44 constexpr float FONT_SIZE_PERCENT = 1.0f;
45 constexpr int32_t HOVER_ANIMATION_DURATION = 40;
46 constexpr int32_t CLICK_ANIMATION_DURATION = 300;
47 constexpr size_t MIXTURE_CHILD_COUNT = 2;
48 const uint32_t OPTION_COUNT_PHONE_LANDSCAPE = 3;
49 const Dimension ICON_SIZE = 24.0_vp;
50 const Dimension ICON_TEXT_SPACE = 8.0_vp;
51 const std::vector<std::string> FONT_FAMILY_DEFAULT = { "sans-serif" };
52 const std::string MEASURE_STRING = "TEST";
53 const int32_t HALF_NUMBER = 2;
54 const int32_t BUFFER_NODE_NUMBER = 2;
55 const double CURVE_MOVE_THRESHOLD = 0.5;
56 constexpr char PICKER_DRAG_SCENE[] = "picker_drag_scene";
57 const uint32_t NEXT_COLOUM_DIFF = 1;
58 } // namespace
59 
OnAttachToFrameNode()60 void TextPickerColumnPattern::OnAttachToFrameNode()
61 {
62     auto host = GetHost();
63     CHECK_NULL_VOID(host);
64 
65     auto context = host->GetContextRefPtr();
66     CHECK_NULL_VOID(context);
67     auto pickerTheme = context->GetTheme<PickerTheme>();
68     CHECK_NULL_VOID(pickerTheme);
69     auto hub = host->GetEventHub<EventHub>();
70     CHECK_NULL_VOID(hub);
71     auto gestureHub = hub->GetOrCreateGestureEventHub();
72     CHECK_NULL_VOID(gestureHub);
73     tossAnimationController_->SetPipelineContext(context);
74     tossAnimationController_->SetColumn(AceType::WeakClaim(this));
75     overscroller_.SetColumn(AceType::WeakClaim(this));
76     jumpInterval_ = pickerTheme->GetJumpInterval().ConvertToPx();
77     CreateAnimation();
78     InitPanEvent(gestureHub);
79     host->GetRenderContext()->SetClipToFrame(true);
80     InitHapticController(host);
81     RegisterWindowStateChangedCallback();
82 }
83 
OnDetachFromFrameNode(FrameNode * frameNode)84 void TextPickerColumnPattern::OnDetachFromFrameNode(FrameNode* frameNode)
85 {
86     if (hapticController_) {
87         hapticController_->Stop();
88     }
89     UnregisterWindowStateChangedCallback(frameNode);
90 }
91 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)92 bool TextPickerColumnPattern::OnDirtyLayoutWrapperSwap(
93     const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
94 {
95     bool isChange =
96         config.frameSizeChange || config.frameOffsetChange || config.contentSizeChange || config.contentOffsetChange;
97 
98     CHECK_NULL_RETURN(isChange, false);
99     CHECK_NULL_RETURN(dirty, false);
100     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
101     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
102     auto layoutAlgorithm = DynamicCast<TextPickerLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
103     CHECK_NULL_RETURN(layoutAlgorithm, false);
104     halfDisplayCounts_ = layoutAlgorithm->GetHalfDisplayCounts();
105     return true;
106 }
107 
OnModifyDone()108 void TextPickerColumnPattern::OnModifyDone()
109 {
110     auto pipeline = PipelineContext::GetCurrentContext();
111     CHECK_NULL_VOID(pipeline);
112     auto theme = pipeline->GetTheme<PickerTheme>(GetThemeScopeId());
113     CHECK_NULL_VOID(theme);
114     pressColor_ = theme->GetPressColor();
115     hoverColor_ = theme->GetHoverColor();
116     useButtonFocusArea_ = theme->NeedButtonFocusAreaType();
117     InitTextFadeOut();
118     InitSelectorButtonProperties(theme);
119     InitMouseAndPressEvent();
120     SetAccessibilityAction();
121     auto host = GetHost();
122     CHECK_NULL_VOID(host);
123     if (optionProperties_.size() <= 0) {
124         dividerSpacing_ = pipeline->NormalizeToPx(theme->GetDividerSpacing());
125         gradientHeight_ = static_cast<float>(pipeline->NormalizeToPx(theme->GetGradientHeight()));
126 
127         auto showCount = GetShowOptionCount();
128         auto midIndex = showCount / HALF_NUMBER;
129         uint32_t childIndex = 0;
130 
131         while (childIndex < showCount) {
132             TextPickerOptionProperty prop;
133             InitTextHeightAndFontHeight(childIndex, midIndex, prop);
134             optionProperties_.emplace_back(prop);
135             childIndex++;
136         }
137         SetOptionShiftDistance();
138     }
139     InitHapticController(host);
140 }
141 
InitHapticController(const RefPtr<FrameNode> & host)142 void TextPickerColumnPattern::InitHapticController(const RefPtr<FrameNode>& host)
143 {
144     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
145         return;
146     }
147     CHECK_NULL_VOID(host);
148     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
149     CHECK_NULL_VOID(blendNode);
150     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
151     CHECK_NULL_VOID(stackNode);
152     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
153     CHECK_NULL_VOID(parentNode);
154     auto textPickerPattern = parentNode->GetPattern<TextPickerPattern>();
155     CHECK_NULL_VOID(textPickerPattern);
156     if (textPickerPattern->GetIsEnableHaptic()) {
157         isEnableHaptic_ = true;
158         if (!hapticController_) {
159             auto context = parentNode->GetContext();
160             CHECK_NULL_VOID(context);
161             context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
162                 auto pattern = weak.Upgrade();
163                 CHECK_NULL_VOID(pattern);
164                 pattern->hapticController_ = PickerAudioHapticFactory::GetInstance();
165             });
166         }
167     } else {
168         isEnableHaptic_ = false;
169         if (hapticController_) {
170             hapticController_->Stop();
171         }
172     }
173 }
174 
RegisterWindowStateChangedCallback()175 void TextPickerColumnPattern::RegisterWindowStateChangedCallback()
176 {
177     auto host = GetHost();
178     CHECK_NULL_VOID(host);
179     auto pipeline = host->GetContext();
180     CHECK_NULL_VOID(pipeline);
181     pipeline->AddWindowStateChangedCallback(host->GetId());
182 }
183 
UnregisterWindowStateChangedCallback(FrameNode * frameNode)184 void TextPickerColumnPattern::UnregisterWindowStateChangedCallback(FrameNode* frameNode)
185 {
186     CHECK_NULL_VOID(frameNode);
187     auto pipeline = frameNode->GetContext();
188     CHECK_NULL_VOID(pipeline);
189     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
190 }
191 
OnWindowHide()192 void TextPickerColumnPattern::OnWindowHide()
193 {
194     isShow_ = false;
195     if (hapticController_) {
196         hapticController_->Stop();
197     }
198 }
199 
StopHapticController()200 void TextPickerColumnPattern::StopHapticController()
201 {
202     if (hapticController_) {
203         hapticController_->Stop();
204     }
205 }
206 
OnWindowShow()207 void TextPickerColumnPattern::OnWindowShow()
208 {
209     isShow_ = true;
210 }
211 
OnMiddleButtonTouchDown()212 void TextPickerColumnPattern::OnMiddleButtonTouchDown()
213 {
214     PlayPressAnimation(pressColor_);
215 }
216 
OnMiddleButtonTouchMove()217 void TextPickerColumnPattern::OnMiddleButtonTouchMove()
218 {
219     PlayPressAnimation(Color::TRANSPARENT);
220 }
221 
OnMiddleButtonTouchUp()222 void TextPickerColumnPattern::OnMiddleButtonTouchUp()
223 {
224     PlayPressAnimation(isHover_ ? GetButtonHoverColor() : buttonBgColor_);
225 
226     if (useButtonFocusArea_) {
227         FlushCurrentOptions();
228     }
229 }
230 
InitSelectorButtonProperties(const RefPtr<PickerTheme> & pickerTheme)231 void TextPickerColumnPattern::InitSelectorButtonProperties(const RefPtr<PickerTheme>& pickerTheme)
232 {
233     CHECK_NULL_VOID(pickerTheme);
234     if (useButtonFocusArea_) {
235         buttonDefaultBgColor_ = pickerTheme->GetSelectorItemNormalBgColor();
236         buttonFocusBgColor_ = pickerTheme->GetSelectorItemFocusBgColor();
237         buttonDefaultBorderColor_ = pickerTheme->GetSelectorItemBorderColor();
238         buttonFocusBorderColor_ = pickerTheme->GetSelectorItemFocusBorderColor();
239         selectorTextFocusColor_ = pickerTheme->GetOptionStyle(true, true).GetTextColor();
240         pressColor_ = buttonDefaultBgColor_.BlendColor(pickerTheme->GetPressColor());
241         hoverColor_ = buttonDefaultBgColor_.BlendColor(pickerTheme->GetHoverColor());
242 
243         buttonFocusBorderWidth_ = pickerTheme->GetSelectorItemFocusBorderWidth();
244         buttonDefaultBorderWidth_ = pickerTheme->GetSelectorItemBorderWidth();
245     }
246 }
247 
GetButtonHoverColor() const248 const Color& TextPickerColumnPattern::GetButtonHoverColor() const
249 {
250     return useButtonFocusArea_ && isFocusColumn_ ? buttonFocusBgColor_ : hoverColor_;
251 }
252 
UpdateColumnButtonFocusState(bool haveFocus,bool needMarkDirty)253 void TextPickerColumnPattern::UpdateColumnButtonFocusState(bool haveFocus, bool needMarkDirty)
254 {
255     auto isInitUpdate = isFirstTimeUpdateButtonProps_ && !haveFocus;
256     auto isFocusChanged = isFocusColumn_ != haveFocus;
257 
258     if (isFocusChanged || isInitUpdate) {
259         isFocusColumn_ = haveFocus;
260         UpdateSelectorButtonProps(isFocusColumn_, needMarkDirty);
261     }
262     if (isFocusChanged) {
263         FlushCurrentOptions();
264     }
265     if (isInitUpdate) {
266         isFirstTimeUpdateButtonProps_ = false;
267     }
268 }
269 
UpdateSelectorButtonProps(bool haveFocus,bool needMarkDirty)270 void TextPickerColumnPattern::UpdateSelectorButtonProps(bool haveFocus, bool needMarkDirty)
271 {
272     auto host = GetHost();
273     CHECK_NULL_VOID(host);
274     auto blend = host->GetParent();
275     CHECK_NULL_VOID(blend);
276     auto stack = blend->GetParent();
277     CHECK_NULL_VOID(stack);
278     auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
279     CHECK_NULL_VOID(buttonNode);
280     auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
281     CHECK_NULL_VOID(buttonLayoutProperty);
282     auto renderContext = buttonNode->GetRenderContext();
283     CHECK_NULL_VOID(renderContext);
284 
285     BorderWidthProperty borderWidth;
286     BorderColorProperty borderColor;
287 
288     if (haveFocus) {
289         buttonBgColor_ = buttonFocusBgColor_;
290         borderWidth.SetBorderWidth(buttonFocusBorderWidth_);
291         borderColor.SetColor(buttonFocusBorderColor_);
292     } else {
293         buttonBgColor_ = buttonDefaultBgColor_;
294         borderWidth.SetBorderWidth(buttonDefaultBorderWidth_);
295         borderColor.SetColor(buttonDefaultBorderColor_);
296     }
297 
298     buttonLayoutProperty->UpdateBorderWidth(borderWidth);
299     renderContext->UpdateBorderColor(borderColor);
300     renderContext->UpdateBackgroundColor(buttonBgColor_);
301 
302     if (needMarkDirty) {
303         buttonNode->MarkModifyDone();
304         buttonNode->MarkDirtyNode();
305     }
306 }
307 
UpdateTextAreaPadding(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty)308 void TextPickerColumnPattern::UpdateTextAreaPadding(const RefPtr<PickerTheme>& pickerTheme,
309     const RefPtr<TextLayoutProperty>& textLayoutProperty)
310 {
311     if (useButtonFocusArea_) {
312         auto padding = pickerTheme->GetSelectorItemSpace();
313         PaddingProperty defaultPadding = { CalcLength(padding), CalcLength(padding),
314             CalcLength(0.0_vp), CalcLength(0.0_vp) };
315         textLayoutProperty->UpdatePadding(defaultPadding);
316     }
317 }
318 
InitTextFadeOut()319 void TextPickerColumnPattern::InitTextFadeOut()
320 {
321     auto host = GetHost();
322     CHECK_NULL_VOID(host);
323     auto context = host->GetContextRefPtr();
324     CHECK_NULL_VOID(context);
325     auto textTheme = context->GetTheme<TextTheme>();
326     CHECK_NULL_VOID(textTheme);
327     isTextFadeOut_ = textTheme->GetIsTextFadeout();
328 }
329 
UpdateTextOverflow(bool isSel,const RefPtr<TextLayoutProperty> & textLayoutProperty)330 void TextPickerColumnPattern::UpdateTextOverflow(bool isSel, const RefPtr<TextLayoutProperty>& textLayoutProperty)
331 {
332     if (isTextFadeOut_) {
333         textLayoutProperty->UpdateTextOverflow(TextOverflow::MARQUEE);
334         textLayoutProperty->UpdateTextMarqueeStartPolicy(MarqueeStartPolicy::DEFAULT);
335         textLayoutProperty->UpdateTextMarqueeFadeout(true);
336         textLayoutProperty->UpdateTextMarqueeStart(isSel && (isFocusColumn_ || isHover_));
337     }
338 }
339 
GetMiddleButtonIndex()340 int32_t TextPickerColumnPattern::GetMiddleButtonIndex()
341 {
342     return GetShowOptionCount() / 2;
343 }
344 
CreateItemTouchEventListener()345 RefPtr<TouchEventImpl> TextPickerColumnPattern::CreateItemTouchEventListener()
346 {
347     auto toss = GetToss();
348     CHECK_NULL_RETURN(toss, nullptr);
349     auto touchCallback = [weak = WeakClaim(this), toss](const TouchEventInfo& info) {
350         auto pattern = weak.Upgrade();
351         CHECK_NULL_VOID(pattern);
352         auto isToss = pattern->GetTossStatus();
353         if (info.GetTouches().empty()) {
354             return;
355         }
356         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
357             if (isToss) {
358                 pattern->touchBreak_ = true;
359                 pattern->animationBreak_ = true;
360                 pattern->clickBreak_ = true;
361                 auto TossEndPosition = toss->GetTossEndPosition();
362                 pattern->SetYLast(TossEndPosition);
363                 toss->StopTossAnimation();
364                 pattern->StopHapticController();
365             } else {
366                 pattern->animationBreak_ = false;
367                 pattern->clickBreak_ = false;
368             }
369         }
370         if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
371             pattern->touchBreak_ = false;
372             if (pattern->animationBreak_) {
373                 pattern->PlayResetAnimation();
374                 pattern->yOffset_ = 0.0;
375             }
376         }
377     };
378     auto listener = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
379     return listener;
380 }
381 
CreateItemClickEventListener(RefPtr<EventParam> param)382 RefPtr<ClickEvent> TextPickerColumnPattern::CreateItemClickEventListener(RefPtr<EventParam> param)
383 {
384     auto clickEventHandler = [param, weak = WeakClaim(this)](const GestureEvent& /* info */) {
385         auto pattern = weak.Upgrade();
386         pattern->OnAroundButtonClick(param);
387     };
388 
389     auto listener = AceType::MakeRefPtr<NG::ClickEvent>(clickEventHandler);
390     return listener;
391 }
392 
CreateMouseHoverEventListener(RefPtr<EventParam> param)393 RefPtr<InputEvent> TextPickerColumnPattern::CreateMouseHoverEventListener(RefPtr<EventParam> param)
394 {
395     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
396         auto pattern = weak.Upgrade();
397         if (pattern) {
398             pattern->HandleMouseEvent(isHover);
399         }
400     };
401     auto hoverEventListener = MakeRefPtr<InputEvent>(std::move(mouseTask));
402     return hoverEventListener;
403 }
404 
ParseTouchListener()405 void TextPickerColumnPattern::ParseTouchListener()
406 {
407     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
408         auto pattern = weak.Upgrade();
409         CHECK_NULL_VOID(pattern);
410         if (info.GetTouches().empty()) {
411             return;
412         }
413         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
414             pattern->SetLocalDownDistance(info.GetTouches().front().GetLocalLocation().GetDistance());
415             pattern->OnMiddleButtonTouchDown();
416             pattern->SetSelectedMark(true);
417             return;
418         }
419         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
420             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
421             pattern->OnMiddleButtonTouchUp();
422             pattern->SetLocalDownDistance(0.0f);
423             return;
424         }
425         if (info.GetTouches().front().GetTouchType() == TouchType::MOVE) {
426             if (std::abs(info.GetTouches().front().GetLocalLocation().GetDistance() - pattern->GetLocalDownDistance()) >
427                 MOVE_DISTANCE) {
428                 pattern->OnMiddleButtonTouchUp();
429             }
430         }
431     };
432     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
433 }
434 
ParseMouseEvent()435 void TextPickerColumnPattern::ParseMouseEvent()
436 {
437     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
438         auto pattern = weak.Upgrade();
439         CHECK_NULL_VOID(pattern);
440         pattern->HandleMouseEvent(isHover);
441     };
442     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
443 }
444 
InitMouseAndPressEvent()445 void TextPickerColumnPattern::InitMouseAndPressEvent()
446 {
447     if (mouseEvent_ || touchListener_) {
448         return;
449     }
450     auto host = GetHost();
451     CHECK_NULL_VOID(host);
452     auto columnEventHub = host->GetEventHub<EventHub>();
453     CHECK_NULL_VOID(columnEventHub);
454     RefPtr<TouchEventImpl> touchListener = CreateItemTouchEventListener();
455     CHECK_NULL_VOID(touchListener);
456     auto columnGesture = columnEventHub->GetOrCreateGestureEventHub();
457     CHECK_NULL_VOID(columnGesture);
458     columnGesture->AddTouchEvent(touchListener);
459     auto childSize = static_cast<int32_t>(host->GetChildren().size());
460     RefPtr<FrameNode> middleChild = nullptr;
461     auto midSize = childSize / 2;
462     middleChild = DynamicCast<FrameNode>(host->GetChildAtIndex(midSize));
463     CHECK_NULL_VOID(middleChild);
464     auto eventHub = middleChild->GetEventHub<EventHub>();
465     CHECK_NULL_VOID(eventHub);
466     auto inputHub = eventHub->GetOrCreateInputEventHub();
467     ParseMouseEvent();
468     inputHub->AddOnHoverEvent(mouseEvent_);
469     auto gesture = middleChild->GetOrCreateGestureEventHub();
470     CHECK_NULL_VOID(gesture);
471     ParseTouchListener();
472     gesture->AddTouchEvent(touchListener_);
473     int32_t i = 0;
474     for (const auto& child : host->GetChildren()) {
475         RefPtr<FrameNode> childNode = DynamicCast<FrameNode>(child);
476         CHECK_NULL_VOID(childNode);
477         RefPtr<EventParam> param = MakeRefPtr<EventParam>();
478         param->instance = childNode;
479         param->itemIndex = i;
480         param->itemTotalCounts = childSize;
481         auto eventHub = childNode->GetEventHub<EventHub>();
482         CHECK_NULL_VOID(eventHub);
483         if (i != midSize) {
484             RefPtr<ClickEvent> clickListener = CreateItemClickEventListener(param);
485             CHECK_NULL_VOID(clickListener);
486             auto gesture = eventHub->GetOrCreateGestureEventHub();
487             CHECK_NULL_VOID(gesture);
488             gesture->AddClickEvent(clickListener);
489         }
490         i++;
491     }
492 }
493 
HandleMouseEvent(bool isHover)494 void TextPickerColumnPattern::HandleMouseEvent(bool isHover)
495 {
496     PlayPressAnimation(isHover ? GetButtonHoverColor() : buttonBgColor_);
497     auto needUpdate = isHover_ != isHover;
498     isHover_ = isHover;
499 
500     if (useButtonFocusArea_ && needUpdate) {
501         FlushCurrentOptions();
502     }
503 }
504 
SetButtonBackgroundColor(const Color & pressColor)505 void TextPickerColumnPattern::SetButtonBackgroundColor(const Color& pressColor)
506 {
507     auto pipeline = GetContext();
508     CHECK_NULL_VOID(pipeline);
509     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
510     CHECK_NULL_VOID(pickerTheme);
511     CHECK_EQUAL_VOID(pickerTheme->IsCircleDial(), true);
512 
513     auto host = GetHost();
514     CHECK_NULL_VOID(host);
515     auto blend = host->GetParent();
516     CHECK_NULL_VOID(blend);
517     auto stack = blend->GetParent();
518     CHECK_NULL_VOID(stack);
519     auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
520     auto renderContext = buttonNode->GetRenderContext();
521     renderContext->UpdateBackgroundColor(pressColor);
522     buttonNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
523 }
524 
PlayPressAnimation(const Color & pressColor)525 void TextPickerColumnPattern::PlayPressAnimation(const Color& pressColor)
526 {
527     AnimationOption option = AnimationOption();
528     option.SetDuration(HOVER_ANIMATION_DURATION);
529     option.SetFillMode(FillMode::FORWARDS);
530     AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), pressColor]() {
531         auto picker = weak.Upgrade();
532         if (picker) {
533             picker->SetButtonBackgroundColor(pressColor);
534         }
535     });
536 }
537 
GetShowOptionCount() const538 uint32_t TextPickerColumnPattern::GetShowOptionCount() const
539 {
540     auto context = PipelineContext::GetCurrentContext();
541     CHECK_NULL_RETURN(context, 0);
542     auto pickerTheme = context->GetTheme<PickerTheme>();
543     CHECK_NULL_RETURN(pickerTheme, 0);
544     auto showCount = pickerTheme->GetShowOptionCount() + BUFFER_NODE_NUMBER;
545     return showCount;
546 }
547 
ResetOptionPropertyHeight()548 void TextPickerColumnPattern::ResetOptionPropertyHeight()
549 {
550     if (needOptionPropertyHeightReset_) {
551         auto host = GetHost();
552         CHECK_NULL_VOID(host);
553         auto blendNode = DynamicCast<FrameNode>(host->GetParent());
554         CHECK_NULL_VOID(blendNode);
555         auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
556         CHECK_NULL_VOID(stackNode);
557         auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
558         CHECK_NULL_VOID(parentNode);
559         auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
560         CHECK_NULL_VOID(textPickerLayoutProperty);
561         bool isDefaultPickerItemHeight_ = false;
562         if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
563             auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
564             isDefaultPickerItemHeight_ = LessOrEqual(defaultPickerItemHeightValue.Value(), 0.0) ? false : true;
565         }
566         if (isDefaultPickerItemHeight_) {
567             auto pickerItemHeight = 0.0;
568             auto pattern = parentNode->GetPattern<TextPickerPattern>();
569             CHECK_NULL_VOID(pattern);
570             pickerItemHeight =
571                 pattern->GetResizeFlag() ? pattern->GetResizePickerItemHeight() : pattern->GetDefaultPickerItemHeight();
572             int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
573             for (int32_t i = 0; i < itemCounts; i++) {
574                 TextPickerOptionProperty& prop = optionProperties_[i];
575                 prop.height = pickerItemHeight;
576             }
577             SetOptionShiftDistance();
578         }
579         needOptionPropertyHeightReset_ = false;
580     }
581 }
582 
InitTextFontFamily()583 void TextPickerColumnPattern::InitTextFontFamily()
584 {
585     auto host = GetHost();
586     CHECK_NULL_VOID(host);
587     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
588     CHECK_NULL_VOID(blendNode);
589     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
590     CHECK_NULL_VOID(stackNode);
591     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
592     CHECK_NULL_VOID(parentNode);
593     auto pipeline = parentNode->GetContext();
594     CHECK_NULL_VOID(pipeline);
595     auto pattern = parentNode->GetPattern<TextPickerPattern>();
596     CHECK_NULL_VOID(pattern);
597     auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
598     CHECK_NULL_VOID(textPickerLayoutProperty);
599     hasUserDefinedDisappearFontFamily_ = pattern->GetHasUserDefinedDisappearFontFamily();
600     hasUserDefinedNormalFontFamily_ = pattern->GetHasUserDefinedNormalFontFamily();
601     hasUserDefinedSelectedFontFamily_ = pattern->GetHasUserDefinedSelectedFontFamily();
602     auto fontManager = pipeline->GetFontManager();
603     CHECK_NULL_VOID(fontManager);
604     if (!(fontManager->GetAppCustomFont().empty())) {
605         hasAppCustomFont_ = true;
606     }
607     auto appCustomFontFamily = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
608     if (hasAppCustomFont_ && !hasUserDefinedDisappearFontFamily_) {
609         textPickerLayoutProperty->UpdateDisappearFontFamily(appCustomFontFamily);
610     }
611     if (hasAppCustomFont_ && !hasUserDefinedNormalFontFamily_) {
612         textPickerLayoutProperty->UpdateFontFamily(appCustomFontFamily);
613     }
614     if (hasAppCustomFont_ && !hasUserDefinedSelectedFontFamily_) {
615         textPickerLayoutProperty->UpdateSelectedFontFamily(appCustomFontFamily);
616     }
617 }
618 
FlushCurrentOptions(bool isDown,bool isUpdateTextContentOnly,bool isDirectlyClear,bool isUpdateAnimationProperties)619 void TextPickerColumnPattern::FlushCurrentOptions(
620     bool isDown, bool isUpdateTextContentOnly, bool isDirectlyClear, bool isUpdateAnimationProperties)
621 {
622     ResetOptionPropertyHeight();
623 
624     auto host = GetHost();
625     CHECK_NULL_VOID(host);
626     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
627     CHECK_NULL_VOID(blendNode);
628     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
629     CHECK_NULL_VOID(stackNode);
630     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
631     CHECK_NULL_VOID(parentNode);
632     auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
633     CHECK_NULL_VOID(textPickerLayoutProperty);
634 
635     InitTextFontFamily();
636 
637     if (!isUpdateTextContentOnly) {
638         animationProperties_.clear();
639     }
640     if (columnKind_ == TEXT) {
641         FlushCurrentTextOptions(textPickerLayoutProperty, isUpdateTextContentOnly, isDirectlyClear);
642     } else if (columnKind_ == ICON) {
643         FlushCurrentImageOptions();
644     } else if (columnKind_ == MIXTURE) {
645         FlushCurrentMixtureOptions(textPickerLayoutProperty, isUpdateTextContentOnly);
646     }
647     if (isUpdateTextContentOnly && isUpdateAnimationProperties) {
648         FlushAnimationTextProperties(isDown);
649     }
650 }
651 
ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly,bool isDirectlyClear)652 void TextPickerColumnPattern::ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
653     bool isUpdateTextContentOnly, bool isDirectlyClear)
654 {
655     if (isDirectlyClear) {
656         auto host = GetHost();
657         CHECK_NULL_VOID(host);
658         auto child = host->GetChildren();
659         for (auto iter = child.begin(); iter != child.end(); iter++) {
660             auto textNode = DynamicCast<FrameNode>(*iter);
661             CHECK_NULL_VOID(textNode);
662             auto textPattern = textNode->GetPattern<TextPattern>();
663             CHECK_NULL_VOID(textPattern);
664             auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
665             CHECK_NULL_VOID(textLayoutProperty);
666             textLayoutProperty->UpdateContent(u"");
667             textNode->GetRenderContext()->SetClipToFrame(true);
668             textNode->MarkModifyDone();
669             textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
670         }
671         selectedIndex_ = 0;
672     }
673 }
674 
FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly,bool isDirectlyClear)675 void TextPickerColumnPattern::FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
676     bool isUpdateTextContentOnly, bool isDirectlyClear)
677 {
678     ClearCurrentTextOptions(textPickerLayoutProperty, isUpdateTextContentOnly, isDirectlyClear);
679     uint32_t totalOptionCount = GetOptionCount();
680     if (totalOptionCount == 0) {
681         return;
682     }
683     uint32_t currentIndex = GetCurrentIndex();
684     currentIndex = currentIndex % totalOptionCount;
685     uint32_t showCount = GetShowOptionCount();
686     auto middleIndex = showCount / 2; // the center option is selected.
687     auto host = GetHost();
688     CHECK_NULL_VOID(host);
689     auto child = host->GetChildren();
690     auto iter = child.begin();
691     if (child.size() != showCount) {
692         return;
693     }
694     for (uint32_t index = 0; index < showCount; index++) {
695         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
696         RangeContent optionValue = options_[optionIndex];
697         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
698         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
699         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
700         auto textNode = DynamicCast<FrameNode>(*iter);
701         CHECK_NULL_VOID(textNode);
702         auto textPattern = textNode->GetPattern<TextPattern>();
703         CHECK_NULL_VOID(textPattern);
704         auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
705         CHECK_NULL_VOID(textLayoutProperty);
706         UpdateTextOverflow(index == middleIndex, textLayoutProperty);
707         if (!isUpdateTextContentOnly) {
708             UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
709         }
710         if (NotLoopOptions() && !virtualIndexValidate) {
711             textLayoutProperty->UpdateContent(u"");
712         } else {
713             textLayoutProperty->UpdateContent(optionValue.text_);
714             textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
715         }
716         UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
717         textNode->GetRenderContext()->SetClipToFrame(true);
718         textNode->MarkModifyDone();
719         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
720         iter++;
721     }
722     selectedIndex_ = currentIndex;
723 }
724 
UpdateTextAccessibilityProperty(int32_t virtualIndex,std::list<RefPtr<UINode>>::iterator & iter,bool virtualIndexValidate)725 void TextPickerColumnPattern::UpdateTextAccessibilityProperty(
726     int32_t virtualIndex, std::list<RefPtr<UINode>>::iterator& iter, bool virtualIndexValidate)
727 {
728     auto textNode = DynamicCast<FrameNode>(*(iter));
729     CHECK_NULL_VOID(textNode);
730     auto accessibilityProperty = textNode->GetAccessibilityProperty<AccessibilityProperty>();
731     CHECK_NULL_VOID(accessibilityProperty);
732     if (!NotLoopOptions() || virtualIndexValidate) {
733         accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::AUTO);
734         return;
735     }
736     accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
737     auto isFocus = accessibilityProperty->GetAccessibilityFocusState();
738     if (virtualIndex == -1 && isFocus) {
739         auto nextTextNode = DynamicCast<FrameNode>(*(++iter));
740         if (nextTextNode) {
741             nextTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
742         }
743         --iter;
744     } else if (virtualIndex == static_cast<int32_t>(GetOptionCount()) && isFocus) {
745         auto preTextNode = DynamicCast<FrameNode>(*(--iter));
746         if (preTextNode) {
747             preTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
748         }
749         ++iter;
750     }
751 }
752 
FlushCurrentImageOptions()753 void TextPickerColumnPattern::FlushCurrentImageOptions()
754 {
755     uint32_t totalOptionCount = GetOptionCount();
756     if (totalOptionCount == 0) {
757         return;
758     }
759     uint32_t currentIndex = GetCurrentIndex();
760     currentIndex = currentIndex % totalOptionCount;
761     uint32_t showCount = GetShowOptionCount();
762     auto middleIndex = showCount / 2; // the center option is selected.
763     auto host = GetHost();
764     CHECK_NULL_VOID(host);
765     auto child = host->GetChildren();
766     auto iter = child.begin();
767     if (child.size() != showCount) {
768         return;
769     }
770     for (uint32_t index = 0; index < showCount; index++) {
771         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
772         RangeContent optionValue = options_[optionIndex];
773         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
774         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
775         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
776         auto rangeNode = DynamicCast<FrameNode>(*iter);
777         CHECK_NULL_VOID(rangeNode);
778         auto iconNode = DynamicCast<FrameNode>(rangeNode->GetFirstChild());
779         CHECK_NULL_VOID(iconNode);
780         auto iconPattern = iconNode->GetPattern<ImagePattern>();
781         CHECK_NULL_VOID(iconPattern);
782         auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
783         CHECK_NULL_VOID(iconLayoutProperty);
784         CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
785         MeasureProperty layoutConstraint;
786         layoutConstraint.selfIdealSize = idealSize;
787         iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
788         if (NotLoopOptions() && !virtualIndexValidate) {
789             iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
790         } else {
791             iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
792             iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
793         }
794         UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
795         iconNode->MarkModifyDone();
796         iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
797 
798         rangeNode->GetRenderContext()->SetClipToFrame(true);
799         rangeNode->MarkModifyDone();
800         rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
801         iter++;
802     }
803     selectedIndex_ = currentIndex;
804 }
805 
FlushCurrentMixtureOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly)806 void TextPickerColumnPattern::FlushCurrentMixtureOptions(
807     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpdateTextContentOnly)
808 {
809     uint32_t totalOptionCount = GetOptionCount();
810     if (totalOptionCount == 0) {
811         return;
812     }
813     uint32_t currentIndex = GetCurrentIndex();
814     currentIndex = currentIndex % totalOptionCount;
815     uint32_t showCount = GetShowOptionCount();
816     auto middleIndex = showCount / 2; // the center option is selected.
817     auto host = GetHost();
818     CHECK_NULL_VOID(host);
819     auto child = host->GetChildren();
820     auto iter = child.begin();
821     if (child.size() != showCount) {
822         return;
823     }
824     for (uint32_t index = 0; index < showCount; index++) {
825         uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
826         RangeContent optionValue = options_[optionIndex];
827         int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
828         int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
829         bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
830         auto linearLayoutNode = DynamicCast<FrameNode>(*iter);
831         CHECK_NULL_VOID(linearLayoutNode);
832         auto children = linearLayoutNode->GetChildren();
833         if (children.size() != MIXTURE_CHILD_COUNT) {
834             continue;
835         }
836         auto iconNode = DynamicCast<FrameNode>(linearLayoutNode->GetFirstChild());
837         auto iconPattern = iconNode->GetPattern<ImagePattern>();
838         CHECK_NULL_VOID(iconPattern);
839         iconPattern->SetSyncLoad(true);
840         auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
841         CHECK_NULL_VOID(iconLayoutProperty);
842         auto iconLayoutDirection = iconLayoutProperty->GetNonAutoLayoutDirection();
843         CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
844         MeasureProperty layoutConstraint;
845         layoutConstraint.selfIdealSize = idealSize;
846         iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
847         MarginProperty margin;
848         margin.right = CalcLength(ICON_TEXT_SPACE);
849         bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
850         if (isRtl || iconLayoutDirection == TextDirection::RTL) {
851             margin.left = CalcLength(ICON_TEXT_SPACE);
852         }
853         iconLayoutProperty->UpdateMargin(margin);
854 
855         auto textNode = DynamicCast<FrameNode>(linearLayoutNode->GetLastChild());
856         auto textPattern = textNode->GetPattern<TextPattern>();
857         CHECK_NULL_VOID(textPattern);
858         auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
859         CHECK_NULL_VOID(textLayoutProperty);
860         UpdateTextOverflow(index == middleIndex, textLayoutProperty);
861         if (!isUpdateTextContentOnly) {
862             UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
863         }
864         if (NotLoopOptions() && !virtualIndexValidate) {
865             iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
866             textLayoutProperty->UpdateContent(u"");
867         } else {
868             textLayoutProperty->UpdateContent(optionValue.text_);
869             iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
870             iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
871         }
872         UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
873         iconNode->MarkModifyDone();
874         iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
875         textNode->MarkModifyDone();
876         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
877 
878         linearLayoutNode->GetRenderContext()->SetClipToFrame(true);
879         linearLayoutNode->MarkModifyDone();
880         linearLayoutNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
881         iter++;
882     }
883     selectedIndex_ = currentIndex;
884 }
885 
FlushAnimationTextProperties(bool isDown)886 void TextPickerColumnPattern::FlushAnimationTextProperties(bool isDown)
887 {
888     const size_t size = animationProperties_.size();
889     if (size == 0) {
890         return;
891     }
892     if (isDown) {
893         for (size_t i = 0; i < size; i++) {
894             if (i > 0) {
895                 animationProperties_[i - 1].upFontSize = animationProperties_[i].upFontSize;
896                 animationProperties_[i - 1].fontSize = animationProperties_[i].fontSize;
897                 animationProperties_[i - 1].downFontSize = animationProperties_[i].downFontSize;
898                 animationProperties_[i - 1].upColor = animationProperties_[i].upColor;
899                 animationProperties_[i - 1].currentColor = animationProperties_[i].currentColor;
900                 animationProperties_[i - 1].downColor = animationProperties_[i].downColor;
901             }
902             if (i + 1 == size) {
903                 animationProperties_[i].upFontSize = animationProperties_[i].fontSize;
904                 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
905                 animationProperties_[i].downFontSize = Dimension();
906                 animationProperties_[i].upColor = animationProperties_[i].currentColor;
907                 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
908                 animationProperties_[i].currentColor =
909                     colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
910                 animationProperties_[i].downColor = Color();
911             }
912         }
913     } else {
914         for (size_t i = size - 1;; i--) {
915             if (i == 0) {
916                 animationProperties_[i].upFontSize = Dimension();
917                 animationProperties_[i].downFontSize = animationProperties_[i].fontSize;
918                 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
919                 animationProperties_[i].upColor = Color();
920                 animationProperties_[i].downColor = animationProperties_[i].currentColor;
921                 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
922                 animationProperties_[i].currentColor =
923                     colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
924                 break;
925             } else {
926                 animationProperties_[i].upFontSize = animationProperties_[i - 1].upFontSize;
927                 animationProperties_[i].fontSize = animationProperties_[i - 1].fontSize;
928                 animationProperties_[i].downFontSize = animationProperties_[i - 1].downFontSize;
929                 animationProperties_[i].upColor = animationProperties_[i - 1].upColor;
930                 animationProperties_[i].currentColor = animationProperties_[i - 1].currentColor;
931                 animationProperties_[i].downColor = animationProperties_[i - 1].downColor;
932             }
933         }
934     }
935 }
936 
UpdateDisappearTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)937 void TextPickerColumnPattern::UpdateDisappearTextProperties(const RefPtr<PickerTheme>& pickerTheme,
938     const RefPtr<TextLayoutProperty>& textLayoutProperty,
939     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
940 {
941     UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
942     auto normalOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize();
943     textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDisappearColor().value_or(
944         pickerTheme->GetOptionStyle(false, false).GetTextColor()));
945     if (textPickerLayoutProperty->HasDisappearFontSize()) {
946         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetDisappearFontSize().value());
947         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
948         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
949     } else {
950         textLayoutProperty->UpdateAdaptMaxFontSize(normalOptionSize);
951         textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(false, false).GetAdaptMinFontSize());
952     }
953     textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetDisappearWeight().value_or(
954         pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
955     auto fontFamilyVector = textPickerLayoutProperty->GetDisappearFontFamily().value_or(
956         pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
957     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
958     textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetDisappearFontStyle().value_or(
959         pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
960 }
961 
UpdateCandidateTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)962 void TextPickerColumnPattern::UpdateCandidateTextProperties(const RefPtr<PickerTheme>& pickerTheme,
963     const RefPtr<TextLayoutProperty>& textLayoutProperty,
964     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
965 {
966     UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
967     auto focusOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
968     textLayoutProperty->UpdateTextColor(
969         textPickerLayoutProperty->GetColor().value_or(pickerTheme->GetOptionStyle(false, false).GetTextColor()));
970     if (textPickerLayoutProperty->HasFontSize()) {
971         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetFontSize().value());
972         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
973         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
974     } else {
975         textLayoutProperty->UpdateAdaptMaxFontSize(focusOptionSize);
976         textLayoutProperty->UpdateAdaptMinFontSize(
977             pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize() - FOCUS_SIZE);
978     }
979     textLayoutProperty->UpdateFontWeight(
980         textPickerLayoutProperty->GetWeight().value_or(pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
981     auto fontFamilyVector = textPickerLayoutProperty->GetFontFamily().value_or(
982         pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
983     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
984     textLayoutProperty->UpdateItalicFontStyle(
985         textPickerLayoutProperty->GetFontStyle().value_or(pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
986 }
987 
UpdateSelectedTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)988 void TextPickerColumnPattern::UpdateSelectedTextProperties(const RefPtr<PickerTheme>& pickerTheme,
989     const RefPtr<TextLayoutProperty>& textLayoutProperty,
990     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
991 {
992     UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
993     auto selectedOptionSize = pickerTheme->GetOptionStyle(true, false).GetFontSize();
994 
995     if (pickerTheme->IsCircleDial() && !isUserSetSelectColor_) {
996         if (selectedMarkPaint_) {
997             textLayoutProperty->UpdateTextColor(pickerTheme->GetOptionStyle(true, true).GetTextColor());
998         } else {
999             textLayoutProperty->UpdateTextColor(pickerTheme->GetOptionStyle(false, false).GetTextColor());
1000         }
1001     } else {
1002         textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetSelectedColor().value_or(
1003             pickerTheme->GetOptionStyle(true, false).GetTextColor()));
1004     }
1005 
1006     if (textPickerLayoutProperty->HasSelectedFontSize()) {
1007         textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetSelectedFontSize().value());
1008         textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
1009         textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
1010     } else {
1011         textLayoutProperty->UpdateAdaptMaxFontSize(selectedOptionSize);
1012         textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize());
1013     }
1014     textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetSelectedWeight().value_or(
1015         pickerTheme->GetOptionStyle(true, false).GetFontWeight()));
1016     auto fontFamilyVector = textPickerLayoutProperty->GetSelectedFontFamily().value_or(
1017         pickerTheme->GetOptionStyle(true, false).GetFontFamilies());
1018     textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
1019     textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetSelectedFontStyle().value_or(
1020         pickerTheme->GetOptionStyle(true, false).GetFontStyle()));
1021 }
1022 
UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,uint32_t currentIndex,uint32_t middleIndex)1023 void TextPickerColumnPattern::UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1024     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex)
1025 {
1026     CHECK_NULL_VOID(textLayoutProperty);
1027     CHECK_NULL_VOID(textPickerLayoutProperty);
1028     auto host = GetHost();
1029     CHECK_NULL_VOID(host);
1030     auto context = host->GetContext();
1031     CHECK_NULL_VOID(context);
1032     auto theme = context->GetTheme<TextTheme>();
1033     CHECK_NULL_VOID(theme);
1034     auto textStyle = theme->GetTextStyle();
1035     textLayoutProperty->UpdateFontSize(
1036         textPickerLayoutProperty->GetDefaultFontSize().value_or(textStyle.GetFontSize()));
1037     textLayoutProperty->UpdateFontWeight(
1038         textPickerLayoutProperty->GetDefaultWeight().value_or(textStyle.GetFontWeight()));
1039     textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDefaultColor().value_or(textStyle.GetTextColor()));
1040     textLayoutProperty->UpdateFontFamily(
1041         textPickerLayoutProperty->GetDefaultFontFamily().value_or(textStyle.GetFontFamilies()));
1042     textLayoutProperty->UpdateItalicFontStyle(
1043         textPickerLayoutProperty->GetDefaultFontStyle().value_or(textStyle.GetFontStyle()));
1044     textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetDefaultMinFontSize().value_or(Dimension()));
1045     textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetDefaultMaxFontSize().value_or(Dimension()));
1046     if (textPickerLayoutProperty->GetDefaultTextOverflow().has_value() &&
1047         textPickerLayoutProperty->GetDefaultTextOverflow().value() != TextOverflow::MARQUEE) {
1048         textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetDefaultTextOverflow().value());
1049     } else {
1050         textLayoutProperty->UpdateTextOverflow(textStyle.GetTextOverflow());
1051     }
1052     textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
1053     textLayoutProperty->UpdateMaxLines(1);
1054     textLayoutProperty->UpdateAlignment(Alignment::CENTER);
1055 
1056     CHECK_EQUAL_VOID(optionProperties_.empty(), true);
1057     InitTextHeightAndFontHeight(currentIndex, middleIndex, optionProperties_[currentIndex]);
1058 
1059     bool isLandscape = static_cast<int32_t>(GetShowOptionCount()) == OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER;
1060     SetOptionShiftDistanceByIndex(currentIndex, isLandscape);
1061 }
1062 
AddAnimationTextProperties(uint32_t currentIndex,const RefPtr<TextLayoutProperty> & textLayoutProperty)1063 void TextPickerColumnPattern::AddAnimationTextProperties(
1064     uint32_t currentIndex, const RefPtr<TextLayoutProperty>& textLayoutProperty)
1065 {
1066     TextProperties properties{};
1067     if (textLayoutProperty->HasFontSize()) {
1068         MeasureContext measureContext;
1069         measureContext.textContent = MEASURE_STRING;
1070         measureContext.fontSize = textLayoutProperty->GetFontSize().value();
1071         if (textLayoutProperty->HasFontFamily()) {
1072             auto fontFamilyVector = textLayoutProperty->GetFontFamily().value();
1073             if (fontFamilyVector.empty()) {
1074                 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
1075             } else {
1076                 measureContext.fontFamily = fontFamilyVector[0];
1077             }
1078         } else {
1079             measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
1080         }
1081         auto size = MeasureUtil::MeasureTextSize(measureContext);
1082         if (!optionProperties_.empty()) {
1083             optionProperties_[currentIndex].fontheight = size.Height();
1084             if (optionProperties_[currentIndex].fontheight > optionProperties_[currentIndex].height) {
1085                 optionProperties_[currentIndex].fontheight = optionProperties_[currentIndex].height;
1086             }
1087         }
1088         bool isLandscape = static_cast<int32_t>(GetShowOptionCount()) ==
1089                            (OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER);
1090         SetOptionShiftDistanceByIndex(currentIndex, isLandscape);
1091         properties.fontSize = Dimension(textLayoutProperty->GetFontSize().value().ConvertToPx());
1092     }
1093     if (textLayoutProperty->HasTextColor()) {
1094         properties.currentColor = textLayoutProperty->GetTextColor().value();
1095     }
1096     if (textLayoutProperty->HasFontWeight()) {
1097         properties.fontWeight = textLayoutProperty->GetFontWeight().value();
1098     }
1099     if (currentIndex > 0) {
1100         properties.upFontSize = animationProperties_[currentIndex - 1].fontSize;
1101         animationProperties_[currentIndex - 1].downFontSize = properties.fontSize;
1102 
1103         properties.upColor = animationProperties_[currentIndex - 1].currentColor;
1104         animationProperties_[currentIndex - 1].downColor = properties.currentColor;
1105 
1106         properties.upFontWeight = animationProperties_[currentIndex - 1].fontWeight;
1107         animationProperties_[currentIndex - 1].downFontWeight = properties.fontWeight;
1108     }
1109     animationProperties_.emplace_back(properties);
1110 }
1111 
UpdatePickerTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,uint32_t currentIndex,uint32_t middleIndex,uint32_t showCount)1112 void TextPickerColumnPattern::UpdatePickerTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1113     const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex,
1114     uint32_t showCount)
1115 {
1116     if (textPickerLayoutProperty && textPickerLayoutProperty->GetDisableTextStyleAnimation().value_or(false)) {
1117         UpdateDefaultTextProperties(textLayoutProperty, textPickerLayoutProperty, currentIndex, middleIndex);
1118         return;
1119     }
1120     auto host = GetHost();
1121     CHECK_NULL_VOID(host);
1122     auto context = host->GetContext();
1123     CHECK_NULL_VOID(context);
1124     auto pickerTheme = context->GetTheme<PickerTheme>(GetThemeScopeId());
1125     CHECK_NULL_VOID(pickerTheme);
1126     if (currentIndex == middleIndex) {
1127         UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1128         textLayoutProperty->UpdateAlignment(Alignment::CENTER);
1129     } else if ((currentIndex == middleIndex + 1) || (currentIndex == middleIndex - 1)) {
1130         UpdateCandidateTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1131     } else {
1132         UpdateDisappearTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1133     }
1134     if (currentIndex < middleIndex) {
1135         textLayoutProperty->UpdateAlignment(Alignment::TOP_CENTER);
1136     } else if (currentIndex > middleIndex) {
1137         textLayoutProperty->UpdateAlignment(Alignment::BOTTOM_CENTER);
1138     }
1139     textLayoutProperty->UpdateMaxLines(1);
1140     textLayoutProperty->UpdateTextOverflow(isTextFadeOut_ ? TextOverflow::MARQUEE : TextOverflow::CLIP);
1141     AddAnimationTextProperties(currentIndex, textLayoutProperty);
1142 }
1143 
SetSelectColor(const RefPtr<TextLayoutProperty> & textLayoutProperty,const Color & startColor,const Color & endColor,const float & percent,bool isEqual)1144 void TextPickerColumnPattern::SetSelectColor(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1145     const Color& startColor, const Color& endColor, const float& percent, bool isEqual)
1146 {
1147     auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
1148     Color updateColor = colorEvaluator->Evaluate(startColor, endColor, percent);
1149     textLayoutProperty->UpdateTextColor(updateColor);
1150 }
1151 
TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty> & textLayoutProperty,uint32_t idx,uint32_t showCount,bool isDown,double scaleSize)1152 void TextPickerColumnPattern::TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1153     uint32_t idx, uint32_t showCount, bool isDown, double scaleSize)
1154 {
1155     uint32_t deltaIdx = static_cast<uint32_t>(GetOverScrollDeltaIndex());
1156     auto index = idx;
1157     bool isEqual = false;
1158     if (GreatNotEqual(scrollDelta_, 0.0f)) {
1159         index = index + deltaIdx;
1160     } else {
1161         if (index < deltaIdx) {
1162             return;
1163         }
1164         index = index - deltaIdx;
1165     }
1166     auto percent = distancePercent_ - deltaIdx;
1167     auto scale = scaleSize - deltaIdx;
1168 
1169     if (index >= animationProperties_.size()) {
1170         return;
1171     }
1172     Dimension startFontSize = animationProperties_[index].fontSize;
1173     Color startColor = animationProperties_[index].currentColor;
1174     if ((!index && isDown) || ((index == (showCount - 1)) && !isDown)) {
1175         textLayoutProperty->UpdateFontSize(startFontSize);
1176         textLayoutProperty->UpdateTextColor(startColor);
1177         return;
1178     }
1179     Dimension endFontSize;
1180     Color endColor;
1181     if (GreatNotEqual(scrollDelta_, 0.0)) {
1182         endFontSize = animationProperties_[index].downFontSize;
1183         endColor = animationProperties_[index].downColor;
1184         if (GreatOrEqual(scale, FONTWEIGHT)) {
1185             textLayoutProperty->UpdateFontWeight(animationProperties_[index].downFontWeight);
1186         }
1187     } else {
1188         endFontSize = animationProperties_[index].upFontSize;
1189         endColor = animationProperties_[index].upColor;
1190         if (GreatOrEqual(scale, FONTWEIGHT)) {
1191             textLayoutProperty->UpdateFontWeight(animationProperties_[index].upFontWeight);
1192         }
1193     }
1194     Dimension updateSize = LinearFontSize(startFontSize, endFontSize, percent);
1195     textLayoutProperty->UpdateFontSize(updateSize);
1196     isEqual = (idx == (showCount / PICKER_SELECT_AVERAGE));
1197     SetSelectColor(textLayoutProperty, startColor, endColor, percent, isEqual);
1198     if (scale < FONTWEIGHT) {
1199         textLayoutProperty->UpdateFontWeight(animationProperties_[index].fontWeight);
1200     }
1201 }
1202 
GetOverScrollDeltaIndex() const1203 int32_t TextPickerColumnPattern::GetOverScrollDeltaIndex() const
1204 {
1205     auto deltaIdx = 0;
1206     if (NotLoopOptions() && overscroller_.IsOverScroll()) {
1207         auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1208         auto shiftDistance = optionProperties_[midIndex].nextDistance;
1209         for (auto idx = midIndex; idx < GetShowOptionCount(); idx++) {
1210             if (shiftDistance > std::abs(scrollDelta_)) {
1211                 break;
1212             }
1213             shiftDistance += optionProperties_[idx].nextDistance;
1214             deltaIdx++;
1215         }
1216     }
1217     return deltaIdx;
1218 }
1219 
UpdateTextPropertiesLinear(bool isDown,double scale)1220 void TextPickerColumnPattern::UpdateTextPropertiesLinear(bool isDown, double scale)
1221 {
1222     if (columnKind_ == ICON) {
1223         return;
1224     }
1225     auto host = GetHost();
1226     CHECK_NULL_VOID(host);
1227     uint32_t showCount = GetShowOptionCount();
1228     auto middleIndex = showCount / 2;
1229     auto child = host->GetChildren();
1230     auto iter = child.begin();
1231     if (child.size() != showCount) {
1232         return;
1233     }
1234     for (uint32_t index = 0; index < showCount; index++) {
1235         auto rangeNode = DynamicCast<FrameNode>(*iter);
1236         CHECK_NULL_VOID(rangeNode);
1237         RefPtr<TextLayoutProperty> textLayoutProperty;
1238         if (columnKind_ == TEXT) {
1239             auto textPattern = rangeNode->GetPattern<TextPattern>();
1240             CHECK_NULL_VOID(textPattern);
1241             textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1242             CHECK_NULL_VOID(textLayoutProperty);
1243             UpdateTextOverflow(index == middleIndex, textLayoutProperty);
1244             TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1245         } else if (columnKind_ == MIXTURE) {
1246             auto children = rangeNode->GetChildren();
1247             if (children.size() != MIXTURE_CHILD_COUNT) {
1248                 continue;
1249             }
1250             auto textNode = DynamicCast<FrameNode>(rangeNode->GetLastChild());
1251             auto textPattern = textNode->GetPattern<TextPattern>();
1252             textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1253             CHECK_NULL_VOID(textLayoutProperty);
1254             UpdateTextOverflow(index == middleIndex, textLayoutProperty);
1255             TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1256             textNode->MarkModifyDone();
1257             textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1258         }
1259         rangeNode->MarkModifyDone();
1260         rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1261         iter++;
1262     }
1263 }
1264 
LinearFontSize(const Dimension & startFontSize,const Dimension & endFontSize,double percent)1265 Dimension TextPickerColumnPattern::LinearFontSize(
1266     const Dimension& startFontSize, const Dimension& endFontSize, double percent)
1267 {
1268     if (percent > FONT_SIZE_PERCENT) {
1269         return startFontSize + (endFontSize - startFontSize);
1270     } else {
1271         return startFontSize + (endFontSize - startFontSize) * std::abs(percent);
1272     }
1273 }
1274 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1275 void TextPickerColumnPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1276 {
1277     CHECK_NULL_VOID(!panEvent_);
1278     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1279         auto pattern = weak.Upgrade();
1280         CHECK_NULL_VOID(pattern);
1281         if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1282             return;
1283         }
1284         pattern->HandleDragStart(event);
1285     };
1286     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1287         auto pattern = weak.Upgrade();
1288         CHECK_NULL_VOID(pattern);
1289         pattern->SetMainVelocity(event.GetMainVelocity());
1290         pattern->HandleDragMove(event);
1291     };
1292     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1293         auto pattern = weak.Upgrade();
1294         CHECK_NULL_VOID(pattern);
1295         if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1296             return;
1297         }
1298         pattern->SetMainVelocity(info.GetMainVelocity());
1299         pattern->HandleDragEnd();
1300     };
1301     auto actionCancelTask = [weak = WeakClaim(this)]() {
1302         auto pattern = weak.Upgrade();
1303         CHECK_NULL_VOID(pattern);
1304         pattern->HandleDragEnd();
1305     };
1306     PanDirection panDirection;
1307     panDirection.type = PanDirection::VERTICAL;
1308     panEvent_ = MakeRefPtr<PanEvent>(
1309         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1310     gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
1311 }
1312 
GetParentLayout() const1313 RefPtr<TextPickerLayoutProperty> TextPickerColumnPattern::GetParentLayout() const
1314 {
1315     auto host = GetHost();
1316     CHECK_NULL_RETURN(host, nullptr);
1317     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
1318     CHECK_NULL_RETURN(blendNode, nullptr);
1319     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
1320     CHECK_NULL_RETURN(stackNode, nullptr);
1321     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
1322     CHECK_NULL_RETURN(parentNode, nullptr);
1323 
1324     auto property = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
1325     return property;
1326 }
1327 
HandleDragStart(const GestureEvent & event)1328 void TextPickerColumnPattern::HandleDragStart(const GestureEvent& event)
1329 {
1330     SetSelectedMark();
1331     CHECK_NULL_VOID(GetToss());
1332     auto toss = GetToss();
1333     auto offsetY = event.GetGlobalPoint().GetY();
1334     toss->SetStart(offsetY);
1335     yLast_ = offsetY;
1336     overscroller_.SetStart(offsetY);
1337     pressed_ = true;
1338     auto frameNode = GetHost();
1339     CHECK_NULL_VOID(frameNode);
1340     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::START);
1341     // AccessibilityEventType::SCROLL_START
1342 
1343     if (animation_) {
1344         AnimationUtils::StopAnimation(animation_);
1345     }
1346 
1347     if (NotLoopOptions() && reboundAnimation_) {
1348         AnimationUtils::StopAnimation(reboundAnimation_);
1349         isReboundInProgress_ = false;
1350         overscroller_.ResetVelocity();
1351         overscroller_.SetOverScroll(scrollDelta_);
1352     }
1353 }
1354 
HandleDragMove(const GestureEvent & event)1355 void TextPickerColumnPattern::HandleDragMove(const GestureEvent& event)
1356 {
1357     if (event.GetFingerList().size() > 1) {
1358         return;
1359     }
1360     if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1361         if (InnerHandleScroll(LessNotEqual(event.GetDelta().GetY(), 0.0), true)) {
1362             HandleScrollStopEventCallback(true);
1363         }
1364         return;
1365     }
1366     animationBreak_ = false;
1367     CHECK_NULL_VOID(pressed_);
1368     CHECK_NULL_VOID(GetHost());
1369     CHECK_NULL_VOID(GetToss());
1370     auto toss = GetToss();
1371     auto offsetY =
1372         event.GetGlobalPoint().GetY() + (event.GetInputEventType() == InputEventType::AXIS ? event.GetOffsetY() : 0.0);
1373     if (NearEqual(offsetY, yLast_, MOVE_THRESHOLD)) { // if changing less than MOVE_THRESHOLD, no need to handle
1374         return;
1375     }
1376     toss->SetEnd(offsetY);
1377     UpdateColumnChildPosition(offsetY);
1378     auto frameNode = GetHost();
1379     CHECK_NULL_VOID(frameNode);
1380     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::RUNNING);
1381 }
1382 
HandleDragEnd()1383 void TextPickerColumnPattern::HandleDragEnd()
1384 {
1385     if (hapticController_) {
1386         hapticController_->Stop();
1387     }
1388     pressed_ = false;
1389     CHECK_NULL_VOID(GetToss());
1390     auto toss = GetToss();
1391     auto frameNode = GetHost();
1392     CHECK_NULL_VOID(frameNode);
1393     if (NotLoopOptions()) {
1394         frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1395         if (overscroller_.IsOverScroll()) { // Start rebound animation. Higher priority than fling
1396             CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
1397             HandleScrollStopEventCallback(true);
1398             return;
1399         }
1400     }
1401     if (toss->Play()) { // Start fling animation
1402         frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1403         // AccessibilityEventType::SCROLL_END
1404         return;
1405     }
1406     yOffset_ = 0.0;
1407     yLast_ = 0.0;
1408     if (!animationCreated_) {
1409         ScrollOption(0.0);
1410         return;
1411     }
1412     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
1413     ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1414     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
1415                                                       : optionProperties_[middleIndex].nextDistance;
1416     auto shiftThreshold = shiftDistance / HALF_NUMBER;
1417     if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
1418         InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
1419         scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
1420         if (NearZero(scrollDelta_)) {
1421             HandleScrollStopEventCallback(true);
1422         }
1423     }
1424     CreateAnimation(scrollDelta_, 0.0);
1425     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1426     if (!NearZero(scrollDelta_)) {
1427         HandleScrollStopEventCallback(true);
1428     }
1429     // AccessibilityEventType::SCROLL_END
1430 }
1431 
CreateAnimation()1432 void TextPickerColumnPattern::CreateAnimation()
1433 {
1434     CHECK_NULL_VOID(!animationCreated_);
1435     auto host = GetHost();
1436     CHECK_NULL_VOID(host);
1437     auto renderContext = host->GetRenderContext();
1438     CHECK_NULL_VOID(renderContext);
1439     auto propertyCallback = [weak = AceType::WeakClaim(this)](float value) {
1440         auto column = weak.Upgrade();
1441         CHECK_NULL_VOID(column);
1442         column->ScrollOption(value);
1443     };
1444     scrollProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
1445     renderContext->AttachNodeAnimatableProperty(scrollProperty_);
1446 
1447     auto aroundClickCallback = [weak = AceType::WeakClaim(this)](float value) {
1448         auto column = weak.Upgrade();
1449         CHECK_NULL_VOID(column);
1450         column->UpdateColumnChildPosition(value);
1451     };
1452     aroundClickProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(aroundClickCallback));
1453     renderContext->AttachNodeAnimatableProperty(aroundClickProperty_);
1454     animationCreated_ = true;
1455 }
1456 
CreateAnimation(double from,double to)1457 void TextPickerColumnPattern::CreateAnimation(double from, double to)
1458 {
1459     AnimationOption option;
1460     option.SetCurve(Curves::FAST_OUT_SLOW_IN);
1461     option.SetDuration(CLICK_ANIMATION_DURATION);
1462     scrollProperty_->Set(from);
1463     AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), to]() {
1464         auto column = weak.Upgrade();
1465         CHECK_NULL_VOID(column);
1466         column->scrollProperty_->Set(to);
1467     });
1468 }
1469 
CreateReboundAnimation(double from,double to)1470 void TextPickerColumnPattern::CreateReboundAnimation(double from, double to)
1471 {
1472     isReboundInProgress_ = true;
1473     AnimationOption option;
1474     option.SetCurve(overscroller_.GetReboundCurve());
1475     option.SetDuration(CLICK_ANIMATION_DURATION);
1476     scrollProperty_->Set(from);
1477     reboundAnimation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), to]() {
1478         auto column = weak.Upgrade();
1479         CHECK_NULL_VOID(column);
1480         column->scrollProperty_->Set(to);
1481     }, [weak = AceType::WeakClaim(this)]() { // On Finish
1482         auto column = weak.Upgrade();
1483         CHECK_NULL_VOID(column);
1484         if (column->isReboundInProgress_) {
1485             column->isReboundInProgress_ = false;
1486             column->overscroller_.Reset();
1487             column->yLast_ = 0.0;
1488             column->yOffset_ = 0.0;
1489         }
1490     });
1491 }
1492 
HandleEnterSelectedArea(double scrollDelta,float shiftDistance,ScrollDirection dir)1493 void TextPickerColumnPattern::HandleEnterSelectedArea(double scrollDelta, float shiftDistance, ScrollDirection dir)
1494 {
1495     auto shiftThreshold = shiftDistance / HALF_NUMBER;
1496     uint32_t totalOptionCount = GetOptionCount();
1497     uint32_t currentEnterIndex = GetCurrentIndex();
1498     auto isOverScroll = NotLoopOptions() && overscroller_.IsOverScroll();
1499     if (totalOptionCount == 0) {
1500         return;
1501     }
1502     if (dir == ScrollDirection::UP) {
1503         currentEnterIndex = (totalOptionCount + currentEnterIndex + 1) % totalOptionCount;
1504     } else {
1505         auto totalCountAndIndex = totalOptionCount + currentEnterIndex;
1506         currentEnterIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount;
1507     }
1508     bool isDragReverse = false;
1509     if (GreatNotEqual(std::abs(enterDelta_), std::abs(scrollDelta))) {
1510         isDragReverse = true;
1511     }
1512     enterDelta_ = (NearEqual(scrollDelta, shiftDistance)) ? 0.0 : scrollDelta;
1513     if (GreatOrEqual(std::abs(scrollDelta), std::abs(shiftThreshold)) && GetEnterIndex() != currentEnterIndex &&
1514         !isOverScroll) {
1515         SetEnterIndex(currentEnterIndex);
1516         HandleEnterSelectedAreaEventCallback(true);
1517     }
1518     if (isDragReverse && LessOrEqual(std::abs(scrollDelta), std::abs(shiftThreshold)) &&
1519         GetEnterIndex() != GetCurrentIndex() && !isOverScroll) {
1520         SetEnterIndex(GetCurrentIndex());
1521         HandleEnterSelectedAreaEventCallback(true);
1522     }
1523 }
1524 
ScrollOption(double delta)1525 void TextPickerColumnPattern::ScrollOption(double delta)
1526 {
1527     scrollDelta_ = delta;
1528     auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1529     ScrollDirection dir = GreatNotEqual(delta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1530     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1531                                                       : optionProperties_[midIndex].nextDistance;
1532     HandleEnterSelectedArea(scrollDelta_, shiftDistance, dir);
1533     distancePercent_ = delta / shiftDistance;
1534     auto textLinearPercent = 0.0;
1535     textLinearPercent = (std::abs(delta)) / (optionProperties_[midIndex].height);
1536     UpdateTextPropertiesLinear(LessNotEqual(delta, 0.0), textLinearPercent);
1537     CalcAlgorithmOffset(dir, distancePercent_);
1538     auto host = GetHost();
1539     CHECK_NULL_VOID(host);
1540     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1541 }
1542 
ResetAlgorithmOffset()1543 void TextPickerColumnPattern::ResetAlgorithmOffset()
1544 {
1545     algorithmOffset_.clear();
1546 
1547     uint32_t counts = GetShowOptionCount();
1548     for (uint32_t i = 0; i < counts; i++) {
1549         algorithmOffset_.emplace_back(0.0);
1550     }
1551 }
1552 
UpdateScrollDelta(double delta)1553 void TextPickerColumnPattern::UpdateScrollDelta(double delta)
1554 {
1555     SetCurrentOffset(delta);
1556     auto host = GetHost();
1557     CHECK_NULL_VOID(host);
1558     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1559 }
1560 
CalcAlgorithmOffset(ScrollDirection dir,double distancePercent)1561 void TextPickerColumnPattern::CalcAlgorithmOffset(ScrollDirection dir, double distancePercent)
1562 {
1563     algorithmOffset_.clear();
1564 
1565     uint32_t counts = GetShowOptionCount();
1566 
1567     for (uint32_t i = 0; i < counts; i++) {
1568         auto distance = (dir == ScrollDirection::UP) ? optionProperties_[i].prevDistance
1569                                                      : optionProperties_[i].nextDistance;
1570         auto val  = std::trunc(distance * distancePercent);
1571         algorithmOffset_.emplace_back(static_cast<int32_t>(val));
1572     }
1573 }
1574 
GetShiftDistance(int32_t index,ScrollDirection dir)1575 double TextPickerColumnPattern::GetShiftDistance(int32_t index, ScrollDirection dir)
1576 {
1577     if (optionProperties_.empty()) {
1578         return 0.0;
1579     }
1580     int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1581     if (optionCounts == 0) {
1582         return 0.0;
1583     }
1584     int32_t nextIndex = 0;
1585     auto isDown = dir == ScrollDirection::DOWN;
1586     nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1587     double distance = 0.0;
1588     switch (static_cast<OptionIndex>(index)) {
1589         case OptionIndex::COLUMN_INDEX_0: // first
1590             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1591                                                       : (0.0 - optionProperties_[index].height);
1592             break;
1593         case OptionIndex::COLUMN_INDEX_1:
1594             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1595                                                       : (0.0 - optionProperties_[nextIndex].height);
1596             break;
1597         case OptionIndex::COLUMN_INDEX_2:
1598             distance = GetUpCandidateDistance(index, nextIndex, dir);
1599             break;
1600 
1601         case OptionIndex::COLUMN_INDEX_3:
1602             distance = GetSelectedDistance(index, nextIndex, dir);
1603             break;
1604 
1605         case OptionIndex::COLUMN_INDEX_4:
1606             distance = GetDownCandidateDistance(index, nextIndex, dir);
1607             break;
1608         case OptionIndex::COLUMN_INDEX_5:
1609             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1610                                                       : (0.0 - optionProperties_[nextIndex].height);
1611             break;
1612         case OptionIndex::COLUMN_INDEX_6: // last
1613             distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1614                                                       : (0.0 - optionProperties_[nextIndex].height);
1615             break;
1616         default:
1617             break;
1618     }
1619 
1620     return distance;
1621 }
1622 
IsDisableTextStyleAnimation() const1623 bool TextPickerColumnPattern::IsDisableTextStyleAnimation() const
1624 {
1625     RefPtr<TextPickerLayoutProperty> layout = GetParentLayout();
1626     CHECK_NULL_RETURN(layout, false);
1627     return layout->GetDisableTextStyleAnimation().value_or(false);
1628 }
1629 
GetSelectedDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1630 double TextPickerColumnPattern::GetSelectedDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1631 {
1632     double distance = 0.0;
1633     double val = 0.0;
1634     if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1635         if (GreatOrEqual(optionProperties_[nextIndex].fontheight, optionProperties_[nextIndex].height)) {
1636             distance = (dir == ScrollDirection::UP) ?
1637                 - optionProperties_[nextIndex].height : optionProperties_[index].height;
1638         } else {
1639             val = optionProperties_[index].height / HALF_NUMBER + optionProperties_[nextIndex].height -
1640                   optionProperties_[nextIndex].fontheight / HALF_NUMBER;
1641             val = std::round(val);
1642             distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1643         }
1644     } else {
1645         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1646         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1647     }
1648     return distance;
1649 }
1650 
GetUpCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1651 double TextPickerColumnPattern::GetUpCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1652 {
1653     double distance = 0.0;
1654     double val = 0.0;
1655     // the index of last element in optionProperties_. return -1 while the arraySize equals 0.
1656     auto maxIndex = static_cast<int32_t>(optionProperties_.size()) - 1;
1657     auto minIndex = 0;
1658     if (index > maxIndex || index < minIndex || nextIndex > maxIndex || nextIndex < minIndex) {
1659         return distance;
1660     }
1661     if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1662         if (dir == ScrollDirection::UP) {
1663             distance = -optionProperties_[nextIndex].height;
1664         } else {
1665             val = optionProperties_[index].height +
1666                   (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1667             distance = std::round(val);
1668         }
1669     } else {
1670         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1671         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1672     }
1673     return distance;
1674 }
1675 
GetDownCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1676 double TextPickerColumnPattern::GetDownCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1677 {
1678     double distance = 0.0;
1679     double val = 0.0;
1680     if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1681         if (dir == ScrollDirection::DOWN) {
1682             distance = optionProperties_[index].height;
1683         } else {
1684             val = optionProperties_[index].height +
1685                   (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1686             if (GreatNotEqual(optionProperties_[nextIndex].fontheight, optionProperties_[index].height)) {
1687                 val = val + (optionProperties_[nextIndex].fontheight - optionProperties_[index].height);
1688             }
1689             distance = - std::round(val);
1690         }
1691     } else {
1692         val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1693         distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1694     }
1695     return distance;
1696 }
1697 
GetShiftDistanceForLandscape(int32_t index,ScrollDirection dir)1698 double TextPickerColumnPattern::GetShiftDistanceForLandscape(int32_t index, ScrollDirection dir)
1699 {
1700     int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1701     if (optionCounts == 0) {
1702         return 0.0;
1703     }
1704     int32_t nextIndex = 0;
1705     auto isDown = dir == ScrollDirection::DOWN;
1706     nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1707     double distance = 0.0;
1708     switch (static_cast<OptionIndex>(index)) {
1709         case OptionIndex::COLUMN_INDEX_0:
1710             distance = GetUpCandidateDistance(index, nextIndex, dir);
1711             break;
1712 
1713         case OptionIndex::COLUMN_INDEX_1:
1714             distance = GetSelectedDistance(index, nextIndex, dir);
1715             break;
1716 
1717         case OptionIndex::COLUMN_INDEX_2:
1718             distance = GetDownCandidateDistance(index, nextIndex, dir);
1719             break;
1720         default:
1721             break;
1722     }
1723 
1724     return distance;
1725 }
1726 
SetOptionShiftDistanceByIndex(int32_t index,const bool isLandscape)1727 void TextPickerColumnPattern::SetOptionShiftDistanceByIndex(int32_t index, const bool isLandscape)
1728 {
1729     TextPickerOptionProperty& prop = optionProperties_[index];
1730     if (isLandscape) {
1731         prop.prevDistance = GetShiftDistanceForLandscape(index, ScrollDirection::UP);
1732         prop.nextDistance = GetShiftDistanceForLandscape(index, ScrollDirection::DOWN);
1733     } else {
1734         prop.prevDistance = GetShiftDistance(index, ScrollDirection::UP);
1735         prop.nextDistance = GetShiftDistance(index, ScrollDirection::DOWN);
1736     }
1737 }
1738 
SetOptionShiftDistance()1739 void TextPickerColumnPattern::SetOptionShiftDistance()
1740 {
1741     CHECK_EQUAL_VOID(optionProperties_.empty(), true);
1742     int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
1743     bool isLandscape = itemCounts == OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER;
1744     for (int32_t i = 0; i < itemCounts; i++) {
1745         SetOptionShiftDistanceByIndex(i, isLandscape);
1746     }
1747 }
1748 
UpdateToss(double offsetY)1749 void TextPickerColumnPattern::UpdateToss(double offsetY)
1750 {
1751     UpdateColumnChildPosition(offsetY);
1752 }
1753 
TossStoped()1754 void TextPickerColumnPattern::TossStoped()
1755 {
1756     yOffset_ = 0.0;
1757     yLast_ = 0.0;
1758     ScrollOption(0.0);
1759 }
1760 
TossAnimationStoped()1761 void TextPickerColumnPattern::TossAnimationStoped()
1762 {
1763     if (hapticController_) {
1764         hapticController_->Stop();
1765     }
1766     yLast_ = 0.0;
1767     ScrollOption(0.0);
1768 }
1769 
GetSelectedObject(bool isColumnChange,int32_t status) const1770 std::string TextPickerColumnPattern::GetSelectedObject(bool isColumnChange, int32_t status) const
1771 {
1772     auto host = GetHost();
1773     CHECK_NULL_RETURN(host, "");
1774     auto value = GetOption(GetSelected());
1775     auto index = GetSelected();
1776     if (isColumnChange) {
1777         value = GetCurrentText();
1778         index = GetCurrentIndex();
1779     }
1780 
1781     auto context = host->GetContext();
1782     CHECK_NULL_RETURN(context, "");
1783 
1784     if (context->GetIsDeclarative()) {
1785         return std::string("{\"value\":") + "\"" + value + "\"" + ",\"index\":" + std::to_string(index) +
1786                ",\"status\":" + std::to_string(status) + "}";
1787     } else {
1788         return std::string("{\"newValue\":") + "\"" + value + "\"" + ",\"newSelected\":" + std::to_string(index) +
1789                ",\"status\":" + std::to_string(status) + "}";
1790     }
1791 }
1792 
ResetTotalDelta()1793 void TextPickerColumnPattern::ResetTotalDelta()
1794 {
1795     totalDragDelta_ = 0.0;
1796 }
1797 
SpringCurveTailMoveProcess(bool useRebound,double & dragDelta)1798 bool TextPickerColumnPattern::SpringCurveTailMoveProcess(bool useRebound, double& dragDelta)
1799 {
1800     if (useRebound) {
1801         return false;
1802     }
1803     auto toss = GetToss();
1804     if (toss && toss->GetTossPlaying()) {
1805         if (std::abs(dragDelta) < CURVE_MOVE_THRESHOLD) {
1806             dragDelta = dragDelta > 0 ? CURVE_MOVE_THRESHOLD : -CURVE_MOVE_THRESHOLD;
1807         }
1808         totalDragDelta_ += dragDelta;
1809         if (std::abs(totalDragDelta_) >= std::abs(toss->GetTossEndPosition())) {
1810             dragDelta -= (totalDragDelta_ - toss->GetTossEndPosition());
1811             ResetTotalDelta();
1812             return true;
1813         }
1814     }
1815     return false;
1816 }
1817 
SpringCurveTailEndProcess(bool useRebound,bool stopMove)1818 void TextPickerColumnPattern::SpringCurveTailEndProcess(bool useRebound, bool stopMove)
1819 {
1820     if (useRebound || !stopMove) {
1821         return;
1822     }
1823     auto toss = GetToss();
1824     if (toss) {
1825         toss->SetTossPlaying(false);
1826         toss->StopTossAnimation();
1827     }
1828 }
1829 
UpdateColumnChildPosition(double offsetY)1830 void TextPickerColumnPattern::UpdateColumnChildPosition(double offsetY)
1831 {
1832     double dragDelta = offsetY - yLast_;
1833     auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1834     ScrollDirection dir = GreatNotEqual(dragDelta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1835     auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1836                                                       : optionProperties_[midIndex].nextDistance;
1837     auto useRebound = NotLoopOptions();
1838     auto stopMove = SpringCurveTailMoveProcess(useRebound, dragDelta);
1839     offsetCurSet_ = 0.0;
1840 
1841     if (hapticController_ && isShow_) {
1842         if (isEnableHaptic_) {
1843             hapticController_->HandleDelta(dragDelta);
1844         }
1845     }
1846     StopHapticController();
1847     // the abs of drag delta is less than jump interval.
1848     dragDelta = GetDragDeltaLessThanJumpInterval(offsetY, dragDelta, useRebound, shiftDistance);
1849 
1850     // Set options position
1851     ScrollOption(dragDelta);
1852     offsetCurSet_ = dragDelta;
1853     yOffset_ = dragDelta;
1854     yLast_ = offsetY;
1855 
1856     if (useRebound && !pressed_ && isTossStatus_ && !isReboundInProgress_ && overscroller_.IsOverScroll()) {
1857         overscroller_.UpdateTossSpring(offsetY);
1858         if (overscroller_.ShouldStartRebound()) {
1859             auto toss = GetToss();
1860             CHECK_NULL_VOID(toss);
1861             toss->StopTossAnimation(); // Stop fling animation and start rebound animation implicitly
1862         }
1863     }
1864     SpringCurveTailEndProcess(useRebound, stopMove);
1865 }
1866 
GetDragDeltaLessThanJumpInterval(double offsetY,float originalDragDelta,bool useRebound,float shiftDistance)1867 double TextPickerColumnPattern::GetDragDeltaLessThanJumpInterval(
1868     double offsetY, float originalDragDelta, bool useRebound, float shiftDistance)
1869 {
1870     double dragDelta = originalDragDelta + yOffset_;
1871     auto isOverScroll = useRebound && overscroller_.IsOverScroll();
1872     if (NearEqual(std::abs(dragDelta), std::abs(shiftDistance)) && !NearZero(dragDelta)) {
1873         dragDelta = std::abs(dragDelta) / dragDelta * std::abs(shiftDistance);
1874     }
1875     if ((std::abs(dragDelta) >= std::abs(shiftDistance)) && !isOverScroll) {
1876         int32_t shiftDistanceCount = static_cast<int>(std::abs(dragDelta) / std::abs(shiftDistance));
1877         double additionalShift = dragDelta - shiftDistanceCount * shiftDistance;
1878         if (GreatNotEqual(std::abs(additionalShift), std::abs(dragDelta))) {
1879             additionalShift = dragDelta + shiftDistanceCount * shiftDistance;
1880         }
1881         for (int32_t i = 0; i < shiftDistanceCount; i++) {
1882             ScrollOption(shiftDistance);
1883             InnerHandleScroll(dragDelta < 0, true, false);
1884         }
1885         dragDelta = additionalShift;
1886         if (NearZero(dragDelta)) {
1887             HandleScrollStopEventCallback(true);
1888         }
1889     }
1890     if (useRebound && !isReboundInProgress_) {
1891         if (overscroller_.ApplyCurrentOffset(yLast_, offsetY, dragDelta)) {
1892             dragDelta =
1893                 overscroller_.IsBackOverScroll() ? overscroller_.GetBackScroll() : overscroller_.GetOverScroll();
1894         }
1895     }
1896     return dragDelta;
1897 }
1898 
CanMove(bool isDown) const1899 bool TextPickerColumnPattern::CanMove(bool isDown) const
1900 {
1901     if (!NotLoopOptions()) {
1902         return true;
1903     }
1904     auto host = GetHost();
1905     CHECK_NULL_RETURN(host, false);
1906     int totalOptionCount = static_cast<int>(GetOptionCount());
1907     int currentIndex = static_cast<int>(GetCurrentIndex());
1908     int nextVirtualIndex = isDown ? currentIndex + 1 : currentIndex - 1;
1909     return nextVirtualIndex >= 0 && nextVirtualIndex < totalOptionCount;
1910 }
1911 
NotLoopOptions() const1912 bool TextPickerColumnPattern::NotLoopOptions() const
1913 {
1914     RefPtr<TextPickerLayoutProperty> layout = GetParentLayout();
1915     CHECK_NULL_RETURN(layout, false);
1916     bool canLoop = layout->GetCanLoop().value_or(true);
1917     return !canLoop;
1918 }
1919 
InnerHandleScroll(bool isDown,bool isUpatePropertiesOnly,bool isUpdateAnimationProperties)1920 bool TextPickerColumnPattern::InnerHandleScroll(
1921     bool isDown, bool isUpatePropertiesOnly, bool isUpdateAnimationProperties)
1922 {
1923     auto host = GetHost();
1924     CHECK_NULL_RETURN(host, false);
1925     auto totalOptionCount = GetOptionCount();
1926     if (totalOptionCount == 0) {
1927         return false;
1928     }
1929 
1930     if (NotLoopOptions() && ((isDown && currentIndex_ == totalOptionCount - 1) || (!isDown && currentIndex_ == 0))) {
1931         return false;
1932     }
1933 
1934     uint32_t currentIndex = GetCurrentIndex();
1935     if (isDown) {
1936         currentIndex = (totalOptionCount + currentIndex + 1) % totalOptionCount; // index add one
1937     } else {
1938         auto totalCountAndIndex = totalOptionCount + currentIndex;
1939         currentIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount; // index reduce one
1940     }
1941     SetCurrentIndex(currentIndex);
1942     if (hapticController_ && isEnableHaptic_) {
1943         hapticController_->PlayOnce();
1944     }
1945     FlushCurrentOptions(isDown, isUpatePropertiesOnly, isUpdateAnimationProperties);
1946     HandleChangeCallback(isDown, true);
1947     HandleEventCallback(true);
1948 
1949     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1950     host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE);
1951     return true;
1952 }
1953 
OnKeyEvent(const KeyEvent & event)1954 bool TextPickerColumnPattern::OnKeyEvent(const KeyEvent& event)
1955 {
1956     if (event.action != KeyAction::DOWN) {
1957         return false;
1958     }
1959     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
1960         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
1961         HandleDirectionKey(event.code);
1962         return true;
1963     }
1964     return false;
1965 }
1966 
HandleDirectionKey(KeyCode code)1967 bool TextPickerColumnPattern::HandleDirectionKey(KeyCode code)
1968 {
1969     auto host = GetHost();
1970     CHECK_NULL_RETURN(host, false);
1971     auto currentIndex = GetCurrentIndex();
1972     auto totalOptionCount = GetOptionCount();
1973     if (totalOptionCount == 0) {
1974         return false;
1975     }
1976     if (code == KeyCode::KEY_DPAD_UP) {
1977         auto totalCountAndIndex = totalOptionCount + currentIndex;
1978         SetCurrentIndex((totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount);
1979         FlushCurrentOptions();
1980         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1981         return true;
1982     }
1983     if (code == KeyCode::KEY_DPAD_DOWN) {
1984         SetCurrentIndex((totalOptionCount + currentIndex + 1) % totalOptionCount);
1985         FlushCurrentOptions(true);
1986         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1987         return true;
1988     }
1989     return false;
1990 }
SetAccessibilityAction()1991 void TextPickerColumnPattern::SetAccessibilityAction()
1992 {
1993     auto host = GetHost();
1994     CHECK_NULL_VOID(host);
1995     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1996     CHECK_NULL_VOID(accessibilityProperty);
1997     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1998         const auto& pattern = weakPtr.Upgrade();
1999         CHECK_NULL_VOID(pattern);
2000         CHECK_NULL_VOID(pattern->animationCreated_);
2001         if (!pattern->CanMove(true)) {
2002             return;
2003         }
2004         pattern->InnerHandleScroll(true);
2005         pattern->CreateAnimation(0.0 - pattern->jumpInterval_, 0.0);
2006         pattern->HandleScrollStopEventCallback(true);
2007         // AccessibilityEventType::SCROLL_END
2008     });
2009 
2010     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
2011         const auto& pattern = weakPtr.Upgrade();
2012         CHECK_NULL_VOID(pattern);
2013         CHECK_NULL_VOID(pattern->animationCreated_);
2014         if (!pattern->CanMove(false)) {
2015             return;
2016         }
2017         pattern->InnerHandleScroll(false);
2018         pattern->CreateAnimation(pattern->jumpInterval_, 0.0);
2019         pattern->HandleScrollStopEventCallback(true);
2020         // AccessibilityEventType::SCROLL_END
2021     });
2022 }
2023 
OnAroundButtonClick(RefPtr<EventParam> param)2024 void TextPickerColumnPattern::OnAroundButtonClick(RefPtr<EventParam> param)
2025 {
2026     if (clickBreak_) {
2027         return;
2028     }
2029     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2030     int32_t step = param->itemIndex - middleIndex;
2031     if (step != 0) {
2032         if (animation_) {
2033             AnimationUtils::StopAnimation(animation_);
2034             yOffset_ = 0.0;
2035         }
2036 
2037         int32_t index = static_cast<int32_t>(currentIndex_) + step;
2038         auto overFirst = index < 0 && step < 0;
2039         auto overLast =
2040             index > static_cast<int32_t>(GetOptionCount() ? GetOptionCount() - 1 : 0) && step > 0;
2041         if (NotLoopOptions() && (overscroller_.IsOverScroll() || overFirst || overLast)) {
2042             return;
2043         }
2044 
2045         double distance =
2046             (step > 0 ? optionProperties_[middleIndex].prevDistance : optionProperties_[middleIndex].nextDistance) *
2047             std::abs(step);
2048         AnimationOption option;
2049         option.SetCurve(Curves::FAST_OUT_SLOW_IN);
2050         option.SetDuration(CLICK_ANIMATION_DURATION);
2051         yLast_ = 0.0;
2052         aroundClickProperty_->Set(0.0);
2053         animation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), step, distance]() {
2054             auto column = weak.Upgrade();
2055             CHECK_NULL_VOID(column);
2056             column->aroundClickProperty_->Set(step > 0 ? 0.0 - std::abs(distance) : std::abs(distance));
2057         });
2058         auto host = GetHost();
2059         CHECK_NULL_VOID(host);
2060         auto pipeline = host->GetContext();
2061         CHECK_NULL_VOID(pipeline);
2062         pipeline->RequestFrame();
2063     }
2064     SetSelectedMark();
2065 }
2066 
PlayResetAnimation()2067 void TextPickerColumnPattern::PlayResetAnimation()
2068 {
2069     int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2070     ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
2071     double shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
2072                                                         : optionProperties_[middleIndex].nextDistance;
2073     double shiftThreshold = shiftDistance / HALF_NUMBER;
2074     if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
2075         InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
2076         scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
2077         if (NearZero(scrollDelta_)) {
2078             HandleScrollStopEventCallback(true);
2079         }
2080     }
2081     CreateAnimation(scrollDelta_, 0.0);
2082     if (!NearZero(scrollDelta_)) {
2083         HandleScrollStopEventCallback(true);
2084     }
2085 }
2086 
SetCanLoop(bool isLoop)2087 void TextPickerColumnPattern::SetCanLoop(bool isLoop)
2088 {
2089     if (isLoop_ == isLoop) {
2090         return;
2091     }
2092 
2093     isLoop_ = isLoop;
2094     if (overscroller_.IsOverScroll()) {
2095         overscroller_.Reset();
2096         isReboundInProgress_ = false;
2097         yOffset_ = 0.0;
2098         ScrollOption(0.0);
2099     }
2100 
2101     if (!isLoop && isTossStatus_) {
2102         auto toss = GetToss();
2103         CHECK_NULL_VOID(toss);
2104         overscroller_.SetLoopTossOffset(toss->GetTossOffset());
2105     }
2106 }
2107 
SetSelectedMarkListener(std::function<void (int & selectedColumnId)> & listener)2108 void TextPickerColumnPattern::SetSelectedMarkListener(std::function<void(int& selectedColumnId)>& listener)
2109 {
2110     focusedListerner_ = listener;
2111     if (!circleUtils_) {
2112         circleUtils_ = new PickerColumnPatternCircleUtils<TextPickerColumnPattern>();
2113     }
2114 }
2115 
SetSelectedMarkId(const int strColumnId)2116 void TextPickerColumnPattern::SetSelectedMarkId(const int strColumnId)
2117 {
2118     selectedColumnId_ = strColumnId;
2119 }
2120 
SetSelectedMark(bool focus,bool notify,bool reRender)2121 void TextPickerColumnPattern::SetSelectedMark(bool focus, bool notify, bool reRender)
2122 {
2123     auto pipeline = GetContext();
2124     CHECK_NULL_VOID(pipeline);
2125     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2126     CHECK_NULL_VOID(pickerTheme);
2127     if (pickerTheme->IsCircleDial()) {
2128         CHECK_NULL_VOID(circleUtils_);
2129         circleUtils_->SetSelectedMark(this, pickerTheme, focus, notify, reRender);
2130     }
2131 }
2132 
SetSelectedMarkPaint(bool paint)2133 void TextPickerColumnPattern::SetSelectedMarkPaint(bool paint)
2134 {
2135     selectedMarkPaint_ = paint;
2136 }
2137 
UpdateSelectedTextColor(const RefPtr<PickerTheme> & pickerTheme)2138 void TextPickerColumnPattern::UpdateSelectedTextColor(const RefPtr<PickerTheme>& pickerTheme)
2139 {
2140     UpdateAnimationColor(pickerTheme);
2141 
2142     auto host = GetHost();
2143     CHECK_NULL_VOID(host);
2144     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2145     CHECK_NULL_VOID(blendNode);
2146     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
2147     CHECK_NULL_VOID(stackNode);
2148     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
2149     CHECK_NULL_VOID(parentNode);
2150     auto layoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
2151     CHECK_NULL_VOID(layoutProperty);
2152 
2153     auto&& child = host->GetChildren();
2154     auto iter = child.begin();
2155     CHECK_NULL_VOID(iter != child.end());
2156     std::advance (iter, GetShowOptionCount() / PICKER_SELECT_AVERAGE);
2157     CHECK_NULL_VOID(iter != child.end());
2158     auto textNode = DynamicCast<FrameNode>(*iter);
2159     CHECK_NULL_VOID(textNode);
2160     auto textPattern = textNode->GetPattern<TextPattern>();
2161     CHECK_NULL_VOID(textPattern);
2162     auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
2163     CHECK_NULL_VOID(textLayoutProperty);
2164 
2165     UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, layoutProperty);
2166 
2167     textNode->MarkDirtyNode(PROPERTY_UPDATE_DIFF);
2168     host->MarkDirtyNode(PROPERTY_UPDATE_DIFF);
2169 }
2170 
UpdateUserSetSelectColor()2171 void TextPickerColumnPattern::UpdateUserSetSelectColor()
2172 {
2173     isUserSetSelectColor_ = true;
2174     auto pipeline = GetContext();
2175     CHECK_NULL_VOID(pipeline);
2176     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2177     CHECK_NULL_VOID(pickerTheme);
2178     UpdateSelectedTextColor(pickerTheme);
2179 }
2180 
UpdateAnimationColor(const RefPtr<PickerTheme> & pickerTheme)2181 void TextPickerColumnPattern::UpdateAnimationColor(const RefPtr<PickerTheme>& pickerTheme)
2182 {
2183     CHECK_NULL_VOID(pickerTheme);
2184     auto host = GetHost();
2185     CHECK_NULL_VOID(host);
2186     auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2187     CHECK_NULL_VOID(blendNode);
2188     auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
2189     CHECK_NULL_VOID(stackNode);
2190     auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
2191     CHECK_NULL_VOID(parentNode);
2192     auto layoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
2193     CHECK_NULL_VOID(layoutProperty);
2194     Color color;
2195 
2196     if (pickerTheme->IsCircleDial() && !isUserSetSelectColor_) {
2197         if (selectedMarkPaint_) {
2198             color = pickerTheme->GetOptionStyle(true, true).GetTextColor();
2199         } else {
2200             color = pickerTheme->GetOptionStyle(false, false).GetTextColor();
2201         }
2202     } else {
2203         color = layoutProperty->GetSelectedColor().value_or(
2204             pickerTheme->GetOptionStyle(true, false).GetTextColor());
2205     }
2206 
2207     uint32_t middleIndex = GetShowOptionCount() / PICKER_SELECT_AVERAGE;
2208     if (middleIndex - NEXT_COLOUM_DIFF >= 0 && animationProperties_.size() > middleIndex) {
2209         animationProperties_[middleIndex - NEXT_COLOUM_DIFF].downColor = color;
2210         animationProperties_[middleIndex + NEXT_COLOUM_DIFF].upColor = color;
2211         animationProperties_[middleIndex].currentColor = color;
2212     }
2213 }
2214 
InitTextHeightAndFontHeight(uint32_t childIndex,uint32_t midIndex,TextPickerOptionProperty & prop)2215 void TextPickerColumnPattern::InitTextHeightAndFontHeight(uint32_t childIndex, uint32_t midIndex,
2216                                                           TextPickerOptionProperty &prop)
2217 {
2218     auto pipeline = PipelineContext::GetCurrentContext();
2219     CHECK_NULL_VOID(pipeline);
2220     auto theme = pipeline->GetTheme<PickerTheme>();
2221 
2222     MeasureContext measureContext;
2223     measureContext.textContent = MEASURE_STRING;
2224     measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
2225 
2226     if (childIndex == midIndex) {
2227         measureContext.fontSize = theme->GetOptionStyle(true, false).GetFontSize();
2228     } else if ((childIndex == (midIndex + 1)) || (childIndex == (midIndex - 1))) {
2229         measureContext.fontSize = theme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
2230     } else {
2231         measureContext.fontSize = theme->GetOptionStyle(false, false).GetFontSize();
2232     }
2233 
2234     Size size = MeasureUtil::MeasureTextSize(measureContext);
2235     prop.fontheight = size.Height();
2236     prop.height = (childIndex == midIndex) ? dividerSpacing_ : gradientHeight_;
2237 }
2238 
2239 #ifdef SUPPORT_DIGITAL_CROWN
GetSelectedColumnId()2240 int32_t& TextPickerColumnPattern::GetSelectedColumnId()
2241 {
2242     return selectedColumnId_;
2243 }
2244 
IsCrownEventEnded()2245 bool TextPickerColumnPattern::IsCrownEventEnded()
2246 {
2247     return isCrownEventEnded_;
2248 }
2249 
GetDigitalCrownSensitivity()2250 int32_t TextPickerColumnPattern::GetDigitalCrownSensitivity()
2251 {
2252     if (crownSensitivity_ == INVALID_CROWNSENSITIVITY) {
2253         auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
2254         CHECK_NULL_RETURN(pipeline, DEFAULT_CROWNSENSITIVITY);
2255         auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2256         CHECK_NULL_RETURN(pickerTheme, DEFAULT_CROWNSENSITIVITY);
2257         crownSensitivity_ = pickerTheme->GetDigitalCrownSensitivity();
2258     }
2259 
2260     return crownSensitivity_;
2261 }
2262 
SetDigitalCrownSensitivity(int32_t crownSensitivity)2263 void TextPickerColumnPattern::SetDigitalCrownSensitivity(int32_t crownSensitivity)
2264 {
2265     crownSensitivity_ = crownSensitivity;
2266 }
2267 
OnCrownEvent(const CrownEvent & event)2268 bool TextPickerColumnPattern::OnCrownEvent(const CrownEvent& event)
2269 {
2270     CHECK_NULL_RETURN(circleUtils_, false);
2271     return circleUtils_->OnCrownEvent(this, event);
2272 }
2273 
HandleCrownBeginEvent(const CrownEvent & event)2274 void TextPickerColumnPattern::HandleCrownBeginEvent(const CrownEvent& event)
2275 {
2276     auto toss = GetToss();
2277     CHECK_NULL_VOID(toss);
2278     auto offsetY = 0.0;
2279     toss->SetStart(offsetY);
2280     yLast_ = offsetY;
2281     overscroller_.SetStart(offsetY);
2282     pressed_ = true;
2283     isCrownEventEnded_ = false;
2284     auto frameNode = GetHost();
2285     CHECK_NULL_VOID(frameNode);
2286     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, yLast_, SceneStatus::START);
2287 
2288     if (animation_) {
2289         AnimationUtils::StopAnimation(animation_);
2290     }
2291 
2292     if (NotLoopOptions() && reboundAnimation_) {
2293         AnimationUtils::StopAnimation(reboundAnimation_);
2294         isReboundInProgress_ = false;
2295         overscroller_.ResetVelocity();
2296         overscroller_.SetOverScroll(scrollDelta_);
2297     }
2298 }
2299 
HandleCrownMoveEvent(const CrownEvent & event)2300 void TextPickerColumnPattern::HandleCrownMoveEvent(const CrownEvent& event)
2301 {
2302     SetMainVelocity(event.angularVelocity);
2303     animationBreak_ = false;
2304     isCrownEventEnded_ = false;
2305     CHECK_NULL_VOID(pressed_);
2306     auto toss = GetToss();
2307     CHECK_NULL_VOID(toss);
2308     CHECK_NULL_VOID(circleUtils_);
2309     auto offsetY = circleUtils_->GetCrownRotatePx(event, GetDigitalCrownSensitivity());
2310     offsetY += yLast_;
2311     if (NearEqual(offsetY, yLast_, MOVE_THRESHOLD)) { // if changing less than MOVE_THRESHOLD, no need to handle
2312         return;
2313     }
2314     toss->SetEnd(offsetY);
2315     UpdateColumnChildPosition(offsetY);
2316     auto frameNode = GetHost();
2317     CHECK_NULL_VOID(frameNode);
2318     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::RUNNING);
2319 }
2320 
HandleCrownEndEvent(const CrownEvent & event)2321 void TextPickerColumnPattern::HandleCrownEndEvent(const CrownEvent& event)
2322 {
2323     SetMainVelocity(event.angularVelocity);
2324     pressed_ = false;
2325     isCrownEventEnded_ = true;
2326     auto frameNode = GetHost();
2327     CHECK_NULL_VOID(frameNode);
2328     if (NotLoopOptions()) {
2329         frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
2330         if (overscroller_.IsOverScroll()) { // Start rebound animation. Higher priority than fling
2331             CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
2332             StopHapticController();
2333             return;
2334         }
2335     }
2336 
2337     yOffset_ = 0.0;
2338     yLast_ = 0.0;
2339     if (!animationCreated_) {
2340         ScrollOption(0.0);
2341         return;
2342     }
2343 
2344     ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0f) ? ScrollDirection::DOWN : ScrollDirection::UP;
2345     auto middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2346     auto shiftDistance = (dir == ScrollDirection::DOWN) ? optionProperties_[middleIndex].nextDistance
2347                                                         : optionProperties_[middleIndex].prevDistance;
2348     auto shiftThreshold = shiftDistance / HALF_NUMBER;
2349     if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
2350         InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
2351         scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
2352     }
2353     CreateAnimation(scrollDelta_, 0.0);
2354     frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
2355     StopHapticController();
2356 }
2357 #endif
2358 
2359 } // namespace OHOS::Ace::NG
2360