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