• 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/list/interactive_effect.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/animation/keyframe.h"
20 #include "core/components/list/render_list_item.h"
21 
22 namespace OHOS::Ace {
23 namespace {
24 
25 constexpr int32_t TOUCH_START_DELAY = 100; // Unit: milliseconds.
26 
27 } // namespace
28 
InteractiveEffect(const WeakPtr<PipelineContext> & context)29 InteractiveEffect::InteractiveEffect(const WeakPtr<PipelineContext>& context)
30 {
31     auto pipelineContext = context.Upgrade();
32     if (pipelineContext) {
33         context_ = pipelineContext;
34         controller_ = AceType::MakeRefPtr<Animator>(pipelineContext);
35     } else {
36         LOGE("context is null.");
37     }
38 }
39 
UpdateContext(const WeakPtr<PipelineContext> & context)40 void InteractiveEffect::UpdateContext(const WeakPtr<PipelineContext>& context)
41 {
42     auto pipelineContext = context.Upgrade();
43     if (pipelineContext) {
44         context_ = pipelineContext;
45         controller_ = AceType::MakeRefPtr<Animator>(pipelineContext);
46     }
47 }
48 
Initialize(const RefPtr<ThemeManager> & themeManager)49 void InteractiveEffect::Initialize(const RefPtr<ThemeManager>& themeManager)
50 {
51     if (!themeManager) {
52         return;
53     }
54     if (!theme_) {
55         theme_ = themeManager->GetTheme<ListItemTheme>();
56     }
57 }
58 
FinishPreviousAnimation()59 void InteractiveEffect::FinishPreviousAnimation()
60 {
61     if (controller_ && !controller_->IsStopped()) {
62         controller_->Finish();
63     }
64 }
65 
ShowAnimation(ItemState state)66 void InteractiveEffect::ShowAnimation(ItemState state)
67 {
68     FinishPreviousAnimation();
69     switch (state) {
70         case ItemState::FOCUS:
71             HandleOnFocus();
72             BuildStateAnimation();
73             break;
74         case ItemState::BLUR:
75             HandleOnBlur();
76             BuildStateAnimation();
77             break;
78         case ItemState::CLICK:
79             HandleOnClick();
80             BuildClickAnimation();
81             break;
82         default:
83             LOGW("invalid state.");
84             break;
85     }
86 }
87 
TouchDownAnimation()88 void InteractiveEffect::TouchDownAnimation()
89 {
90     FinishPreviousAnimation();
91     if (!theme_) {
92         LOGE("theme is invalid, stop build animation");
93         EventReport::SendComponentException(ComponentExcepType::GET_THEME_ERR);
94         return;
95     }
96     RefPtr<KeyframeAnimation<double>> alphaAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
97     CreateDoubleAnimation(alphaAnimation, alphaBegin_, alphaEnd_);
98     StartTouchAnimation(controller_, alphaAnimation, TOUCH_START_DELAY);
99 }
100 
TouchUpAnimation()101 void InteractiveEffect::TouchUpAnimation()
102 {
103     FinishPreviousAnimation();
104     if (!theme_) {
105         LOGE("theme is invalid, stop build animation");
106         EventReport::SendComponentException(ComponentExcepType::GET_THEME_ERR);
107         return;
108     }
109     RefPtr<KeyframeAnimation<double>> alphaAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
110     CreateDoubleAnimation(alphaAnimation, GetAlpha(), alphaBegin_);
111     StartTouchAnimation(controller_, alphaAnimation);
112 }
113 
CancelTouchAnimation()114 void InteractiveEffect::CancelTouchAnimation()
115 {
116     if (!theme_) {
117         LOGE("theme is invalid, stop build animation");
118         EventReport::SendComponentException(ComponentExcepType::GET_THEME_ERR);
119         return;
120     }
121     if (controller_ && !controller_->IsStopped()) {
122         controller_->Stop();
123     }
124     double currentAlpha = GetAlpha();
125     if (NearEqual(currentAlpha, alphaBegin_)) {
126         return;
127     }
128     RefPtr<KeyframeAnimation<double>> alphaAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
129     CreateDoubleAnimation(alphaAnimation, currentAlpha, alphaBegin_);
130     StartTouchAnimation(controller_, alphaAnimation);
131 }
132 
StartTouchAnimation(RefPtr<Animator> controller,RefPtr<KeyframeAnimation<double>> & doubleAnimation,int32_t startDelay)133 void InteractiveEffect::StartTouchAnimation(RefPtr<Animator> controller,
134     RefPtr<KeyframeAnimation<double>>& doubleAnimation, int32_t startDelay)
135 {
136     if (!controller || !doubleAnimation) {
137         return;
138     }
139     controller->ClearInterpolators();
140     controller->SetStartDelay(startDelay);
141     controller->AddInterpolator(doubleAnimation);
142     controller->SetDuration(PRESS_ANIMATION_DURATION);
143     controller->SetFillMode(FillMode::FORWARDS);
144     controller->Play();
145 }
146 
CreateDoubleAnimation(RefPtr<KeyframeAnimation<double>> & doubleAnimation,double beginValue,double endValue)147 void InteractiveEffect::CreateDoubleAnimation(RefPtr<KeyframeAnimation<double>>& doubleAnimation, double beginValue,
148     double endValue)
149 {
150     if (!doubleAnimation) {
151         return;
152     }
153     auto alphaFrameStart = AceType::MakeRefPtr<Keyframe<double>>(ANIMATION_ZERO_TIME, beginValue);
154     auto alphaFrameEnd = AceType::MakeRefPtr<Keyframe<double>>(ANIMATION_END_TIME, endValue);
155     doubleAnimation->SetCurve(Curves::SHARP);
156     doubleAnimation->AddKeyframe(alphaFrameStart);
157     doubleAnimation->AddKeyframe(alphaFrameEnd);
158     doubleAnimation->AddListener([weakEffect = AceType::WeakClaim(this)](double value) {
159         auto effect = weakEffect.Upgrade();
160         if (effect) {
161             effect->SetAlpha(value);
162             effect->MarkItemRender();
163         }
164     });
165 }
166 
NeedClickAnimation()167 bool InteractiveEffect::NeedClickAnimation()
168 {
169     auto node = item_.Upgrade();
170     RefPtr<RenderListItem> listItem;
171     if (!node || !AceType::DynamicCast<RenderListItem>(node)) {
172         return false;
173     } else {
174         listItem = AceType::DynamicCast<RenderListItem>(node);
175         if (!listItem->GetSupportClick()) {
176             return false;
177         }
178     }
179     return true;
180 }
181 
BuildClickAnimation()182 void InteractiveEffect::BuildClickAnimation()
183 {
184     if (!theme_) {
185         LOGE("theme is invalid, stop build animation");
186         EventReport::SendComponentException(ComponentExcepType::GET_THEME_ERR);
187         return;
188     }
189 
190     if (!NeedClickAnimation()) {
191         return;
192     }
193 
194     RefPtr<KeyframeAnimation<double>> alphaAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
195     BuildClickAlphaAnimation(alphaAnimation);
196     if (controller_) {
197         controller_->ClearInterpolators();
198         controller_->AddInterpolator(alphaAnimation);
199         controller_->SetDuration(clickDuration_);
200         controller_->Play();
201     }
202 }
203 
MarkItemRender()204 void InteractiveEffect::MarkItemRender()
205 {
206     auto item = item_.Upgrade();
207     if (item) {
208         item->MarkNeedRender();
209         auto listItem = AceType::DynamicCast<RenderListItem>(item);
210         if (listItem) {
211             if (listItem->GetSticky()) {
212                 auto list = list_.Upgrade();
213                 if (list) {
214                     list->MarkNeedRender();
215                 }
216             }
217         }
218     }
219 }
220 
BuildClickAlphaAnimation(const RefPtr<KeyframeAnimation<double>> & alphaAnimation)221 void InteractiveEffect::BuildClickAlphaAnimation(const RefPtr<KeyframeAnimation<double>>& alphaAnimation)
222 {
223     auto alphaFrameStart = AceType::MakeRefPtr<Keyframe<double>>(ANIMATION_ZERO_TIME, alphaBegin_);
224     auto alphaFrameMid = AceType::MakeRefPtr<Keyframe<double>>(ANIMATION_HALF_TIME, alphaEnd_);
225     auto alphaFrameEnd = AceType::MakeRefPtr<Keyframe<double>>(ANIMATION_END_TIME, alphaBegin_);
226     alphaFrameMid->SetCurve(Curves::FRICTION);
227     alphaFrameEnd->SetCurve(Curves::FRICTION);
228 
229     alphaAnimation->AddKeyframe(alphaFrameStart);
230     alphaAnimation->AddKeyframe(alphaFrameMid);
231     alphaAnimation->AddKeyframe(alphaFrameEnd);
232     alphaAnimation->AddListener([weakEffect = AceType::WeakClaim(this)](double value) {
233         auto effect = weakEffect.Upgrade();
234         if (effect) {
235             effect->SetAlpha(value);
236             effect->MarkItemRender();
237         }
238     });
239 }
240 
241 } // namespace OHOS::Ace
242