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