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/manager/shared_overlay/shared_transition_effect.h"
17
18 #include "base/utils/utils.h"
19 #include "core/components/common/layout/constants.h"
20 #include "core/components/common/properties/animation_option.h"
21 #include "core/components/common/properties/motion_path_evaluator.h"
22 #include "core/components_ng/base/frame_node.h"
23 #include "core/components_ng/layout/layout_property.h"
24 #include "core/components_ng/property/property.h"
25
26 namespace OHOS::Ace::NG {
SharedTransitionEffect(const ShareId & shareId,const std::shared_ptr<SharedTransitionOption> & sharedOption)27 SharedTransitionEffect::SharedTransitionEffect(
28 const ShareId& shareId, const std::shared_ptr<SharedTransitionOption>& sharedOption)
29 : shareId_(shareId), option_(sharedOption)
30 {
31 std::string animatorName = "SharedTransition(" + shareId + ")";
32 controller_ = CREATE_ANIMATOR(animatorName.c_str());
33 }
34
GetSharedTransitionEffect(const ShareId & shareId,const std::shared_ptr<SharedTransitionOption> & option)35 RefPtr<SharedTransitionEffect> SharedTransitionEffect::GetSharedTransitionEffect(
36 const ShareId& shareId, const std::shared_ptr<SharedTransitionOption>& option)
37 {
38 CHECK_NULL_RETURN(option, nullptr);
39 RefPtr<SharedTransitionEffect> effect;
40 if (option->type == SharedTransitionEffectType::SHARED_EFFECT_EXCHANGE) {
41 effect = AceType::MakeRefPtr<SharedTransitionExchange>(shareId, option);
42 } else {
43 effect = AceType::MakeRefPtr<SharedTransitionStatic>(shareId, option);
44 }
45 return effect;
46 }
47
PerformFinishCallback()48 void SharedTransitionEffect::PerformFinishCallback()
49 {
50 for (const auto& callback : finishCallbacks_) {
51 if (callback) {
52 callback();
53 }
54 }
55 finishCallbacks_.clear();
56 }
57
CreateOpacityAnimation(float startOpacity,float endOpacity,float finalOpacity,const WeakPtr<FrameNode> & node)58 bool SharedTransitionEffect::CreateOpacityAnimation(
59 float startOpacity, float endOpacity, float finalOpacity, const WeakPtr<FrameNode>& node)
60 {
61 if (NearEqual(startOpacity, endOpacity)) {
62 // no need to perform opacity animation
63 return true;
64 }
65 auto opacityAnimation = AceType::MakeRefPtr<CurveAnimation<float>>(startOpacity, endOpacity, option_->curve);
66 auto opacityListener = [weakFrame = node](const float& opacity) {
67 auto node = weakFrame.Upgrade();
68 CHECK_NULL_VOID(node);
69 node->GetRenderContext()->UpdateOpacity(opacity);
70 };
71 opacityAnimation->AddListener(opacityListener);
72 controller_->AddInterpolator(opacityAnimation);
73 controller_->AddStopListener([weakFrame = node, finalOpacity]() {
74 auto node = weakFrame.Upgrade();
75 CHECK_NULL_VOID(node);
76 node->GetRenderContext()->UpdateOpacity(finalOpacity);
77 });
78 return true;
79 }
80
ApplyAnimation()81 bool SharedTransitionEffect::ApplyAnimation()
82 {
83 CHECK_NULL_RETURN(option_, false);
84 controller_->SetDuration(option_->duration);
85 controller_->SetStartDelay(option_->delay);
86 return true;
87 }
88
SharedTransitionExchange(const ShareId & shareId,const std::shared_ptr<SharedTransitionOption> & sharedOption)89 SharedTransitionExchange::SharedTransitionExchange(
90 const ShareId& shareId, const std::shared_ptr<SharedTransitionOption>& sharedOption)
91 : SharedTransitionEffect(shareId, sharedOption)
92 {}
93
Allow() const94 bool SharedTransitionExchange::Allow() const
95 {
96 auto dest = dest_.Upgrade();
97 auto src = src_.Upgrade();
98 if (!dest || !src) {
99 return false;
100 }
101 return !GetShareId().empty();
102 }
103
CreateAnimation()104 bool SharedTransitionExchange::CreateAnimation()
105 {
106 auto src = src_.Upgrade();
107 auto dest = dest_.Upgrade();
108 if (!dest || !src) {
109 return false;
110 }
111 CHECK_NULL_RETURN(option_, false);
112 CHECK_NULL_RETURN(option_->curve, false);
113 if (!CreateTranslateAnimation(src, dest)) {
114 return false;
115 }
116 if (!CreateSizeAnimation(src, dest)) {
117 return false;
118 }
119 if (!CreateOpacityAnimation(src, dest)) {
120 return false;
121 }
122 return true;
123 }
124
CreateTranslateAnimation(const RefPtr<FrameNode> & src,const RefPtr<FrameNode> & dest)125 bool SharedTransitionExchange::CreateTranslateAnimation(const RefPtr<FrameNode>& src, const RefPtr<FrameNode>& dest)
126 {
127 auto destOffset = dest->GetPaintRectOffsetToPage();
128 auto srcOffset = src->GetPaintRectOffsetToPage();
129 TAG_LOGI(AceLogTag::ACE_ANIMATION,
130 "Translate animation get Offset, share id: %{public}s. src: %{public}s, dest: %{public}s", GetShareId().c_str(),
131 srcOffset.ToString().c_str(), destOffset.ToString().c_str());
132 if (NearEqual(destOffset, srcOffset)) {
133 return true;
134 }
135 Offset diff { destOffset.GetX() - srcOffset.GetX(), destOffset.GetY() - srcOffset.GetY() };
136 auto translateAnimation = AceType::MakeRefPtr<CurveAnimation<DimensionOffset>>(Offset(0, 0), diff, option_->curve);
137 auto srcRenderContext = src->GetRenderContext();
138 std::optional<Vector5F> srcRotate;
139 if (option_->motionPathOption.IsValid()) {
140 auto motionPathEvaluator =
141 AceType::MakeRefPtr<MotionPathEvaluator>(option_->motionPathOption, Offset(0, 0), diff);
142 translateAnimation->SetEvaluator(motionPathEvaluator->CreateDimensionOffsetEvaluator());
143 if (option_->motionPathOption.GetRotate()) {
144 // Just need to add a rotation animation, the specific rotation Angle is calculated through the path
145 auto rotateAnimation = AceType::MakeRefPtr<CurveAnimation<float>>(0.0f, 0.0f, option_->curve);
146 rotateAnimation->SetEvaluator(motionPathEvaluator->CreateRotateEvaluator());
147 auto rotateListener = [weakSrc = WeakPtr<RenderContext>(srcRenderContext)](float value) {
148 auto srcNode = weakSrc.Upgrade();
149 CHECK_NULL_VOID(srcNode);
150 // Rotate around the Z axis
151 srcNode->UpdateTransformRotate({ 0, 0, 1, value, 0 });
152 };
153 rotateAnimation->AddListener(rotateListener);
154 controller_->AddInterpolator(rotateAnimation);
155 srcRotate = srcRenderContext->GetTransformRotateValue({ 0, 0, 1, 0, 0 });
156 }
157 }
158 auto translateListener = [weakSrc = WeakPtr<RenderContext>(srcRenderContext)](const DimensionOffset& value) {
159 auto srcNode = weakSrc.Upgrade();
160 CHECK_NULL_VOID(srcNode);
161 srcNode->SetSharedTranslate(static_cast<float>(value.GetX().Value()), static_cast<float>(value.GetY().Value()));
162 };
163 translateAnimation->AddListener(translateListener);
164 controller_->AddInterpolator(translateAnimation);
165 finishCallbacks_.emplace_back([weakSrc = WeakPtr<RenderContext>(srcRenderContext), srcRotate]() {
166 auto srcNode = weakSrc.Upgrade();
167 CHECK_NULL_VOID(srcNode);
168 srcNode->ResetSharedTranslate();
169 if (srcRotate) {
170 srcNode->UpdateTransformRotate(srcRotate.value());
171 }
172 });
173 return true;
174 }
175
CreateSizeAnimation(const RefPtr<FrameNode> & src,const RefPtr<FrameNode> & dest)176 bool SharedTransitionExchange::CreateSizeAnimation(const RefPtr<FrameNode>& src, const RefPtr<FrameNode>& dest)
177 {
178 auto destSize = dest->GetGeometryNode()->GetFrameSize();
179 auto srcSize = src->GetGeometryNode()->GetFrameSize();
180 if (!destSize.IsPositive()) {
181 TAG_LOGW(AceLogTag::ACE_ANIMATION,
182 "DestSize is %{public}s, means we don't get the size correctly, so create sharedTransition failed"
183 ", sharedId:%{public}s",
184 destSize.ToString().c_str(), GetShareId().c_str());
185 return false;
186 }
187 TAG_LOGI(AceLogTag::ACE_ANIMATION,
188 "Size animation get size, share id: %{public}s. src: %{public}s, dest: %{public}s", GetShareId().c_str(),
189 srcSize.ToString().c_str(), destSize.ToString().c_str());
190 if (NearEqual(srcSize, destSize)) {
191 return true;
192 }
193 const auto& magicProperty = src->GetLayoutProperty()->GetMagicItemProperty();
194 auto initAspectRatio = magicProperty.GetAspectRatio();
195 auto initSize = src->GetLayoutProperty()->GetCalcLayoutConstraint()
196 ? src->GetLayoutProperty()->GetCalcLayoutConstraint()->selfIdealSize
197 : std::nullopt;
198 auto sizeAnimation = AceType::MakeRefPtr<CurveAnimation<SizeF>>(srcSize, destSize, option_->curve);
199 auto sizeListener = [weakFrame = WeakPtr<FrameNode>(src), setAspect = initAspectRatio.has_value()](
200 const SizeF& size) {
201 auto src = weakFrame.Upgrade();
202 CHECK_NULL_VOID(src);
203 src->GetLayoutProperty()->UpdateUserDefinedIdealSize(
204 CalcSize(CalcLength(size.Width()), CalcLength(size.Height())));
205 if (setAspect) {
206 src->GetLayoutProperty()->UpdateAspectRatio(size.Width() / size.Height());
207 }
208 // When call listener callback, the passenger has mounted to overlay, only need to measure passenger
209 // for better performance. Notice that the parent has been changed, layoutConstraint is not correct if we
210 // don't measure from parent, otherwise the result may be wrong if passenger has aspectRatio.
211 src->GetGeometryNode()->ResetParentLayoutConstraint();
212 src->GetLayoutProperty()->CleanDirty();
213 src->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
214 };
215 sizeAnimation->AddListener(sizeListener);
216 controller_->AddInterpolator(sizeAnimation);
217 finishCallbacks_.emplace_back([weakFrame = WeakPtr<FrameNode>(src), initSize, initAspectRatio]() {
218 auto src = weakFrame.Upgrade();
219 CHECK_NULL_VOID(src);
220 if (src->GetLayoutProperty()->GetCalcLayoutConstraint()) {
221 src->GetLayoutProperty()->GetCalcLayoutConstraint()->selfIdealSize = initSize;
222 }
223 if (initAspectRatio.has_value()) {
224 src->GetLayoutProperty()->UpdateAspectRatio(initAspectRatio.value());
225 }
226 src->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
227 });
228 return true;
229 }
230
CreateOpacityAnimation(const RefPtr<FrameNode> & src,const RefPtr<FrameNode> & dest)231 bool SharedTransitionExchange::CreateOpacityAnimation(const RefPtr<FrameNode>& src, const RefPtr<FrameNode>& dest)
232 {
233 auto startOpacity = static_cast<float>(src->GetRenderContext()->GetOpacityValue(1.0));
234 auto endOpacity = static_cast<float>(dest->GetRenderContext()->GetOpacityValue(1.0));
235 return SharedTransitionEffect::CreateOpacityAnimation(startOpacity, endOpacity, startOpacity, src_);
236 }
237
SetVisibleToDest(VisibleType type)238 bool SharedTransitionExchange::SetVisibleToDest(VisibleType type)
239 {
240 auto dest = dest_.Upgrade();
241 CHECK_NULL_RETURN(dest, false);
242 dest->GetLayoutProperty()->UpdateVisibility(type);
243 return true;
244 }
245
DestRequestDefaultFocus()246 void SharedTransitionExchange::DestRequestDefaultFocus()
247 {
248 if (destVisible_ != VisibleType::VISIBLE) {
249 return;
250 }
251 auto dest = dest_.Upgrade();
252 CHECK_NULL_VOID(dest);
253 auto page = dest->GetPageNode();
254 CHECK_NULL_VOID(page);
255 auto pageFocusHub = page->GetFocusHub();
256 CHECK_NULL_VOID(pageFocusHub);
257 pageFocusHub->SetParentFocusable(true);
258 pageFocusHub->RequestFocusWithDefaultFocusFirstly();
259 }
260
SharedTransitionStatic(const ShareId & shareId,const std::shared_ptr<SharedTransitionOption> & sharedOption)261 SharedTransitionStatic::SharedTransitionStatic(
262 const ShareId& shareId, const std::shared_ptr<SharedTransitionOption>& sharedOption)
263 : SharedTransitionEffect(shareId, sharedOption)
264 {}
265
Allow() const266 bool SharedTransitionStatic::Allow() const
267 {
268 auto shared = GetPassengerNode().Upgrade();
269 CHECK_NULL_RETURN(shared, false);
270 return !(GetShareId().empty());
271 }
272
CreateAnimation()273 bool SharedTransitionStatic::CreateAnimation()
274 {
275 auto node = GetPassengerNode().Upgrade();
276 if (!node) {
277 return false;
278 }
279 // static transition only need opacity animation
280 auto initialOpacity = static_cast<float>(node->GetRenderContext()->GetOpacityValue(1.0));
281 if (dest_ == node) {
282 // anchor appearing, passenger is dest_, opacity 0 to initial opacity
283 return SharedTransitionEffect::CreateOpacityAnimation(0.0f, initialOpacity, initialOpacity, dest_);
284 }
285 // anchor disappearing, passenger is src_, opacity initial opacity to 0
286 return SharedTransitionEffect::CreateOpacityAnimation(initialOpacity, 0.0f, initialOpacity, src_);
287 }
288
GetPassengerNode() const289 const WeakPtr<FrameNode>& SharedTransitionStatic::GetPassengerNode() const
290 {
291 return src_.Invalid() ? dest_ : src_;
292 }
293
294 } // namespace OHOS::Ace::NG
295