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