• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/scroll/scroll_fade_controller.h"
17 
18 #include "core/pipeline/pipeline_context.h"
19 
20 namespace OHOS::Ace {
21 namespace {
22 
23 constexpr int32_t RECEDE_TIME = 600;       // milliseconds
24 constexpr int32_t PULL_TIME = 167;         // milliseconds
25 constexpr int32_t PULL_HOLD_TIME = 167;    // milliseconds
26 constexpr int32_t PULL_RECEDE_TIME = 1000; // milliseconds
27 constexpr double MIN_VELOCITY = 100.0;
28 constexpr double MAX_VELOCITY = 10000.0;
29 constexpr double MIN_OPACITY = 0.15;
30 constexpr double MAX_OPACITY = 0.5;
31 constexpr double DEFAULT_OPACITY = 0.3;
32 constexpr double MAX_SCALE_SIZE = 1.0;
33 constexpr double VELOCITY_FACTOR = 0.00006;
34 constexpr double WIDTH_TO_HEIGHT_FACTOR = 0.20096; // (3.0 / 4.0) * (2.0 - std::sqrt(3));
35 constexpr double SCALE_SIZE_BASE = 0.025;
36 constexpr double SCALE_VELOCITY_FACTOR = 7.5e-7;
37 constexpr double DURATION_BASE = 0.15;
38 constexpr double DURATION_VELOCITY_FACTOR = 0.02;
39 constexpr double OVER_DISTANCE_SCALE = 200.0;
40 constexpr double PULL_OPACITY_FACTOR = 3.2;
41 constexpr double SCALE_CALCULATOR_FACTOR = 0.7;
42 
43 } // namespace
44 
ScrollFadeController(const WeakPtr<PipelineContext> & context)45 ScrollFadeController::ScrollFadeController(const WeakPtr<PipelineContext>& context) : context_(context)
46 {
47     Initialize();
48 }
49 
~ScrollFadeController()50 ScrollFadeController::~ScrollFadeController()
51 {
52     // If animation still runs, force stop it.
53     if (controller_ && !controller_->IsStopped()) {
54         controller_->Stop();
55     }
56     pullTask_.Cancel();
57 }
58 
Initialize()59 void ScrollFadeController::Initialize()
60 {
61     decele_ = AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 1.0, Curves::DECELE);
62     auto weak = AceType::WeakClaim(this);
63     decele_->AddListener([weak](double value) {
64         auto controller = weak.Upgrade();
65         if (controller) {
66             controller->DecelerateListener(value);
67         }
68     });
69 
70     controller_ = AceType::MakeRefPtr<Animator>(context_);
71     controller_->AddInterpolator(decele_);
72     controller_->AddStopListener([weak]() {
73         auto controller = weak.Upgrade();
74         if (controller) {
75             controller->ChangeState();
76         }
77     });
78 }
79 
DecelerateListener(double value)80 void ScrollFadeController::DecelerateListener(double value)
81 {
82     opacity_ = opacityFloor_ + value * (opacityCeil_ - opacityFloor_);
83     scaleSize_ = scaleSizeFloor_ + value * (scaleSizeCeil_ - scaleSizeFloor_);
84     if (callback_) {
85         callback_(opacity_, scaleSize_);
86     }
87 }
88 
ProcessAbsorb(double velocity)89 void ScrollFadeController::ProcessAbsorb(double velocity)
90 {
91     LOGD("ProcessAbsorb enter: velocity(%{public}lf)", velocity);
92     if (velocity < 0.0 || state_ == OverScrollState::PULL) {
93         return;
94     }
95     pullTask_.Cancel();
96     velocity = std::clamp(velocity, MIN_VELOCITY, MAX_VELOCITY);
97     opacityFloor_ = state_ == OverScrollState::IDLE ? DEFAULT_OPACITY : opacity_;
98     opacityCeil_ = std::clamp(velocity * VELOCITY_FACTOR, opacityFloor_, MAX_OPACITY);
99     scaleSizeFloor_ = scaleSize_;
100     scaleSizeCeil_ = std::min(SCALE_SIZE_BASE + SCALE_VELOCITY_FACTOR * velocity * velocity, MAX_SCALE_SIZE);
101     if (controller_) {
102         controller_->SetDuration(std::round(DURATION_BASE + velocity * DURATION_VELOCITY_FACTOR));
103         controller_->Play();
104         state_ = OverScrollState::ABSORB;
105     }
106 }
107 
ProcessPull(double overDistance,double mainAxisExtent,double crossAxisExtent)108 void ScrollFadeController::ProcessPull(double overDistance, double mainAxisExtent, double crossAxisExtent)
109 {
110     LOGD("ProcessPull enter:overDistance(%{public}lf), mainAxisExtent(%{public}lf), crossAxisExtent(%{public}lf)",
111         overDistance, mainAxisExtent, crossAxisExtent);
112     pullTask_.Cancel();
113     opacityFloor_ = std::min(MIN_OPACITY + opacity_, DEFAULT_OPACITY);
114     opacityCeil_ = NearZero(mainAxisExtent)
115                        ? MAX_OPACITY
116                        : std::min(opacity_ + overDistance / mainAxisExtent * PULL_OPACITY_FACTOR, MAX_OPACITY);
117     double height = std::min(mainAxisExtent, crossAxisExtent * WIDTH_TO_HEIGHT_FACTOR);
118     pullDistance_ += overDistance / OVER_DISTANCE_SCALE;
119     scaleSizeFloor_ = scaleSize_;
120     double scaleByPullDistance = SCALE_CALCULATOR_FACTOR * std::sqrt(pullDistance_ * height);
121     scaleSizeCeil_ = NearZero(scaleSize_) ? MAX_SCALE_SIZE
122                                           : std::max(MAX_SCALE_SIZE - MAX_SCALE_SIZE / scaleByPullDistance, scaleSize_);
123     LOGD("opacityFloor_(%{public}lf), opacityCeil_(%{public}lf)", opacityFloor_, opacityCeil_);
124     LOGD("scaleSizeFloor_(%{public}lf), scaleSizeCeil_(%{public}lf)", scaleSizeFloor_, scaleSizeCeil_);
125     if (controller_) {
126         controller_->SetDuration(PULL_TIME);
127         if (state_ != OverScrollState::PULL) {
128             controller_->Play();
129             state_ = OverScrollState::PULL;
130         } else {
131             controller_->Stop();
132             controller_->Play();
133         }
134     }
135 
136     SchedulePullHoldTask();
137 }
138 
ProcessRecede(int32_t duration)139 void ScrollFadeController::ProcessRecede(int32_t duration)
140 {
141     LOGD("ProcessRecede enter:duration(%{public}d)", duration);
142     if (state_ == OverScrollState::RECEDE || state_ == OverScrollState::IDLE) {
143         LOGD("current state do not support recede:state_(%{public}d)", state_);
144         return;
145     }
146     pullTask_.Cancel();
147     opacityFloor_ = opacity_;
148     opacityCeil_ = 0.0;
149     scaleSizeFloor_ = scaleSize_;
150     scaleSizeCeil_ = 0.0;
151     if (controller_) {
152         controller_->SetDuration(duration);
153         controller_->Play();
154         state_ = OverScrollState::RECEDE;
155     }
156 }
157 
ChangeState()158 void ScrollFadeController::ChangeState()
159 {
160     LOGD("ChangeState enter: old(%{public}d)", state_);
161     switch (state_) {
162         case OverScrollState::RECEDE:
163             state_ = OverScrollState::IDLE;
164             pullDistance_ = 0.0;
165             break;
166         case OverScrollState::ABSORB:
167             ProcessRecede(RECEDE_TIME);
168             break;
169         case OverScrollState::PULL:
170         case OverScrollState::IDLE:
171             break;
172         default:
173             break;
174     }
175 }
176 
SchedulePullHoldTask()177 void ScrollFadeController::SchedulePullHoldTask()
178 {
179     const auto context = context_.Upgrade();
180     if (!context) {
181         LOGW("No context exists.");
182         return;
183     }
184 
185     if (!context->GetTaskExecutor()) {
186         LOGW("context has no task executor.");
187         return;
188     }
189 
190     pullTask_.Reset([weak = WeakClaim(this)] {
191         auto client = weak.Upgrade();
192         if (client) {
193             client->ProcessRecede(PULL_RECEDE_TIME);
194         }
195     });
196     context->GetTaskExecutor()->PostDelayedTask(pullTask_, TaskExecutor::TaskType::UI, PULL_HOLD_TIME);
197 }
198 
199 } // namespace OHOS::Ace