• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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_overscroll.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components_ng/pattern/text_picker/textpicker_column_pattern.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 const int32_t HALF_NUMBER = 2;
24 constexpr float MIN_SCROLL = 0.1f;
25 constexpr float MIN_VELOCITY = 200.f;
26 constexpr float REBOUND_SCROLL_DAMPING = -1.848f;
27 constexpr float REBOUND_SPRING_VELOCITY = 1.f;
28 constexpr float REBOUND_SPRING_MASS = 1.f;
29 constexpr float REBOUND_SPRING_STIFFNESS = 228.f;
30 constexpr float REBOUND_SPRING_DAMPING = 30.f;
31 constexpr float LOOP_TOSS_DAMPING = 100.f;
32 } //namespace
ApplyCurrentOffset(float yLast,float offsetY,float scrollDelta)33 bool TextPickerOverscroller::ApplyCurrentOffset(float yLast, float offsetY, float scrollDelta)
34 {
35     auto column = AceType::DynamicCast<TextPickerColumnPattern>(column_.Upgrade());
36     CHECK_NULL_RETURN(column, false);
37     auto hostNode = column->GetHost();
38     CHECK_NULL_RETURN(hostNode, false);
39     auto geometryNode = hostNode->GetGeometryNode();
40     CHECK_NULL_RETURN(geometryNode, false);
41     height_ = geometryNode->GetFrameSize().Height();
42 
43     if (!CanOverScroll(scrollDelta)) {
44         overScroll_ = 0.0;
45         backScrollOffset_ = 0.0;
46         return false;
47     }
48 
49     // start overScroll
50     isFirstStart_ = false;
51     if (NearZero(overScroll_)) {
52         overScrollStartOffsetY_ = yLast;
53         isFirstStart_ = true;
54     }
55 
56     deltaScrollOffset_ = GetOverScrollOffset(yLast, offsetY);
57 
58     auto isSignDiff = LessNotEqual(deltaScrollOffset_ * overScroll_, 0.0);
59     auto isBackZero = isSignDiff && GreatOrEqual(std::fabs(deltaScrollOffset_), std::fabs(overScroll_));
60     if (!NearZero(overScroll_) && isBackZero) { // overScroll come back zero
61         overScroll_ = 0.0;
62         backScrollOffset_ = overScroll_ + deltaScrollOffset_;
63     } else {
64         overScroll_ += deltaScrollOffset_;
65         overScroll_ = (overScroll_ > 0.0 ? 1 : -1) * std::min(std::fabs(overScroll_), height_ / HALF_NUMBER);
66         backScrollOffset_ = 0.0;
67     }
68 
69     return true;
70 }
71 
CanOverScroll(float scrollDelta) const72 bool TextPickerOverscroller::CanOverScroll(float scrollDelta) const
73 {
74     if (NearZero(scrollDelta)) {
75         return false;
76     }
77 
78     auto column = AceType::DynamicCast<TextPickerColumnPattern>(column_.Upgrade());
79     CHECK_NULL_RETURN(column, false);
80     auto currentIdx = column->GetCurrentIndex();
81     auto optionCount = column->GetOptionCount();
82 
83     auto isDown = GreatNotEqual(overScroll_, 0.0) || (GreatNotEqual(scrollDelta, 0.0) && NearZero(overScroll_));
84     auto isUp = LessNotEqual(overScroll_, 0.0) || (LessNotEqual(scrollDelta, 0.0) && NearZero(overScroll_));
85     return (currentIdx == 0 && isDown) || (currentIdx == optionCount - 1 && isUp);
86 }
87 
GetOverScrollOffset(float yLast,float offsetY) const88 float TextPickerOverscroller::GetOverScrollOffset(float yLast, float offsetY) const
89 {
90     auto dx = offsetY - yLast;
91     auto input = NearZero(height_) ? 0.0 : std::fabs(offsetY - overScrollStartOffsetY_) / height_;
92     return dx * std::exp(REBOUND_SCROLL_DAMPING * input);
93 }
94 
GetReboundCurve() const95 RefPtr<Curve> TextPickerOverscroller::GetReboundCurve() const
96 {
97     return AceType::MakeRefPtr<InterpolatingSpring>(
98         REBOUND_SPRING_VELOCITY, REBOUND_SPRING_MASS, REBOUND_SPRING_STIFFNESS, REBOUND_SPRING_DAMPING);
99 }
100 
UpdateTossSpring(float offsetY)101 void TextPickerOverscroller::UpdateTossSpring(float offsetY)
102 {
103     velocityTracker_.UpdateTrackerPoint(0.0, offsetY, std::chrono::high_resolution_clock::now());
104 }
105 
ShouldStartRebound()106 bool TextPickerOverscroller::ShouldStartRebound()
107 {
108     auto damping = NearZero(loopTossOffset_) ? 1.0 : LOOP_TOSS_DAMPING / std::abs(loopTossOffset_);
109     auto velocity = std::abs(velocityTracker_.GetVelocity().GetVelocityY()) * damping;
110     auto canRebound = !isFirstStart_ && velocity < MIN_VELOCITY;
111     return canRebound || InMaxOverScroll() || NearZero(deltaScrollOffset_, MIN_SCROLL);
112 }
113 
Reset()114 void TextPickerOverscroller::Reset()
115 {
116     overScroll_ = 0.0;
117     backScrollOffset_ = 0.0;
118     deltaScrollOffset_ = 0.0;
119     overScrollStartOffsetY_ = 0.0;
120     isFirstStart_ = false;
121     loopTossOffset_ = 0.0;
122     velocityTracker_.Reset();
123 }
124 
InMaxOverScroll() const125 bool TextPickerOverscroller::InMaxOverScroll() const
126 {
127     return GreatOrEqual(std::fabs(overScroll_), height_ / HALF_NUMBER);
128 }
129 
IsOverScroll() const130 bool TextPickerOverscroller::IsOverScroll() const
131 {
132     return !NearZero(overScroll_);
133 }
134 
IsBackOverScroll() const135 bool TextPickerOverscroller::IsBackOverScroll() const
136 {
137     return !NearZero(backScrollOffset_);
138 }
139 } // namespace OHOS::Ace::NG