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/tab_bar/render_tab_bar_item.h"
17
18 namespace OHOS::Ace {
19 namespace {
20
21 constexpr Dimension TAB_BAR_ITEM_SMALL_PADDING(8, DimensionUnit::VP);
22 constexpr Dimension TAB_BAR_ITEM_BIG_PADDING(12, DimensionUnit::VP);
23 constexpr int32_t HOVER_ANIMATION_DURATION = 250;
24 constexpr double HOVER_OPACITY_RATIO = 0.05;
25 constexpr double CLICK_OPACITY_RATIO = 0.1;
26
27 } // namespace
28
RenderTabBarItem()29 RenderTabBarItem::RenderTabBarItem() : RenderBox()
30 {
31 touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
32 touchRecognizer_->SetOnTouchDown([wp = AceType::WeakClaim(this)](const TouchEventInfo&) {
33 auto sp = wp.Upgrade();
34 if (sp) {
35 sp->HandleTouchDown();
36 }
37 });
38 touchRecognizer_->SetOnTouchUp([wp = AceType::WeakClaim(this)](const TouchEventInfo&) {
39 auto sp = wp.Upgrade();
40 if (sp) {
41 sp->HandleTouchUp();
42 }
43 });
44 touchRecognizer_->SetOnTouchCancel([wp = AceType::WeakClaim(this)](const TouchEventInfo&) {
45 auto sp = wp.Upgrade();
46 if (sp) {
47 sp->HandleTouchUp();
48 }
49 });
50 }
51
HandleTouchDown()52 void RenderTabBarItem::HandleTouchDown()
53 {
54 SetTouching(true);
55 PlayPressAnimation(CLICK_OPACITY_RATIO);
56 }
57
HandleTouchUp()58 void RenderTabBarItem::HandleTouchUp()
59 {
60 if (IsTouching()) {
61 SetTouching(false);
62 auto ratio = onHover_ ? HOVER_OPACITY_RATIO : 0.0;
63 PlayPressAnimation(ratio);
64 }
65 }
66
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)67 void RenderTabBarItem::OnTouchTestHit(
68 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
69 {
70 if (!touchRecognizer_) {
71 return;
72 }
73 touchRecognizer_->SetCoordinateOffset(coordinateOffset);
74 result.emplace_back(touchRecognizer_);
75 }
76
OnMouseHoverEnterTest()77 void RenderTabBarItem::OnMouseHoverEnterTest()
78 {
79 ResetController(controllerExit_);
80 ResetController(controllerPress_);
81 if (!controllerEnter_) {
82 controllerEnter_ = CREATE_ANIMATOR(context_);
83 }
84 doubleAnimationEnter_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
85 CreateDoubleAnimation(doubleAnimationEnter_, hoverOpacity_, HOVER_OPACITY_RATIO, true);
86 doubleAnimationEnter_->SetCurve(Curves::FRICTION);
87 StartHoverAnimation(controllerEnter_, doubleAnimationEnter_);
88 }
89
OnMouseHoverExitTest()90 void RenderTabBarItem::OnMouseHoverExitTest()
91 {
92 ResetController(controllerEnter_);
93 ResetController(controllerPress_);
94 if (!controllerExit_) {
95 controllerExit_ = CREATE_ANIMATOR(context_);
96 }
97 doubleAnimationExit_ = AceType::MakeRefPtr<KeyframeAnimation<double>>();
98 CreateDoubleAnimation(doubleAnimationExit_, hoverOpacity_, 0.0, false);
99 if (hoverOpacity_ == HOVER_OPACITY_RATIO) {
100 doubleAnimationExit_->SetCurve(Curves::FRICTION);
101 } else {
102 doubleAnimationExit_->SetCurve(Curves::FAST_OUT_SLOW_IN);
103 }
104 StartHoverAnimation(controllerExit_, doubleAnimationExit_);
105 }
106
PlayPressAnimation(double endOpacityRatio)107 void RenderTabBarItem::PlayPressAnimation(double endOpacityRatio)
108 {
109 ResetController(controllerEnter_);
110 ResetController(controllerExit_);
111 if (!controllerPress_) {
112 controllerPress_ = CREATE_ANIMATOR(context_);
113 }
114 auto doubleAnimationPress = AceType::MakeRefPtr<KeyframeAnimation<double>>();
115 CreateDoubleAnimation(doubleAnimationPress, hoverOpacity_, endOpacityRatio, onHover_);
116 doubleAnimationPress->SetCurve(Curves::SHARP);
117 controllerPress_->ClearInterpolators();
118 controllerPress_->AddInterpolator(doubleAnimationPress);
119 controllerPress_->SetDuration(HOVER_ANIMATION_DURATION);
120 controllerPress_->SetFillMode(FillMode::FORWARDS);
121 controllerPress_->Play();
122 }
123
StartHoverAnimation(RefPtr<Animator> controller,RefPtr<KeyframeAnimation<double>> & doubleAnimation)124 void RenderTabBarItem::StartHoverAnimation(RefPtr<Animator> controller,
125 RefPtr<KeyframeAnimation<double>>& doubleAnimation)
126 {
127 if (!controller || !doubleAnimation) {
128 return;
129 }
130 controller->ClearInterpolators();
131 controller->AddInterpolator(doubleAnimation);
132 controller->SetDuration(HOVER_ANIMATION_DURATION);
133 controller->SetFillMode(FillMode::FORWARDS);
134 controller->Play();
135 }
136
CreateDoubleAnimation(RefPtr<KeyframeAnimation<double>> & doubleAnimation,double beginValue,double endValue,bool hover)137 void RenderTabBarItem::CreateDoubleAnimation(
138 RefPtr<KeyframeAnimation<double>>& doubleAnimation, double beginValue, double endValue, bool hover)
139 {
140 if (!doubleAnimation) {
141 return;
142 }
143 auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, beginValue);
144 auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, endValue);
145 doubleAnimation->AddKeyframe(keyframeBegin);
146 doubleAnimation->AddKeyframe(keyframeEnd);
147 doubleAnimation->AddListener([weakBarItem = AceType::WeakClaim(this), hover](double value) {
148 auto barItem = weakBarItem.Upgrade();
149 if (barItem) {
150 barItem->onHover_ = hover;
151 barItem->hoverOpacity_ = value;
152 barItem->MarkNeedRender();
153 }
154 });
155 }
156
ResetController(RefPtr<Animator> & controller)157 void RenderTabBarItem::ResetController(RefPtr<Animator>& controller)
158 {
159 if (controller) {
160 if (!controller->IsStopped()) {
161 controller->Stop();
162 }
163 controller->ClearInterpolators();
164 }
165 }
166
PerformLayout()167 void RenderTabBarItem::PerformLayout()
168 {
169 auto currentSize = GridSystemManager::GetInstance().GetCurrentSize();
170 if (currentSize == GridSizeType::SM) {
171 paddingOrigin_.SetLeft(TAB_BAR_ITEM_SMALL_PADDING);
172 paddingOrigin_.SetRight(TAB_BAR_ITEM_SMALL_PADDING);
173 } else if (currentSize >= GridSizeType::MD) {
174 paddingOrigin_.SetLeft(TAB_BAR_ITEM_BIG_PADDING);
175 paddingOrigin_.SetRight(TAB_BAR_ITEM_BIG_PADDING);
176 }
177 RenderBox::PerformLayout();
178 }
179
180 } // namespace OHOS::Ace
181