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/time_picker/timepicker_column_pattern.h"
17
18 #include <cstdint>
19 #include <cstdlib>
20 #include <iterator>
21 #include <list>
22
23 #include "core/components_ng/pattern/time_picker/timepicker_haptic_factory.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/font_manager.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components/common/properties/color.h"
30 #include "core/components/picker/picker_base_component.h"
31 #include "core/components_ng/base/frame_scene_status.h"
32 #include "core/components_ng/layout/layout_wrapper.h"
33 #include "core/components_ng/pattern/button/button_pattern.h"
34 #include "core/components_ng/pattern/text/text_pattern.h"
35 #include "core/components_ng/pattern/time_picker/timepicker_row_pattern.h"
36 #include "core/pipeline_ng/ui_task_scheduler.h"
37
38 namespace OHOS::Ace::NG {
39 namespace {
40 // timepicker style modification
41 constexpr Dimension PADDING_WEIGHT = 10.0_vp;
42 const Dimension FONT_SIZE = Dimension(2.0);
43 const uint32_t OPTION_COUNT_PHONE_LANDSCAPE = 3;
44 const int32_t CHILDREN_SIZE = 3;
45 const float TEXT_HEIGHT_NUMBER = 3.0f;
46 const float TEXT_HOUR24_HEIGHT_NUMBER = 9.0f;
47 const float TEXT_WEIGHT_NUMBER = 6.0f;
48 const Dimension FOCUS_SIZE = Dimension(1.0);
49 const int32_t MIDDLE_CHILD_INDEX = 2;
50 const float MOVE_DISTANCE = 5.0f;
51 constexpr int32_t HOVER_ANIMATION_DURATION = 250;
52 constexpr int32_t PRESS_ANIMATION_DURATION = 100;
53 constexpr int32_t CLICK_ANIMATION_DURATION = 300;
54 constexpr float FONTWEIGHT = 0.5f;
55 constexpr float FONT_SIZE_PERCENT = 1.0f;
56 constexpr char MEASURE_SIZE_STRING[] = "TEST";
57 constexpr int32_t HOT_ZONE_HEIGHT_CANDIDATE = 2;
58 constexpr int32_t HOT_ZONE_HEIGHT_DISAPPEAR = 4;
59 constexpr char PICKER_DRAG_SCENE[] = "picker_drag_scene";
60 } // namespace
61
OnAttachToFrameNode()62 void TimePickerColumnPattern::OnAttachToFrameNode()
63 {
64 auto host = GetHost();
65 CHECK_NULL_VOID(host);
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 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 TimePickerColumnPattern::OnDetachFromFrameNode(FrameNode* frameNode)
85 {
86 if (hapticController_) {
87 hapticController_->Stop();
88 }
89 UnregisterWindowStateChangedCallback();
90 }
91
OnModifyDone()92 void TimePickerColumnPattern::OnModifyDone()
93 {
94 auto host = GetHost();
95 auto focusHub = host->GetFocusHub();
96 CHECK_NULL_VOID(focusHub);
97 auto pipeline = GetContext();
98 CHECK_NULL_VOID(pipeline);
99 auto theme = pipeline->GetTheme<PickerTheme>();
100 pressColor_ = theme->GetPressColor();
101 hoverColor_ = theme->GetHoverColor();
102 auto showCount = GetShowCount();
103 InitOnKeyEvent(focusHub);
104 InitMouseAndPressEvent();
105 SetAccessibilityAction();
106 if (optionProperties_.empty()) {
107 auto midIndex = showCount / 2;
108 auto host = GetHost();
109 CHECK_NULL_VOID(host);
110 dividerSpacing_ = pipeline->NormalizeToPx(theme->GetDividerSpacing());
111 gradientHeight_ = static_cast<float>(pipeline->NormalizeToPx(theme->GetGradientHeight()));
112 MeasureContext measureContext;
113 measureContext.textContent = MEASURE_SIZE_STRING;
114 uint32_t childIndex = 0;
115 TimePickerOptionProperty prop;
116 while (childIndex < showCount) {
117 if (childIndex == midIndex) { // selected
118 auto selectedOptionSize = theme->GetOptionStyle(true, false).GetFontSize();
119 measureContext.fontSize = selectedOptionSize;
120 } else if ((childIndex == (midIndex + 1)) || (childIndex == (midIndex - 1))) {
121 auto focusOptionSize = theme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
122 measureContext.fontSize = focusOptionSize;
123 } else {
124 auto normalOptionSize = theme->GetOptionStyle(false, false).GetFontSize();
125 measureContext.fontSize = normalOptionSize;
126 }
127 if (childIndex == midIndex) {
128 prop.height = dividerSpacing_;
129 } else {
130 prop.height = gradientHeight_;
131 }
132 Size size = MeasureUtil::MeasureTextSize(measureContext);
133 prop.fontheight = size.Height();
134 optionProperties_.emplace_back(prop);
135 childIndex++;
136 }
137 SetOptionShiftDistance();
138 }
139 InitHapticController(host);
140 }
141
InitHapticController(const RefPtr<FrameNode> & host)142 void TimePickerColumnPattern::InitHapticController(const RefPtr<FrameNode>& host)
143 {
144 CHECK_NULL_VOID(host);
145 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
146 CHECK_NULL_VOID(blendNode);
147 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
148 CHECK_NULL_VOID(stackNode);
149 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
150 CHECK_NULL_VOID(parentNode);
151 auto timePickerRowPattern = parentNode->GetPattern<TimePickerRowPattern>();
152 CHECK_NULL_VOID(timePickerRowPattern);
153 if (timePickerRowPattern->GetIsEnableHaptic()) {
154 isEnableHaptic_ = true;
155 if (!hapticController_) {
156 auto context = parentNode->GetContext();
157 CHECK_NULL_VOID(context);
158 context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
159 auto pattern = weak.Upgrade();
160 CHECK_NULL_VOID(pattern);
161 pattern->hapticController_ = TimepickerAudioHapticFactory::GetInstance();
162 });
163 }
164 } else {
165 isEnableHaptic_ = false;
166 if (hapticController_) {
167 hapticController_->Stop();
168 }
169 }
170 }
171
RegisterWindowStateChangedCallback()172 void TimePickerColumnPattern::RegisterWindowStateChangedCallback()
173 {
174 auto host = GetHost();
175 CHECK_NULL_VOID(host);
176 auto pipeline = host->GetContext();
177 CHECK_NULL_VOID(pipeline);
178 pipeline->AddWindowStateChangedCallback(host->GetId());
179 }
180
UnregisterWindowStateChangedCallback()181 void TimePickerColumnPattern::UnregisterWindowStateChangedCallback()
182 {
183 auto host = GetHost();
184 CHECK_NULL_VOID(host);
185 auto pipeline = host->GetContext();
186 CHECK_NULL_VOID(pipeline);
187 pipeline->RemoveWindowStateChangedCallback(host->GetId());
188 }
189
OnWindowHide()190 void TimePickerColumnPattern::OnWindowHide()
191 {
192 isShow_ = false;
193 if (hapticController_) {
194 hapticController_->Stop();
195 }
196 }
197
OnWindowShow()198 void TimePickerColumnPattern::OnWindowShow()
199 {
200 isShow_ = true;
201 }
202
ParseTouchListener()203 void TimePickerColumnPattern::ParseTouchListener()
204 {
205 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
206 auto pattern = weak.Upgrade();
207 CHECK_NULL_VOID(pattern);
208 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
209 pattern->OnTouchDown();
210 pattern->SetLocalDownDistance(info.GetTouches().front().GetLocalLocation().GetDistance());
211 }
212 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
213 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
214 pattern->OnTouchUp();
215 pattern->SetLocalDownDistance(0.0f);
216 }
217 if (info.GetTouches().front().GetTouchType() == TouchType::MOVE) {
218 if (std::abs(info.GetTouches().front().GetLocalLocation().GetDistance() - pattern->GetLocalDownDistance()) >
219 MOVE_DISTANCE) {
220 pattern->OnTouchUp();
221 }
222 }
223 };
224 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
225 }
226
ParseMouseEvent()227 void TimePickerColumnPattern::ParseMouseEvent()
228 {
229 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
230 auto pattern = weak.Upgrade();
231 CHECK_NULL_VOID(pattern);
232 if (pattern) {
233 pattern->HandleMouseEvent(isHover);
234 }
235 };
236 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
237 }
238
InitMouseAndPressEvent()239 void TimePickerColumnPattern::InitMouseAndPressEvent()
240 {
241 if (mouseEvent_ || touchListener_) {
242 return;
243 }
244 auto host = GetHost();
245 CHECK_NULL_VOID(host);
246 auto columnEventHub = host->GetEventHub<EventHub>();
247 CHECK_NULL_VOID(columnEventHub);
248 RefPtr<TouchEventImpl> touchListener = CreateItemTouchEventListener();
249 CHECK_NULL_VOID(touchListener);
250 auto columnGesture = columnEventHub->GetOrCreateGestureEventHub();
251 CHECK_NULL_VOID(columnGesture);
252 columnGesture->AddTouchEvent(touchListener);
253 RefPtr<FrameNode> middleChild = nullptr;
254 auto childSize = static_cast<int32_t>(host->GetChildren().size());
255 auto midSize = childSize / 2;
256 middleChild = DynamicCast<FrameNode>(host->GetChildAtIndex(midSize));
257 CHECK_NULL_VOID(middleChild);
258 auto eventHub = middleChild->GetEventHub<EventHub>();
259 CHECK_NULL_VOID(eventHub);
260 auto inputHub = eventHub->GetOrCreateInputEventHub();
261 ParseMouseEvent();
262 inputHub->AddOnHoverEvent(mouseEvent_);
263 auto gesture = middleChild->GetOrCreateGestureEventHub();
264 CHECK_NULL_VOID(gesture);
265 ParseTouchListener();
266 gesture->AddTouchEvent(touchListener_);
267 for (int32_t i = 0; i < childSize; i++) {
268 RefPtr<FrameNode> childNode = DynamicCast<FrameNode>(host->GetChildAtIndex(i));
269 CHECK_NULL_VOID(childNode);
270 RefPtr<TimePickerEventParam> param = MakeRefPtr<TimePickerEventParam>();
271 param->instance_ = childNode;
272 param->itemIndex_ = i;
273 param->itemTotalCounts_ = childSize;
274
275 auto eventHub = childNode->GetEventHub<EventHub>();
276 CHECK_NULL_VOID(eventHub);
277 if (i != midSize) {
278 RefPtr<ClickEvent> clickListener = CreateItemClickEventListener(param);
279 CHECK_NULL_VOID(clickListener);
280 auto gesture = eventHub->GetOrCreateGestureEventHub();
281 CHECK_NULL_VOID(gesture);
282 gesture->AddClickEvent(clickListener);
283 }
284 }
285 }
286
CreateItemTouchEventListener()287 RefPtr<TouchEventImpl> TimePickerColumnPattern::CreateItemTouchEventListener()
288 {
289 auto toss = GetToss();
290 CHECK_NULL_RETURN(toss, nullptr);
291 auto touchCallback = [weak = WeakClaim(this), toss](const TouchEventInfo& info) {
292 auto pattern = weak.Upgrade();
293 CHECK_NULL_VOID(pattern);
294 auto isToss = pattern->GetTossStatus();
295 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
296 if (isToss == true) {
297 pattern->touchBreak_ = true;
298 pattern->animationBreak_ = true;
299 pattern->clickBreak_ = true;
300 auto TossEndPosition = toss->GetTossEndPosition();
301 pattern->SetYLast(TossEndPosition);
302 toss->StopTossAnimation();
303 } else {
304 pattern->animationBreak_ = false;
305 pattern->clickBreak_ = false;
306 }
307 }
308 if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
309 pattern->touchBreak_ = false;
310 if (pattern->animationBreak_ == true) {
311 pattern->PlayRestAnimation();
312 pattern->yOffset_ = 0.0;
313 }
314 }
315 };
316 auto listener = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
317 return listener;
318 }
319
HandleMouseEvent(bool isHover)320 void TimePickerColumnPattern::HandleMouseEvent(bool isHover)
321 {
322 if (isHover) {
323 hoverd_ = true;
324 PlayHoverAnimation(hoverColor_);
325 } else {
326 hoverd_ = false;
327 PlayHoverAnimation(Color::TRANSPARENT);
328 }
329 }
330
OnTouchDown()331 void TimePickerColumnPattern::OnTouchDown()
332 {
333 PlayPressAnimation(pressColor_);
334 }
335
OnTouchUp()336 void TimePickerColumnPattern::OnTouchUp()
337 {
338 if (hoverd_) {
339 PlayPressAnimation(hoverColor_);
340 } else {
341 PlayPressAnimation(Color::TRANSPARENT);
342 }
343 }
344
SetButtonBackgroundColor(const Color & pressColor)345 void TimePickerColumnPattern::SetButtonBackgroundColor(const Color& pressColor)
346 {
347 auto host = GetHost();
348 CHECK_NULL_VOID(host);
349 auto blendNode = host->GetParent();
350 CHECK_NULL_VOID(blendNode);
351 auto stack = blendNode->GetParent();
352 CHECK_NULL_VOID(stack);
353 auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
354 auto renderContext = buttonNode->GetRenderContext();
355 renderContext->UpdateBackgroundColor(pressColor);
356 buttonNode->MarkModifyDone();
357 buttonNode->MarkDirtyNode();
358 }
359
PlayPressAnimation(const Color & pressColor)360 void TimePickerColumnPattern::PlayPressAnimation(const Color& pressColor)
361 {
362 AnimationOption option = AnimationOption();
363 option.SetDuration(PRESS_ANIMATION_DURATION);
364 option.SetCurve(Curves::SHARP);
365 option.SetFillMode(FillMode::FORWARDS);
366 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), pressColor]() {
367 auto picker = weak.Upgrade();
368 if (picker) {
369 picker->SetButtonBackgroundColor(pressColor);
370 }
371 });
372 }
373
PlayHoverAnimation(const Color & color)374 void TimePickerColumnPattern::PlayHoverAnimation(const Color& color)
375 {
376 AnimationOption option = AnimationOption();
377 option.SetDuration(HOVER_ANIMATION_DURATION);
378 option.SetCurve(Curves::FRICTION);
379 option.SetFillMode(FillMode::FORWARDS);
380 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), color]() {
381 auto picker = weak.Upgrade();
382 if (picker) {
383 picker->SetButtonBackgroundColor(color);
384 }
385 });
386 }
387
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)388 bool TimePickerColumnPattern::OnDirtyLayoutWrapperSwap(
389 const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
390 {
391 bool isChange =
392 config.frameSizeChange || config.frameOffsetChange || config.contentSizeChange || config.contentOffsetChange;
393
394 CHECK_NULL_RETURN(isChange, false);
395 CHECK_NULL_RETURN(dirty, false);
396 auto geometryNode = dirty->GetGeometryNode();
397 CHECK_NULL_RETURN(geometryNode, false);
398 auto offset = geometryNode->GetFrameOffset();
399 auto size = geometryNode->GetFrameSize();
400 if (!NearEqual(offset, offset_) || !NearEqual(size, size_)) {
401 offset_ = offset;
402 size_ = size;
403 AddHotZoneRectToText();
404 }
405 return true;
406 }
407
InitTextFontFamily()408 void TimePickerColumnPattern::InitTextFontFamily()
409 {
410 auto host = GetHost();
411 CHECK_NULL_VOID(host);
412 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
413 CHECK_NULL_VOID(blendNode);
414 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
415 CHECK_NULL_VOID(stackNode);
416 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
417 CHECK_NULL_VOID(parentNode);
418 auto pipeline = parentNode->GetContext();
419 CHECK_NULL_VOID(pipeline);
420 auto timePickerRowPattern = parentNode->GetPattern<TimePickerRowPattern>();
421 CHECK_NULL_VOID(timePickerRowPattern);
422 auto timePickerLayoutProperty = parentNode->GetLayoutProperty<TimePickerLayoutProperty>();
423 CHECK_NULL_VOID(timePickerLayoutProperty);
424 hasUserDefinedDisappearFontFamily_ = timePickerRowPattern->GetHasUserDefinedDisappearFontFamily();
425 hasUserDefinedNormalFontFamily_ = timePickerRowPattern->GetHasUserDefinedNormalFontFamily();
426 hasUserDefinedSelectedFontFamily_ = timePickerRowPattern->GetHasUserDefinedSelectedFontFamily();
427 auto fontManager = pipeline->GetFontManager();
428 CHECK_NULL_VOID(fontManager);
429 if (!(fontManager->GetAppCustomFont().empty())) {
430 hasAppCustomFont_ = true;
431 }
432 auto appCustomFontFamily = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
433 if (hasAppCustomFont_ && !hasUserDefinedDisappearFontFamily_) {
434 timePickerLayoutProperty->UpdateDisappearFontFamily(appCustomFontFamily);
435 }
436 if (hasAppCustomFont_ && !hasUserDefinedNormalFontFamily_) {
437 timePickerLayoutProperty->UpdateFontFamily(appCustomFontFamily);
438 }
439 if (hasAppCustomFont_ && !hasUserDefinedSelectedFontFamily_) {
440 timePickerLayoutProperty->UpdateSelectedFontFamily(appCustomFontFamily);
441 }
442 }
443
FlushCurrentOptions(bool isDown,bool isUpateTextContentOnly)444 void TimePickerColumnPattern::FlushCurrentOptions(bool isDown, bool isUpateTextContentOnly)
445 {
446 auto host = GetHost();
447 CHECK_NULL_VOID(host);
448 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
449 CHECK_NULL_VOID(blendNode);
450 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
451 CHECK_NULL_VOID(stackNode);
452 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
453 CHECK_NULL_VOID(parentNode);
454 auto dataPickerLayoutProperty = host->GetLayoutProperty<LinearLayoutProperty>();
455 CHECK_NULL_VOID(dataPickerLayoutProperty);
456 dataPickerLayoutProperty->UpdatePadding(
457 PaddingProperty { CalcLength(static_cast<float>(PADDING_WEIGHT.ConvertToPx()), DimensionUnit::PX) });
458 dataPickerLayoutProperty->UpdateAlignSelf(FlexAlign::CENTER);
459 auto timePickerRowPattern = parentNode->GetPattern<TimePickerRowPattern>();
460 CHECK_NULL_VOID(timePickerRowPattern);
461 auto showOptionCount = GetShowCount();
462 uint32_t totalOptionCount = timePickerRowPattern->GetOptionCount(host);
463 auto timePickerLayoutProperty = parentNode->GetLayoutProperty<TimePickerLayoutProperty>();
464 CHECK_NULL_VOID(timePickerLayoutProperty);
465 uint32_t currentIndex = host->GetPattern<TimePickerColumnPattern>()->GetCurrentIndex();
466 CHECK_EQUAL_VOID(totalOptionCount, 0);
467 currentIndex = currentIndex % totalOptionCount;
468 uint32_t selectedIndex = showOptionCount / 2; // the center option is selected.
469 auto child = host->GetChildren();
470 auto iter = child.begin();
471 InitTextFontFamily();
472
473 if (!isUpateTextContentOnly) {
474 animationProperties_.clear();
475 }
476 auto actualOptionCount = showOptionCount < child.size() ? showOptionCount : child.size();
477 for (uint32_t index = 0; index < actualOptionCount; index++) {
478 uint32_t optionIndex = (totalOptionCount + currentIndex + index - selectedIndex) % totalOptionCount;
479 auto textNode = DynamicCast<FrameNode>(*iter);
480 CHECK_NULL_VOID(textNode);
481 auto textPattern = textNode->GetPattern<TextPattern>();
482 CHECK_NULL_VOID(textPattern);
483 auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
484 CHECK_NULL_VOID(textLayoutProperty);
485 if (!isUpateTextContentOnly) {
486 ChangeTextStyle(index, showOptionCount, textLayoutProperty, timePickerLayoutProperty);
487 ChangeAmPmTextStyle(index, showOptionCount, textLayoutProperty, timePickerLayoutProperty);
488 AddAnimationTextProperties(index, textLayoutProperty);
489 }
490 iter++;
491 int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(selectedIndex);
492 int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
493 bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
494 if ((NotLoopOptions() || !wheelModeEnabled_) && !virtualIndexValidate) {
495 textLayoutProperty->UpdateContent("");
496 } else {
497 auto optionValue = timePickerRowPattern->GetOptionsValue(host, optionIndex);
498 textLayoutProperty->UpdateContent(optionValue);
499 textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
500 }
501 textNode->MarkModifyDone();
502 textNode->MarkDirtyNode();
503 }
504 }
505
UpdateDisappearTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TimePickerLayoutProperty> & timePickerLayoutProperty)506 void TimePickerColumnPattern::UpdateDisappearTextProperties(const RefPtr<PickerTheme>& pickerTheme,
507 const RefPtr<TextLayoutProperty>& textLayoutProperty,
508 const RefPtr<TimePickerLayoutProperty>& timePickerLayoutProperty)
509 {
510 auto normalOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize();
511 textLayoutProperty->UpdateTextColor(timePickerLayoutProperty->GetDisappearColor().value_or(
512 pickerTheme->GetOptionStyle(false, false).GetTextColor()));
513 if (timePickerLayoutProperty->HasDisappearFontSize()) {
514 textLayoutProperty->UpdateFontSize(timePickerLayoutProperty->GetDisappearFontSize().value());
515 } else {
516 textLayoutProperty->UpdateAdaptMaxFontSize(normalOptionSize);
517 textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(false, false).GetAdaptMinFontSize());
518 }
519 textLayoutProperty->UpdateFontWeight(timePickerLayoutProperty->GetDisappearWeight().value_or(
520 pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
521 DisappearWeight_ = timePickerLayoutProperty->GetDisappearWeight().value_or(
522 pickerTheme->GetOptionStyle(false, false).GetFontWeight());
523 textLayoutProperty->UpdateFontFamily(timePickerLayoutProperty->GetDisappearFontFamily().value_or(
524 pickerTheme->GetOptionStyle(false, false).GetFontFamilies()));
525 textLayoutProperty->UpdateItalicFontStyle(timePickerLayoutProperty->GetDisappearFontStyle().value_or(
526 pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
527 }
528
UpdateCandidateTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TimePickerLayoutProperty> & timePickerLayoutProperty)529 void TimePickerColumnPattern::UpdateCandidateTextProperties(const RefPtr<PickerTheme>& pickerTheme,
530 const RefPtr<TextLayoutProperty>& textLayoutProperty,
531 const RefPtr<TimePickerLayoutProperty>& timePickerLayoutProperty)
532 {
533 auto focusOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
534 textLayoutProperty->UpdateTextColor(
535 timePickerLayoutProperty->GetColor().value_or(pickerTheme->GetOptionStyle(false, false).GetTextColor()));
536 if (timePickerLayoutProperty->HasFontSize()) {
537 textLayoutProperty->UpdateFontSize(timePickerLayoutProperty->GetFontSize().value());
538 } else {
539 textLayoutProperty->UpdateAdaptMaxFontSize(focusOptionSize);
540 textLayoutProperty->UpdateAdaptMinFontSize(
541 pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize() - FOCUS_SIZE);
542 }
543 textLayoutProperty->UpdateFontWeight(
544 timePickerLayoutProperty->GetWeight().value_or(pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
545 textLayoutProperty->UpdateFontFamily(timePickerLayoutProperty->GetFontFamily().value_or(
546 pickerTheme->GetOptionStyle(false, false).GetFontFamilies()));
547 textLayoutProperty->UpdateItalicFontStyle(
548 timePickerLayoutProperty->GetFontStyle().value_or(pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
549 }
550
UpdateSelectedTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TimePickerLayoutProperty> & timePickerLayoutProperty)551 void TimePickerColumnPattern::UpdateSelectedTextProperties(const RefPtr<PickerTheme>& pickerTheme,
552 const RefPtr<TextLayoutProperty>& textLayoutProperty,
553 const RefPtr<TimePickerLayoutProperty>& timePickerLayoutProperty)
554 {
555 auto selectedOptionSize = pickerTheme->GetOptionStyle(true, false).GetFontSize();
556 textLayoutProperty->UpdateTextColor(
557 timePickerLayoutProperty->GetSelectedColor().value_or(pickerTheme->GetOptionStyle(true, false).GetTextColor()));
558 if (timePickerLayoutProperty->HasSelectedFontSize()) {
559 textLayoutProperty->UpdateFontSize(timePickerLayoutProperty->GetSelectedFontSize().value());
560 } else {
561 textLayoutProperty->UpdateAdaptMaxFontSize(selectedOptionSize);
562 textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize());
563 }
564 textLayoutProperty->UpdateFontWeight(timePickerLayoutProperty->GetSelectedWeight().value_or(
565 pickerTheme->GetOptionStyle(true, false).GetFontWeight()));
566 SelectedWeight_ = timePickerLayoutProperty->GetSelectedWeight().value_or(
567 pickerTheme->GetOptionStyle(true, false).GetFontWeight());
568 textLayoutProperty->UpdateFontFamily(timePickerLayoutProperty->GetSelectedFontFamily().value_or(
569 pickerTheme->GetOptionStyle(true, false).GetFontFamilies()));
570 textLayoutProperty->UpdateItalicFontStyle(timePickerLayoutProperty->GetSelectedFontStyle().value_or(
571 pickerTheme->GetOptionStyle(true, false).GetFontStyle()));
572 }
573
ChangeAmPmTextStyle(uint32_t index,uint32_t showOptionCount,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TimePickerLayoutProperty> & timePickerLayoutProperty)574 void TimePickerColumnPattern::ChangeAmPmTextStyle(uint32_t index, uint32_t showOptionCount,
575 const RefPtr<TextLayoutProperty>& textLayoutProperty,
576 const RefPtr<TimePickerLayoutProperty>& timePickerLayoutProperty)
577 {
578 if (showOptionCount != CHILDREN_SIZE) {
579 return;
580 }
581 auto pipeline = GetContext();
582 CHECK_NULL_VOID(pipeline);
583 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
584 CHECK_NULL_VOID(pickerTheme);
585 uint32_t selectedIndex = showOptionCount / 2; // the center option is selected.
586 if (index == selectedIndex) {
587 UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, timePickerLayoutProperty);
588 textLayoutProperty->UpdateAlignment(Alignment::CENTER);
589 }
590 if ((index == 0) || (index == showOptionCount - 1)) {
591 UpdateDisappearTextProperties(pickerTheme, textLayoutProperty, timePickerLayoutProperty);
592 if (index == 0) {
593 textLayoutProperty->UpdateAlignment(Alignment::TOP_CENTER);
594 } else {
595 textLayoutProperty->UpdateAlignment(Alignment::BOTTOM_CENTER);
596 }
597 }
598 textLayoutProperty->UpdateMaxLines(1);
599 }
600
ChangeTextStyle(uint32_t index,uint32_t showOptionCount,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TimePickerLayoutProperty> & timePickerLayoutProperty)601 void TimePickerColumnPattern::ChangeTextStyle(uint32_t index, uint32_t showOptionCount,
602 const RefPtr<TextLayoutProperty>& textLayoutProperty,
603 const RefPtr<TimePickerLayoutProperty>& timePickerLayoutProperty)
604 {
605 if (showOptionCount == CHILDREN_SIZE) {
606 return;
607 }
608 auto pipeline = GetContext();
609 CHECK_NULL_VOID(pipeline);
610 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
611 CHECK_NULL_VOID(pickerTheme);
612 uint32_t selectedIndex = showOptionCount / 2; // the center option is selected.
613 uint32_t val = selectedIndex > 0 ? selectedIndex - 1 : 0;
614 if (index != selectedIndex) {
615 if ((index == selectedIndex + 1) || (index == val)) {
616 UpdateCandidateTextProperties(pickerTheme, textLayoutProperty, timePickerLayoutProperty);
617 } else {
618 UpdateDisappearTextProperties(pickerTheme, textLayoutProperty, timePickerLayoutProperty);
619 }
620 if (index < selectedIndex) {
621 textLayoutProperty->UpdateAlignment(Alignment::TOP_CENTER);
622 } else {
623 textLayoutProperty->UpdateAlignment(Alignment::BOTTOM_CENTER);
624 }
625 }
626 if (index == selectedIndex) {
627 UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, timePickerLayoutProperty);
628 textLayoutProperty->UpdateAlignment(Alignment::CENTER);
629 }
630 textLayoutProperty->UpdateMaxLines(1);
631 }
632
AddAnimationTextProperties(uint32_t currentIndex,const RefPtr<TextLayoutProperty> & textLayoutProperty)633 void TimePickerColumnPattern::AddAnimationTextProperties(
634 uint32_t currentIndex, const RefPtr<TextLayoutProperty>& textLayoutProperty)
635 {
636 TimeTextProperties properties;
637 if (textLayoutProperty->HasFontSize()) {
638 MeasureContext measureContext;
639 measureContext.textContent = MEASURE_SIZE_STRING;
640 measureContext.fontSize = textLayoutProperty->GetFontSize().value();
641 auto size = MeasureUtil::MeasureTextSize(measureContext);
642 if (!optionProperties_.empty()) {
643 optionProperties_[currentIndex].fontheight = size.Height();
644 if (optionProperties_[currentIndex].fontheight > optionProperties_[currentIndex].height) {
645 optionProperties_[currentIndex].fontheight = optionProperties_[currentIndex].height;
646 }
647 }
648 SetOptionShiftDistance();
649 properties.fontSize = Dimension(textLayoutProperty->GetFontSize().value().ConvertToPx());
650 }
651 if (textLayoutProperty->HasFontWeight()) {
652 properties.fontWeight = textLayoutProperty->GetFontWeight().value();
653 }
654 if (textLayoutProperty->HasTextColor()) {
655 properties.currentColor = textLayoutProperty->GetTextColor().value();
656 }
657 if (currentIndex > 0) {
658 properties.upFontSize = animationProperties_[currentIndex - 1].fontSize;
659 animationProperties_[currentIndex - 1].downFontSize = properties.fontSize;
660
661 properties.upColor = animationProperties_[currentIndex - 1].currentColor;
662 animationProperties_[currentIndex - 1].downColor = properties.currentColor;
663
664 properties.upFontWeight = animationProperties_[currentIndex - 1].fontWeight;
665 animationProperties_[currentIndex - 1].downFontWeight = properties.fontWeight;
666 }
667 animationProperties_.emplace_back(properties);
668 }
669
FlushAnimationTextProperties(bool isDown)670 void TimePickerColumnPattern::FlushAnimationTextProperties(bool isDown)
671 {
672 if (!animationProperties_.size()) {
673 return;
674 }
675 if (isDown) {
676 for (size_t i = 0; i < animationProperties_.size(); i++) {
677 if (i > 0) {
678 animationProperties_[i - 1].upFontSize = animationProperties_[i].upFontSize;
679 animationProperties_[i - 1].fontSize = animationProperties_[i].fontSize;
680 animationProperties_[i - 1].downFontSize = animationProperties_[i].downFontSize;
681
682 animationProperties_[i - 1].upColor = animationProperties_[i].upColor;
683 animationProperties_[i - 1].currentColor = animationProperties_[i].currentColor;
684 animationProperties_[i - 1].downColor = animationProperties_[i].downColor;
685 }
686 if (i == (animationProperties_.size() - 1)) {
687 animationProperties_[i].upFontSize = animationProperties_[i].fontSize;
688 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
689 animationProperties_[i].downFontSize = Dimension();
690
691 animationProperties_[i].upColor = animationProperties_[i].currentColor;
692 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
693 animationProperties_[i].currentColor =
694 colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
695 animationProperties_[i].downColor = Color();
696 }
697 }
698 } else {
699 for (size_t i = animationProperties_.size() - 1;; i--) {
700 if (i == 0) {
701 animationProperties_[i].upFontSize = Dimension();
702 animationProperties_[i].downFontSize = animationProperties_[i].fontSize;
703 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
704
705 animationProperties_[i].upColor = Color();
706 animationProperties_[i].downColor = animationProperties_[i].currentColor;
707 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
708 animationProperties_[i].currentColor =
709 colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
710 break;
711 } else {
712 animationProperties_[i].upFontSize = animationProperties_[i - 1].upFontSize;
713 animationProperties_[i].fontSize = animationProperties_[i - 1].fontSize;
714 animationProperties_[i].downFontSize = animationProperties_[i - 1].downFontSize;
715
716 animationProperties_[i].upColor = animationProperties_[i - 1].upColor;
717 animationProperties_[i].currentColor = animationProperties_[i - 1].currentColor;
718 animationProperties_[i].downColor = animationProperties_[i - 1].downColor;
719 }
720 }
721 }
722 }
723
TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty> & textLayoutProperty,uint32_t index,uint32_t showCount,bool isDown,double scale)724 void TimePickerColumnPattern::TextPropertiesLinearAnimation(
725 const RefPtr<TextLayoutProperty>& textLayoutProperty, uint32_t index, uint32_t showCount, bool isDown, double scale)
726 {
727 if (index >= animationProperties_.size()) {
728 return;
729 }
730 Dimension startFontSize = animationProperties_[index].fontSize;
731 Color startColor = animationProperties_[index].currentColor;
732 if ((!index && isDown) || ((index == (showCount - 1)) && !isDown && scale)) {
733 textLayoutProperty->UpdateFontSize(startFontSize);
734 textLayoutProperty->UpdateTextColor(startColor);
735 return;
736 }
737 Dimension endFontSize;
738 Color endColor;
739 if (!isDown) {
740 endFontSize = animationProperties_[index].downFontSize;
741 endColor = animationProperties_[index].downColor;
742
743 if (scale >= FONTWEIGHT) {
744 textLayoutProperty->UpdateFontWeight(animationProperties_[index].downFontWeight);
745 }
746 } else {
747 endFontSize = animationProperties_[index].upFontSize;
748 endColor = animationProperties_[index].upColor;
749
750 if (scale >= FONTWEIGHT) {
751 textLayoutProperty->UpdateFontWeight(animationProperties_[index].upFontWeight);
752 }
753 }
754 Dimension updateSize = LinearFontSize(startFontSize, endFontSize, distancePercent_);
755 textLayoutProperty->UpdateFontSize(updateSize);
756 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
757 Color updateColor = colorEvaluator->Evaluate(startColor, endColor, distancePercent_);
758 textLayoutProperty->UpdateTextColor(updateColor);
759 if (scale < FONTWEIGHT) {
760 textLayoutProperty->UpdateFontWeight(animationProperties_[index].fontWeight);
761 }
762 }
763
UpdateTextPropertiesLinear(bool isDown,double scale)764 void TimePickerColumnPattern::UpdateTextPropertiesLinear(bool isDown, double scale)
765 {
766 auto host = GetHost();
767 CHECK_NULL_VOID(host);
768 uint32_t showCount = GetShowCount();
769 auto child = host->GetChildren();
770 auto iter = child.begin();
771 if (child.size() != showCount) {
772 return;
773 }
774 for (uint32_t index = 0; index < showCount; index++) {
775 auto textNode = DynamicCast<FrameNode>(*iter);
776 CHECK_NULL_VOID(textNode);
777 auto textPattern = textNode->GetPattern<TextPattern>();
778 CHECK_NULL_VOID(textPattern);
779 RefPtr<TextLayoutProperty> textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
780 CHECK_NULL_VOID(textLayoutProperty);
781 TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
782 iter++;
783 }
784 }
785
LinearFontSize(const Dimension & startFontSize,const Dimension & endFontSize,double percent)786 Dimension TimePickerColumnPattern::LinearFontSize(
787 const Dimension& startFontSize, const Dimension& endFontSize, double percent)
788 {
789 if (percent > FONT_SIZE_PERCENT) {
790 return startFontSize + (endFontSize - startFontSize);
791 } else {
792 return startFontSize + (endFontSize - startFontSize) * percent;
793 }
794 }
795
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)796 void TimePickerColumnPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
797 {
798 CHECK_NULL_VOID(!panEvent_);
799 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
800 auto pattern = weak.Upgrade();
801 CHECK_NULL_VOID(pattern);
802 if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
803 return;
804 }
805 pattern->HandleDragStart(event);
806 };
807 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& event) {
808 auto pattern = weak.Upgrade();
809 CHECK_NULL_VOID(pattern);
810 pattern->SetMainVelocity(event.GetMainVelocity());
811 pattern->HandleDragMove(event);
812 };
813 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
814 auto pattern = weak.Upgrade();
815 CHECK_NULL_VOID(pattern);
816 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
817 return;
818 }
819 pattern->SetMainVelocity(info.GetMainVelocity());
820 pattern->HandleDragEnd();
821 };
822 auto actionCancelTask = [weak = WeakClaim(this)]() {
823 auto pattern = weak.Upgrade();
824 CHECK_NULL_VOID(pattern);
825 pattern->HandleDragEnd();
826 };
827 PanDirection panDirection;
828 panDirection.type = PanDirection::VERTICAL;
829 panEvent_ = MakeRefPtr<PanEvent>(
830 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
831 gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
832 }
833
HandleDragStart(const GestureEvent & event)834 void TimePickerColumnPattern::HandleDragStart(const GestureEvent& event)
835 {
836 CHECK_NULL_VOID(GetHost());
837 CHECK_NULL_VOID(GetToss());
838 auto toss = GetToss();
839 auto offsetY = event.GetGlobalPoint().GetY();
840 toss->SetStart(offsetY);
841 yLast_ = offsetY;
842 pressed_ = true;
843 auto frameNode = GetHost();
844 CHECK_NULL_VOID(frameNode);
845 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::START);
846 // AccessibilityEventType::SCROLL_START
847 }
848
HandleDragMove(const GestureEvent & event)849 void TimePickerColumnPattern::HandleDragMove(const GestureEvent& event)
850 {
851 if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
852 InnerHandleScroll(LessNotEqual(event.GetDelta().GetY(), 0.0), true);
853 return;
854 }
855 animationBreak_ = false;
856 CHECK_NULL_VOID(pressed_);
857 CHECK_NULL_VOID(GetHost());
858 CHECK_NULL_VOID(GetToss());
859 auto toss = GetToss();
860 auto offsetY =
861 event.GetGlobalPoint().GetY() + (event.GetInputEventType() == InputEventType::AXIS ? event.GetOffsetY() : 0.0);
862 if (NearEqual(offsetY, yLast_, 1.0)) { // if changing less than 1.0, no need to handle
863 return;
864 }
865 toss->SetEnd(offsetY);
866 UpdateColumnChildPosition(offsetY);
867 auto frameNode = GetHost();
868 CHECK_NULL_VOID(frameNode);
869 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::RUNNING);
870 }
871
HandleDragEnd()872 void TimePickerColumnPattern::HandleDragEnd()
873 {
874 if (hapticController_) {
875 hapticController_->Stop();
876 }
877 pressed_ = false;
878 CHECK_NULL_VOID(GetHost());
879 CHECK_NULL_VOID(GetToss());
880 auto toss = GetToss();
881 auto frameNode = GetHost();
882 CHECK_NULL_VOID(frameNode);
883 if (!NotLoopOptions() && toss->Play()) {
884 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
885 // AccessibilityEventType::SCROLL_END
886 return;
887 }
888 yOffset_ = 0.0;
889 yLast_ = 0.0;
890 if (!animationCreated_) {
891 ScrollOption(0.0);
892 return;
893 }
894
895 TimePickerScrollDirection dir =
896 scrollDelta_ > 0.0 ? TimePickerScrollDirection::DOWN : TimePickerScrollDirection::UP;
897 int32_t middleIndex = static_cast<int32_t>(GetShowCount()) / MIDDLE_CHILD_INDEX;
898 auto shiftDistance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
899 : optionProperties_[middleIndex].nextDistance;
900 auto shiftThreshold = shiftDistance / MIDDLE_CHILD_INDEX;
901 if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
902 InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true);
903 scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == TimePickerScrollDirection::UP ? -1 : 1);
904 }
905 CreateAnimation(scrollDelta_, 0.0);
906 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
907 // AccessibilityEventType::SCROLL_END
908 }
909
CreateAnimation()910 void TimePickerColumnPattern::CreateAnimation()
911 {
912 CHECK_NULL_VOID(!animationCreated_);
913 auto host = GetHost();
914 CHECK_NULL_VOID(host);
915 auto renderContext = host->GetRenderContext();
916 CHECK_NULL_VOID(renderContext);
917 auto propertyCallback = [weak = AceType::WeakClaim(this)](float value) {
918 auto column = weak.Upgrade();
919 CHECK_NULL_VOID(column);
920 column->ScrollOption(value);
921 };
922 scrollProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
923 renderContext->AttachNodeAnimatableProperty(scrollProperty_);
924
925 auto aroundClickCallback = [weak = AceType::WeakClaim(this)](float value) {
926 auto column = weak.Upgrade();
927 CHECK_NULL_VOID(column);
928 if (value > 0) {
929 column->UpdateColumnChildPosition(std::ceil(value));
930 } else {
931 column->UpdateColumnChildPosition(std::floor(value));
932 }
933 };
934 aroundClickProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(aroundClickCallback));
935 renderContext->AttachNodeAnimatableProperty(aroundClickProperty_);
936 animationCreated_ = true;
937 }
938
CreateAnimation(double from,double to)939 void TimePickerColumnPattern::CreateAnimation(double from, double to)
940 {
941 AnimationOption option;
942 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
943 option.SetDuration(CLICK_ANIMATION_DURATION);
944 scrollProperty_->Set(from);
945 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), to]() {
946 auto column = weak.Upgrade();
947 CHECK_NULL_VOID(column);
948 column->scrollProperty_->Set(to);
949 });
950 }
951
ScrollOption(double delta,bool isJump)952 void TimePickerColumnPattern::ScrollOption(double delta, bool isJump)
953 {
954 scrollDelta_ = delta;
955 auto midIndex = GetShowCount() / 2;
956 TimePickerScrollDirection dir = delta > 0.0 ? TimePickerScrollDirection::DOWN : TimePickerScrollDirection::UP;
957 auto shiftDistance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
958 : optionProperties_[midIndex].nextDistance;
959 distancePercent_ = delta / shiftDistance;
960 auto textLinearPercent = 0.0;
961 textLinearPercent = (std::abs(delta)) / (optionProperties_[midIndex].height);
962 UpdateTextPropertiesLinear(LessNotEqual(delta, 0.0), textLinearPercent);
963 CalcAlgorithmOffset(dir, distancePercent_);
964 auto host = GetHost();
965 CHECK_NULL_VOID(host);
966 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
967 }
968
ResetAlgorithmOffset()969 void TimePickerColumnPattern::ResetAlgorithmOffset()
970 {
971 algorithmOffset_.clear();
972 uint32_t counts = GetShowCount();
973 for (uint32_t i = 0; i < counts; i++) {
974 algorithmOffset_.emplace_back(0.0f);
975 }
976 }
977
UpdateScrollDelta(double delta)978 void TimePickerColumnPattern::UpdateScrollDelta(double delta)
979 {
980 SetCurrentOffset(delta);
981 auto host = GetHost();
982 CHECK_NULL_VOID(host);
983 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
984 }
985
CalcAlgorithmOffset(TimePickerScrollDirection dir,double distancePercent)986 void TimePickerColumnPattern::CalcAlgorithmOffset(TimePickerScrollDirection dir, double distancePercent)
987 {
988 algorithmOffset_.clear();
989 uint32_t counts = GetShowCount();
990 for (uint32_t i = 0; i < counts; i++) {
991 auto distance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[i].prevDistance
992 : optionProperties_[i].nextDistance;
993 algorithmOffset_.emplace_back(static_cast<int32_t>(distance * distancePercent));
994 }
995 }
996
GetShiftDistance(uint32_t index,TimePickerScrollDirection dir)997 float TimePickerColumnPattern::GetShiftDistance(uint32_t index, TimePickerScrollDirection dir)
998 {
999 auto pipeline = GetContext();
1000 CHECK_NULL_RETURN(pipeline, 0.0f);
1001 auto theme = pipeline->GetTheme<PickerTheme>();
1002 CHECK_NULL_RETURN(theme, 0.0f);
1003 const uint32_t optionCounts = GetShowCount();
1004 uint32_t nextIndex = 0;
1005 float distance = 0.0f;
1006 float val = 0.0f;
1007 auto isDown = dir == TimePickerScrollDirection::DOWN;
1008 if (optionCounts == 0) {
1009 return distance;
1010 }
1011 if (isDown) {
1012 nextIndex = (optionCounts + index + 1) % optionCounts; // index add one
1013 } else {
1014 nextIndex = (optionCounts + index - 1) % optionCounts; // index reduce one
1015 }
1016 switch (static_cast<TimePickerOptionIndex>(index)) {
1017 case TimePickerOptionIndex::COLUMN_INDEX_0: // first
1018 distance = (dir == TimePickerScrollDirection::DOWN) ? optionProperties_[index].height
1019 : (0.0f - optionProperties_[index].height);
1020 break;
1021 case TimePickerOptionIndex::COLUMN_INDEX_1:
1022 distance = (dir == TimePickerScrollDirection::DOWN) ? optionProperties_[index].height
1023 : (0.0f - optionProperties_[index].height);
1024 break;
1025 case TimePickerOptionIndex::COLUMN_INDEX_2:
1026 if (dir == TimePickerScrollDirection::UP) {
1027 distance = -optionProperties_[nextIndex].height;
1028 } else {
1029 val = optionProperties_[index].height +
1030 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) /
1031 MIDDLE_CHILD_INDEX;
1032 distance = std::ceil(val);
1033 }
1034 break;
1035 case TimePickerOptionIndex::COLUMN_INDEX_3:
1036 val = (optionProperties_[index].height - optionProperties_[nextIndex].fontheight) / MIDDLE_CHILD_INDEX +
1037 optionProperties_[nextIndex].height;
1038 distance = (dir == TimePickerScrollDirection::DOWN) ? val : (0.0f - val);
1039 distance = std::floor(distance);
1040 break;
1041 case TimePickerOptionIndex::COLUMN_INDEX_4:
1042 if (dir == TimePickerScrollDirection::DOWN) {
1043 distance = optionProperties_[nextIndex].height;
1044 } else {
1045 val = optionProperties_[index].height +
1046 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) /
1047 MIDDLE_CHILD_INDEX;
1048 distance = std::ceil(0.0f - val);
1049 }
1050 break;
1051 case TimePickerOptionIndex::COLUMN_INDEX_5:
1052 distance = (dir == TimePickerScrollDirection::DOWN) ? optionProperties_[index].height
1053 : (0.0f - optionProperties_[index].height);
1054 break;
1055 case TimePickerOptionIndex::COLUMN_INDEX_6: // last
1056 distance = (dir == TimePickerScrollDirection::DOWN) ? optionProperties_[index].height
1057 : (0.0f - optionProperties_[index].height);
1058 break;
1059 default:
1060 break;
1061 }
1062 return distance;
1063 }
1064
GetShiftDistanceForLandscape(uint32_t index,TimePickerScrollDirection dir)1065 float TimePickerColumnPattern::GetShiftDistanceForLandscape(uint32_t index, TimePickerScrollDirection dir)
1066 {
1067 auto pipeline = GetContext();
1068 CHECK_NULL_RETURN(pipeline, 0.0f);
1069 auto theme = pipeline->GetTheme<PickerTheme>();
1070 CHECK_NULL_RETURN(theme, 0.0f);
1071 uint32_t optionCounts = GetShowCount();
1072 uint32_t nextIndex = 0;
1073 float distance = 0.0f;
1074 float val = 0.0f;
1075 auto isDown = dir == TimePickerScrollDirection::DOWN;
1076 if (optionCounts == 0) {
1077 return distance;
1078 }
1079 if (isDown) {
1080 nextIndex = (optionCounts + index + 1) % optionCounts; // index add one
1081 } else {
1082 nextIndex = (optionCounts + index - 1) % optionCounts; // index reduce one
1083 }
1084 switch (static_cast<TimePickerOptionIndex>(index)) {
1085 case TimePickerOptionIndex::COLUMN_INDEX_0: // first
1086 if (dir == TimePickerScrollDirection::UP) {
1087 distance = 0.0f - optionProperties_[index].height;
1088 } else {
1089 distance = optionProperties_[index].height +
1090 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) /
1091 MIDDLE_CHILD_INDEX;
1092 }
1093 break;
1094 case TimePickerOptionIndex::COLUMN_INDEX_1:
1095 val = (optionProperties_[index].height - optionProperties_[nextIndex].fontheight) / MIDDLE_CHILD_INDEX +
1096 optionProperties_[nextIndex].height;
1097 distance = (dir == TimePickerScrollDirection::DOWN) ? val : (0.0f - val);
1098 distance = std::floor(distance);
1099 break;
1100 case TimePickerOptionIndex::COLUMN_INDEX_2: // last
1101 if (dir == TimePickerScrollDirection::DOWN) {
1102 distance = optionProperties_[index].height;
1103 } else {
1104 val = optionProperties_[index].height +
1105 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) /
1106 MIDDLE_CHILD_INDEX;
1107 distance = 0.0f - val;
1108 }
1109 break;
1110 default:
1111 break;
1112 }
1113 return distance;
1114 }
1115
SetOptionShiftDistance()1116 void TimePickerColumnPattern::SetOptionShiftDistance()
1117 {
1118 auto pipeline = PipelineBase::GetCurrentContext();
1119 CHECK_NULL_VOID(pipeline);
1120 auto theme = pipeline->GetTheme<PickerTheme>();
1121 CHECK_NULL_VOID(theme);
1122 uint32_t itemCounts = GetShowCount();
1123 bool isLanscape = itemCounts == OPTION_COUNT_PHONE_LANDSCAPE;
1124 for (uint32_t i = 0; i < itemCounts; i++) {
1125 TimePickerOptionProperty& prop = optionProperties_[i];
1126 if (isLanscape) {
1127 prop.prevDistance = GetShiftDistanceForLandscape(i, TimePickerScrollDirection::UP);
1128 prop.nextDistance = GetShiftDistanceForLandscape(i, TimePickerScrollDirection::DOWN);
1129 } else {
1130 prop.prevDistance = GetShiftDistance(i, TimePickerScrollDirection::UP);
1131 prop.nextDistance = GetShiftDistance(i, TimePickerScrollDirection::DOWN);
1132 }
1133 }
1134 }
1135
UpdateToss(double offsetY)1136 void TimePickerColumnPattern::UpdateToss(double offsetY)
1137 {
1138 UpdateColumnChildPosition(offsetY);
1139 }
1140
UpdateFinishToss(double offsetY)1141 void TimePickerColumnPattern::UpdateFinishToss(double offsetY)
1142 {
1143 int32_t dragDelta = offsetY - yLast_;
1144 if (!CanMove(LessNotEqual(dragDelta, 0))) {
1145 return;
1146 }
1147 auto midIndex = GetShowCount() / 2;
1148 TimePickerScrollDirection dir = dragDelta > 0.0 ? TimePickerScrollDirection::DOWN : TimePickerScrollDirection::UP;
1149 auto shiftDistance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1150 : optionProperties_[midIndex].nextDistance;
1151 ScrollOption(shiftDistance);
1152 }
1153
TossStoped()1154 void TimePickerColumnPattern::TossStoped()
1155 {
1156 yOffset_ = 0.0;
1157 yLast_ = 0.0;
1158 ScrollOption(0.0);
1159 }
1160
SetDividerHeight(uint32_t showOptionCount)1161 void TimePickerColumnPattern::SetDividerHeight(uint32_t showOptionCount)
1162 {
1163 auto host = GetHost();
1164 CHECK_NULL_VOID(host);
1165 auto pipeline = GetContext();
1166 CHECK_NULL_VOID(pipeline);
1167 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1168 auto childSize = host->GetChildren().size();
1169 if (childSize != CHILDREN_SIZE) {
1170 gradientHeight_ = static_cast<float>(pickerTheme->GetGradientHeight().Value() * TEXT_HEIGHT_NUMBER);
1171 } else {
1172 gradientHeight_ = static_cast<float>(pickerTheme->GetGradientHeight().Value() - TEXT_HOUR24_HEIGHT_NUMBER);
1173 }
1174 dividerHeight_ = static_cast<float>(
1175 gradientHeight_ + pickerTheme->GetDividerSpacing().Value() + pickerTheme->GetGradientHeight().Value());
1176 dividerSpacingWidth_ = static_cast<float>(pickerTheme->GetDividerSpacing().Value() * TEXT_WEIGHT_NUMBER);
1177 }
1178
NotLoopOptions() const1179 bool TimePickerColumnPattern::NotLoopOptions() const
1180 {
1181 auto host = GetHost();
1182 CHECK_NULL_RETURN(host, false);
1183 auto showOptionCount = GetShowCount();
1184 auto options = GetOptions();
1185 uint32_t totalOptionCount = options[host];
1186 return totalOptionCount <= showOptionCount / 2 + 1; // the critical value of loop condition.
1187 }
1188
InnerHandleScroll(bool isDown,bool isUpatePropertiesOnly)1189 bool TimePickerColumnPattern::InnerHandleScroll(bool isDown, bool isUpatePropertiesOnly)
1190 {
1191 auto host = GetHost();
1192 CHECK_NULL_RETURN(host, false);
1193 auto options = GetOptions();
1194 auto totalOptionCount = options[host];
1195
1196 CHECK_NULL_RETURN(host, false);
1197 CHECK_NULL_RETURN(totalOptionCount, false);
1198
1199 uint32_t currentIndex = GetCurrentIndex();
1200 if (isDown) {
1201 currentIndex = (totalOptionCount + currentIndex + 1) % totalOptionCount; // index add one
1202 } else {
1203 auto totalCountAndIndex = totalOptionCount + currentIndex;
1204 currentIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount; // index reduce one
1205 }
1206 SetCurrentIndex(currentIndex);
1207 if (hapticController_ && isEnableHaptic_) {
1208 hapticController_->PlayOnce();
1209 }
1210 FlushCurrentOptions(isDown, isUpatePropertiesOnly);
1211 HandleChangeCallback(isDown, true);
1212 HandleEventCallback(true);
1213
1214 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1215 host->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE);
1216 return true;
1217 }
1218
UpdateColumnChildPosition(double offsetY)1219 void TimePickerColumnPattern::UpdateColumnChildPosition(double offsetY)
1220 {
1221 int32_t dragDelta = offsetY - yLast_;
1222 if (hapticController_ && isShow_) {
1223 if (isEnableHaptic_) {
1224 hapticController_->HandleDelta(dragDelta);
1225 }
1226 }
1227 yLast_ = offsetY;
1228 if (!CanMove(LessNotEqual(dragDelta, 0))) {
1229 return;
1230 }
1231 offsetCurSet_ = 0.0;
1232 auto midIndex = GetShowCount() / 2;
1233 TimePickerScrollDirection dir = dragDelta > 0.0 ? TimePickerScrollDirection::DOWN : TimePickerScrollDirection::UP;
1234 auto shiftDistance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1235 : optionProperties_[midIndex].nextDistance;
1236 // the abs of drag delta is less than jump interval.
1237 dragDelta = dragDelta + yOffset_;
1238 if (GreatOrEqual(std::abs(dragDelta), std::abs(shiftDistance))) {
1239 InnerHandleScroll(LessNotEqual(dragDelta, 0.0), true);
1240 dragDelta = dragDelta % static_cast<int>(std::abs(shiftDistance));
1241 if (!NearZero(dragDelta) && !CanMove(LessNotEqual(dragDelta, 0))) {
1242 dragDelta = 0.0;
1243 auto toss = GetToss();
1244 CHECK_NULL_VOID(toss);
1245 toss->StopTossAnimation();
1246 if (hapticController_) {
1247 hapticController_->Stop();
1248 }
1249 }
1250 ScrollOption(dragDelta, true);
1251 offsetCurSet_ = dragDelta;
1252 yOffset_ = dragDelta;
1253 return;
1254 }
1255 // update selected option
1256 ScrollOption(dragDelta);
1257 offsetCurSet_ = dragDelta;
1258 yOffset_ = dragDelta;
1259 }
1260
ShiftOptionProp(RefPtr<FrameNode> curNode,RefPtr<FrameNode> shiftNode)1261 void TimePickerColumnPattern::ShiftOptionProp(RefPtr<FrameNode> curNode, RefPtr<FrameNode> shiftNode)
1262 {
1263 RefPtr<TextPattern> curPattern = curNode->GetPattern<TextPattern>();
1264 CHECK_NULL_VOID(curPattern);
1265 RefPtr<TextLayoutProperty> curLayoutProperty = curPattern->GetLayoutProperty<TextLayoutProperty>();
1266 CHECK_NULL_VOID(curLayoutProperty);
1267
1268 RefPtr<TextPattern> shiftPattern = shiftNode->GetPattern<TextPattern>();
1269 CHECK_NULL_VOID(shiftPattern);
1270 RefPtr<TextLayoutProperty> shiftLayoutProperty = shiftPattern->GetLayoutProperty<TextLayoutProperty>();
1271 CHECK_NULL_VOID(shiftLayoutProperty);
1272 curLayoutProperty->UpdateFontWeight(shiftLayoutProperty->GetFontWeight().value_or(FontWeight::W100));
1273 }
1274
CanMove(bool isDown) const1275 bool TimePickerColumnPattern::CanMove(bool isDown) const
1276 {
1277 if (wheelModeEnabled_) {
1278 CHECK_NULL_RETURN(NotLoopOptions(), true);
1279 }
1280 auto host = GetHost();
1281 CHECK_NULL_RETURN(host, false);
1282 auto options = GetOptions();
1283 int totalOptionCount = static_cast<int>(options[host]);
1284 auto timePickerColumnPattern = host->GetPattern<TimePickerColumnPattern>();
1285 CHECK_NULL_RETURN(timePickerColumnPattern, false);
1286 int currentIndex = static_cast<int>(timePickerColumnPattern->GetCurrentIndex());
1287 int nextVirtualIndex = isDown ? currentIndex + 1 : currentIndex - 1;
1288 return nextVirtualIndex >= 0 && nextVirtualIndex < totalOptionCount;
1289 }
1290
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1291 void TimePickerColumnPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1292 {
1293 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1294 auto pattern = wp.Upgrade();
1295 CHECK_NULL_RETURN(pattern, false);
1296 return pattern->OnKeyEvent(event);
1297 };
1298 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1299 }
1300
OnKeyEvent(const KeyEvent & event)1301 bool TimePickerColumnPattern::OnKeyEvent(const KeyEvent& event)
1302 {
1303 if (event.action != KeyAction::DOWN) {
1304 return false;
1305 }
1306 if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN) {
1307 HandleDirectionKey(event.code);
1308 return true;
1309 }
1310 return false;
1311 }
1312
HandleDirectionKey(KeyCode code)1313 bool TimePickerColumnPattern::HandleDirectionKey(KeyCode code)
1314 {
1315 if (code == KeyCode::KEY_DPAD_UP) {
1316 // Need to update: current selection
1317 return true;
1318 }
1319 if (code == KeyCode::KEY_DPAD_DOWN) {
1320 // Need to update: current selection
1321 return true;
1322 }
1323 return false;
1324 }
1325
SetAccessibilityAction()1326 void TimePickerColumnPattern::SetAccessibilityAction()
1327 {
1328 auto host = GetHost();
1329 CHECK_NULL_VOID(host);
1330 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1331 CHECK_NULL_VOID(accessibilityProperty);
1332 accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1333 const auto& pattern = weakPtr.Upgrade();
1334 CHECK_NULL_VOID(pattern);
1335 if (!pattern->CanMove(true)) {
1336 return;
1337 }
1338 CHECK_NULL_VOID(pattern->animationCreated_);
1339 pattern->InnerHandleScroll(true);
1340 pattern->CreateAnimation(0.0 - pattern->jumpInterval_, 0.0);
1341 // AccessibilityEventType::SCROLL_END
1342 });
1343
1344 accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
1345 const auto& pattern = weakPtr.Upgrade();
1346 CHECK_NULL_VOID(pattern);
1347 if (!pattern->CanMove(false)) {
1348 return;
1349 }
1350 CHECK_NULL_VOID(pattern->animationCreated_);
1351 pattern->InnerHandleScroll(false);
1352 pattern->CreateAnimation(pattern->jumpInterval_, 0.0);
1353 // AccessibilityEventType::SCROLL_END
1354 });
1355 }
1356
CreateItemClickEventListener(RefPtr<TimePickerEventParam> param)1357 RefPtr<ClickEvent> TimePickerColumnPattern::CreateItemClickEventListener(RefPtr<TimePickerEventParam> param)
1358 {
1359 auto clickEventHandler = [param, weak = WeakClaim(this)](const GestureEvent& /* info */) {
1360 auto pattern = weak.Upgrade();
1361 pattern->OnAroundButtonClick(param);
1362 };
1363 auto listener = AceType::MakeRefPtr<NG::ClickEvent>(clickEventHandler);
1364 return listener;
1365 }
1366
OnAroundButtonClick(RefPtr<TimePickerEventParam> param)1367 void TimePickerColumnPattern::OnAroundButtonClick(RefPtr<TimePickerEventParam> param)
1368 {
1369 if (clickBreak_) {
1370 return;
1371 }
1372 int32_t middleIndex = static_cast<int32_t>(GetShowCount()) / 2;
1373 int32_t step = param->itemIndex_ - middleIndex;
1374 if (step != 0) {
1375 if (animation_) {
1376 AnimationUtils::StopAnimation(animation_);
1377 yLast_ = 0.0;
1378 yOffset_ = 0.0;
1379 }
1380 auto distance =
1381 (step > 0 ? optionProperties_[middleIndex].prevDistance : optionProperties_[middleIndex].nextDistance) *
1382 std::abs(step);
1383 AnimationOption option;
1384 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
1385 option.SetDuration(CLICK_ANIMATION_DURATION);
1386 aroundClickProperty_->Set(0.0);
1387 animation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), step, distance]() {
1388 auto column = weak.Upgrade();
1389 CHECK_NULL_VOID(column);
1390 column->aroundClickProperty_->Set(step > 0 ? 0.0 - std::abs(distance) : std::abs(distance));
1391 });
1392 auto host = GetHost();
1393 CHECK_NULL_VOID(host);
1394 auto pipeline = host->GetContext();
1395 CHECK_NULL_VOID(pipeline);
1396 pipeline->RequestFrame();
1397 }
1398 }
TossAnimationStoped()1399 void TimePickerColumnPattern::TossAnimationStoped()
1400 {
1401 if (hapticController_) {
1402 hapticController_->Stop();
1403 }
1404 yLast_ = 0.0;
1405 }
1406
PlayRestAnimation()1407 void TimePickerColumnPattern::PlayRestAnimation()
1408 {
1409 TimePickerScrollDirection dir =
1410 scrollDelta_ > 0.0 ? TimePickerScrollDirection::DOWN : TimePickerScrollDirection::UP;
1411 int32_t middleIndex = static_cast<int32_t>(GetShowCount()) / 2;
1412 double shiftDistance = (dir == TimePickerScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
1413 : optionProperties_[middleIndex].nextDistance;
1414 double shiftThreshold = shiftDistance / 2;
1415 if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
1416 InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true);
1417 scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == TimePickerScrollDirection::UP ? -1 : 1);
1418 }
1419
1420 CreateAnimation(scrollDelta_, 0.0);
1421 }
1422
CalculateHotZone(int32_t index,int32_t midSize,float middleChildHeight,float otherChildHeight)1423 DimensionRect TimePickerColumnPattern::CalculateHotZone(
1424 int32_t index, int32_t midSize, float middleChildHeight, float otherChildHeight)
1425 {
1426 float hotZoneHeight = 0.0f;
1427 float hotZoneOffsetY = 0.0f;
1428 if (index == midSize) {
1429 hotZoneHeight = middleChildHeight;
1430 }
1431 if (size_.Height() <= middleChildHeight) {
1432 hotZoneHeight = index == midSize ? size_.Height() : 0;
1433 } else if (size_.Height() <= (middleChildHeight + HOT_ZONE_HEIGHT_CANDIDATE * otherChildHeight)) {
1434 if ((index == midSize + 1) || (index == midSize - 1)) {
1435 hotZoneHeight = (size_.Height() - middleChildHeight) / MIDDLE_CHILD_INDEX;
1436 hotZoneOffsetY = (index == midSize - 1) ? (otherChildHeight - hotZoneHeight) : 0;
1437 }
1438 } else if (size_.Height() <= (middleChildHeight + HOT_ZONE_HEIGHT_DISAPPEAR * otherChildHeight)) {
1439 if ((index == midSize + 1) || (index == midSize - 1)) {
1440 hotZoneHeight = otherChildHeight;
1441 } else if ((index == midSize + HOT_ZONE_HEIGHT_CANDIDATE) || (index == midSize - HOT_ZONE_HEIGHT_CANDIDATE)) {
1442 hotZoneHeight = (size_.Height() - middleChildHeight - HOT_ZONE_HEIGHT_CANDIDATE * otherChildHeight) /
1443 MIDDLE_CHILD_INDEX;
1444 hotZoneOffsetY = (index == midSize - HOT_ZONE_HEIGHT_CANDIDATE) ? (otherChildHeight - hotZoneHeight) : 0;
1445 }
1446 } else {
1447 if ((index == midSize + 1) || (index == midSize - 1)) {
1448 hotZoneHeight = otherChildHeight;
1449 } else if ((index == midSize + HOT_ZONE_HEIGHT_CANDIDATE) || (index == midSize - HOT_ZONE_HEIGHT_CANDIDATE)) {
1450 hotZoneHeight = otherChildHeight;
1451 }
1452 }
1453 OffsetF hotZoneOffset;
1454 SizeF hotZoneSize;
1455 hotZoneOffset.SetX(0.0f);
1456 hotZoneOffset.SetY(hotZoneOffsetY);
1457 hotZoneSize.SetWidth(size_.Width());
1458 hotZoneSize.SetHeight(hotZoneHeight);
1459 DimensionRect hotZoneRegion;
1460 hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize.Width()), Dimension(hotZoneSize.Height())));
1461 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset.GetX()), Dimension(hotZoneOffset.GetY())));
1462 return hotZoneRegion;
1463 }
1464
AddHotZoneRectToText()1465 void TimePickerColumnPattern::AddHotZoneRectToText()
1466 {
1467 auto host = GetHost();
1468 CHECK_NULL_VOID(host);
1469 auto childSize = static_cast<int32_t>(host->GetChildren().size());
1470 auto midSize = childSize / MIDDLE_CHILD_INDEX;
1471 auto middleChildHeight = optionProperties_[midSize].height;
1472 auto otherChildHeight = optionProperties_[midSize - 1].height;
1473 for (int32_t i = 0; i < childSize; i++) {
1474 RefPtr<FrameNode> childNode = DynamicCast<FrameNode>(host->GetChildAtIndex(i));
1475 CHECK_NULL_VOID(childNode);
1476 DimensionRect hotZoneRegion = CalculateHotZone(i, midSize, middleChildHeight, otherChildHeight);
1477 childNode->AddHotZoneRect(hotZoneRegion);
1478 }
1479 }
1480 } // namespace OHOS::Ace::NG
1481