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