提交 cb7cedaf 编写于 作者: O openharmony_ci 提交者: Gitee

!57 Add button animator

Merge pull request !57 from benb365/master
......@@ -28,7 +28,7 @@ void Animator::Start()
{
SetState(START);
runTime_ = 0;
lastRunTime_ = 0;
lastRunTime_ = HALTick::GetInstance().GetTime();
AnimatorManager::GetInstance()->Add(this);
}
......@@ -56,14 +56,15 @@ void Animator::Resume()
void Animator::Run()
{
if (lastRunTime_ == 0) {
lastRunTime_ = HALTick::GetInstance().GetTime();
}
uint32_t elapse = HALTick::GetInstance().GetElapseTime(lastRunTime_);
lastRunTime_ = HALTick::GetInstance().GetTime();
runTime_ = (UINT32_MAX - elapse > runTime_) ? (runTime_ + elapse) : period_;
uint32_t elepse = HALTick::GetInstance().GetElapseTime(lastRunTime_);
if (!repeat_ && (runTime_ >= period_)) {
Stop();
return;
}
runTime_ = (UINT32_MAX - elepse > runTime_) ? (runTime_ + elepse) : time_;
lastRunTime_ = HALTick::GetInstance().GetTime();
if (callback_ != nullptr) {
callback_->Callback(view_);
}
......
......@@ -66,11 +66,7 @@ void AnimatorManager::AnimatorTask()
animator = pos->data_;
pos = pos->next_;
if (animator->GetState() == Animator::START) {
if (animator->IsRepeat() || (animator->GetRunTime() <= animator->GetTime())) {
animator->Run();
} else {
animator->Stop();
}
animator->Run();
}
}
}
......
......@@ -15,6 +15,8 @@
#include "animator/interpolation.h"
#include "gfx_utils/graphic_math.h"
namespace OHOS {
/* B(t) = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3 */
int16_t Interpolation::GetBezierInterpolation(int16_t t, int16_t u0, int16_t u1, int16_t u2, int16_t u3)
......@@ -32,4 +34,41 @@ int16_t Interpolation::GetBezierInterpolation(int16_t t, int16_t u0, int16_t u1,
ret = ret >> CUBIC_BEZIER_CALCULATE_OFFSET;
return static_cast<int16_t>(ret);
}
/* B(t) = 3(P1-P0)(1-t)^2 + 6(P2-P1)t(1-t) + 3(P3-P2)t^2 */
int16_t Interpolation::GetBezierDerivative(int16_t t, int16_t u0, int16_t u1, int16_t u2, int16_t u3)
{
int64_t invT = INTERPOLATION_RANGE - t;
int64_t d0 = u1 - u0;
int64_t d1 = u2 - u1;
int64_t d2 = u3 - u2;
constexpr int32_t BESSEL_SQUARE_COEFFICIENT = (BESSEL_COEFFICIENT - 1) * BESSEL_COEFFICIENT;
constexpr int32_t BESSEL_SQUARE_OFFSET = 20;
int64_t ret = BESSEL_COEFFICIENT * d0 * invT * invT;
ret += BESSEL_SQUARE_COEFFICIENT * d1 * invT * t;
ret += BESSEL_COEFFICIENT * d2 * t * t;
ret = ret >> BESSEL_SQUARE_OFFSET;
return static_cast<int16_t>(ret);
}
int16_t Interpolation::GetBezierY(int16_t x, int16_t x1, int16_t y1, int16_t x2, int16_t y2)
{
/* P={x,y}; P0={0,0}; P1={x1,y1}; P2={x2,y2}; P3={1,1}
* P = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3
*/
int16_t t = x;
int16_t xt = GetBezierInterpolation(t, 0, x1, x2, INTERPOLATION_RANGE);
/* Attention: precision must be carefully selected
* too small may lead to misconvergence and a decrease of performance
* too large may cause the curve rugged even make some points outlier */
constexpr int8_t PRECISION = 50; // 50 make serveral outliers near inflection point
/* Newton Method to solve t from x */
while (MATH_ABS(xt - x) > PRECISION) {
t = t + (x - xt) * INTERPOLATION_RANGE / GetBezierDerivative(t, 0, x1, x2, INTERPOLATION_RANGE);
xt = GetBezierInterpolation(t, 0, x1, x2, INTERPOLATION_RANGE);
}
return GetBezierInterpolation(t, 0, y1, y2, INTERPOLATION_RANGE);
}
} // namespace OHOS
......@@ -48,14 +48,14 @@ Window* RootView::GetBoundWindow() const
}
#endif
inline bool RootView::IntersectScreenRect(Rect& rect)
Rect RootView::GetScreenRect()
{
#if ENABLE_WINDOW
Rect screenRect = GetRect();
#else
Rect screenRect(0, 0, Screen::GetInstance().GetWidth() - 1, Screen::GetInstance().GetHeight() - 1);
#endif
return rect.Intersect(rect, screenRect);
return screenRect;
}
#if LOCAL_RENDER
......@@ -338,8 +338,7 @@ void RootView::OptimizeInvalidMap()
}
curview = g_viewStack[--stackCount];
Rect rect(curview->GetRect());
if (!curview->IsVisible() || !IntersectScreenRect(rect)) {
if (!curview->IsVisible() || !rect.Intersect(curview->GetRect(), GetScreenRect())) {
curview = nullptr;
continue;
}
......@@ -386,8 +385,8 @@ void RootView::DrawInvalidMap(const Rect& buffRect)
void RootView::AddInvalidateRect(Rect& rect, UIView* view)
{
Rect commonRect(rect);
if (IntersectScreenRect(commonRect)) {
Rect commonRect;
if (commonRect.Intersect(rect, GetScreenRect())) {
#if LOCAL_RENDER
Vector<Rect>& invalidRects = invalidateMap_[view];
if (invalidRects.IsEmpty()) {
......@@ -505,34 +504,28 @@ void RootView::DrawTop(UIView* view, const Rect& rect)
Rect mask = rect;
Rect origRect;
Rect relativeRect;
bool enableAnimator = false;
while (par != nullptr) {
if (curView != nullptr) {
if (curView->IsVisible()) {
curViewRect = curView->GetMaskedRect();
if (curViewRect.Intersect(curViewRect, mask) || enableAnimator_) {
if (curViewRect.Intersect(curView->GetMaskedRect(), mask) || enableAnimator) {
if ((curView->GetViewType() != UI_IMAGE_VIEW) && (curView->GetViewType() != UI_TEXTURE_MAPPER) &&
!curView->IsTransInvalid() && !enableAnimator_) {
!curView->IsTransInvalid() && !enableAnimator) {
origRect = curView->GetOrigRect();
relativeRect = curView->GetRelativeRect();
curView->GetTransformMap().SetInvalid(true);
curView->SetPosition(relativeRect.GetX() - origRect.GetX(),
relativeRect.GetY() - origRect.GetY());
curViewRect = curView->GetMaskedRect();
ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(true);
ScreenDeviceProxy::GetInstance()->SetAnimatorRect(origRect);
ScreenDeviceProxy::GetInstance()->SetAnimatorTransMap(curView->GetTransformMap());
enableAnimator_ = true;
}
if (enableAnimator_) {
Rect invalidatedArea;
invalidatedArea.SetWidth(ScreenDeviceProxy::GetInstance()->GetScreenWidth());
invalidatedArea.SetHeight(ScreenDeviceProxy::GetInstance()->GetScreenHeight());
curView->OnDraw(invalidatedArea);
} else {
curView->OnDraw(curViewRect);
enableAnimator = true;
}
curView->OnDraw(curViewRect);
if ((curView->IsViewGroup()) && (stackCount < COMPONENT_NESTING_DEPTH)) {
if (enableAnimator_ && (transViewGroup == nullptr)) {
if (enableAnimator && (transViewGroup == nullptr)) {
transViewGroup = curView;
}
par = curView;
......@@ -545,11 +538,11 @@ void RootView::DrawTop(UIView* view, const Rect& rect)
continue;
}
curView->OnPostDraw(curViewRect);
if (enableAnimator_ && (transViewGroup == nullptr)) {
if (enableAnimator && (transViewGroup == nullptr)) {
ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(false);
ScreenDeviceProxy::GetInstance()->DrawAnimatorBuffer(mask);
curView->GetTransformMap().SetInvalid(false);
enableAnimator_ = false;
enableAnimator = false;
curView->SetPosition(relativeRect.GetX(), relativeRect.GetY());
}
}
......@@ -560,14 +553,14 @@ void RootView::DrawTop(UIView* view, const Rect& rect)
if (--stackCount >= 0) {
curViewRect = par->GetMaskedRect();
mask = g_maskStack[stackCount];
if (curViewRect.Intersect(curViewRect, mask)) {
if (enableAnimator || curViewRect.Intersect(curViewRect, mask)) {
par->OnPostDraw(curViewRect);
}
if (enableAnimator_ && transViewGroup == g_viewStack[stackCount]) {
if (enableAnimator && transViewGroup == g_viewStack[stackCount]) {
ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(false);
ScreenDeviceProxy::GetInstance()->DrawAnimatorBuffer(mask);
transViewGroup->GetTransformMap().SetInvalid(false);
enableAnimator_ = false;
enableAnimator = false;
transViewGroup->SetPosition(relativeRect.GetX(), relativeRect.GetY());
transViewGroup = nullptr;
}
......
......@@ -14,6 +14,8 @@
*/
#include "components/ui_button.h"
#include "animator/interpolation.h"
#include "common/image.h"
#include "draw/draw_image.h"
#include "draw/draw_rect.h"
......@@ -24,7 +26,11 @@
namespace OHOS {
UIButton::UIButton()
: defaultImgSrc_(nullptr),
:
#if DEFAULT_ANIMATION
animator_(*this),
#endif
defaultImgSrc_(nullptr),
triggeredImgSrc_(nullptr),
currentImgSrc_(ButtonImageSrc::BTN_IMAGE_DEFAULT),
imgX_(0),
......@@ -168,6 +174,9 @@ bool UIButton::OnPressEvent(const PressEvent& event)
SetState(PRESSED);
Resize(contentWidth_, contentHeight_);
Invalidate();
#if DEFAULT_ANIMATION
animator_.Start();
#endif
return UIView::OnPressEvent(event);
}
......@@ -177,6 +186,9 @@ bool UIButton::OnReleaseEvent(const ReleaseEvent& event)
SetState(RELEASED);
Resize(contentWidth_, contentHeight_);
Invalidate();
#if DEFAULT_ANIMATION
animator_.Start();
#endif
return UIView::OnReleaseEvent(event);
}
......@@ -186,6 +198,9 @@ bool UIButton::OnCancelEvent(const CancelEvent& event)
SetState(RELEASED);
Resize(contentWidth_, contentHeight_);
Invalidate();
#if DEFAULT_ANIMATION
animator_.Start();
#endif
return UIView::OnCancelEvent(event);
}
......@@ -262,6 +277,7 @@ bool UIButton::OnPreDraw(Rect& invalidatedArea) const
if (r == COORD_MAX) {
return true;
}
if (r != 0) {
r = ((r & 0x1) == 0) ? (r >> 1) : ((r + 1) >> 1);
rect.SetLeft(rect.GetX() + r);
......@@ -275,4 +291,77 @@ bool UIButton::OnPreDraw(Rect& invalidatedArea) const
invalidatedArea.Intersect(invalidatedArea, rect);
return false;
}
} // namespace OHOS
\ No newline at end of file
#if DEFAULT_ANIMATION
void UIButton::OnPostDraw(const Rect& invalidatedArea)
{
if (state_ == ButtonState::PRESSED) {
animator_.DrawMask(invalidatedArea);
}
}
namespace {
constexpr int16_t INTERVAL_MAX = Interpolation::INTERPOLATION_RANGE;
constexpr float SHRINK_SCALE = 0.8f;
constexpr uint32_t SHRINK_DURATION = 150;
constexpr uint32_t RECOVER_DURATION = 200;
constexpr int64_t MASK_OPA = 25;
constexpr int16_t BEZIER_CONTROL = INTERVAL_MAX / 5;
} // namespace
void UIButton::ButtonAnimator::Start()
{
if (button_.state_ == UIButton::ButtonState::PRESSED) {
animator_.SetTime(SHRINK_DURATION);
} else {
animator_.SetTime(RECOVER_DURATION);
}
animator_.Start();
if (progress_ != 0) {
/* reverse the animator direction */
progress_ = INTERVAL_MAX - progress_;
animator_.SetRunTime(animator_.GetTime() * progress_ / INTERVAL_MAX);
}
}
void UIButton::ButtonAnimator::DrawMask(const Rect& invalidatedArea)
{
Style maskStyle;
maskStyle.SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
maskStyle.SetStyle(STYLE_BACKGROUND_OPA, MASK_OPA);
maskStyle.SetStyle(STYLE_BORDER_RADIUS, button_.GetStyle(STYLE_BORDER_RADIUS));
OpacityType opa = button_.GetMixOpaScale();
DrawRect::Draw(button_.GetRect(), invalidatedArea, maskStyle, opa);
}
static inline void ScaleButton(UIButton& button, float scale)
{
Vector2<float> scaleValue_ = {scale, scale};
Vector2<float> centrePoint(button.GetWidth() / 2.0f, button.GetHeight() / 2.0f);
button.Scale(scaleValue_, centrePoint);
}
void UIButton::ButtonAnimator::Callback(UIView* view)
{
progress_ = static_cast<int16_t>(INTERVAL_MAX * animator_.GetRunTime() / animator_.GetTime());
int16_t offset = Interpolation::GetBezierY(progress_, BEZIER_CONTROL, 0, BEZIER_CONTROL, INTERVAL_MAX);
float scale = (1 - SHRINK_SCALE) * offset / INTERVAL_MAX;
scale = (button_.state_ == UIButton::ButtonState::PRESSED) ? (1 - scale) : (scale + SHRINK_SCALE);
ScaleButton(button_, scale);
}
void UIButton::ButtonAnimator::OnStop(UIView& view)
{
progress_ = 0;
if (button_.state_ == UIButton::ButtonState::PRESSED) {
ScaleButton(button_, SHRINK_SCALE);
} else {
button_.ResetTransParameter();
}
}
#endif
} // namespace OHOS
......@@ -186,10 +186,15 @@ void UIView::Scale(const Vector2<float>& scale, const Vector2<float>& pivot)
return;
}
}
bool firstTrans = transMap_->IsInvalid();
Rect joinRect = transMap_->GetBoxRect();
transMap_->SetTransMapRect(GetOrigRect());
transMap_->Scale(scale, pivot);
joinRect.Join(joinRect, transMap_->GetBoxRect());
if (firstTrans) {
joinRect = transMap_->GetBoxRect();
} else {
joinRect.Join(joinRect, transMap_->GetBoxRect());
}
joinRect.Join(joinRect, GetOrigRect());
InvalidateRect(joinRect);
}
......@@ -227,6 +232,7 @@ void UIView::ResetTransParameter()
if (transMap_ != nullptr) {
delete transMap_;
transMap_ = nullptr;
Invalidate();
}
}
......@@ -794,7 +800,7 @@ void UIView::LayoutBottomToSibling(const char* id, int16_t offset)
}
}
uint8_t UIView::GetMixOpaScale()
uint8_t UIView::GetMixOpaScale() const
{
uint8_t opaMix = opaScale_;
UIView* parent = parent_;
......
......@@ -112,7 +112,7 @@ public:
* @version 1.0
*/
Animator()
: callback_(nullptr), view_(nullptr), state_(STOP), time_(0), repeat_(false), runTime_(0), lastRunTime_(0)
: callback_(nullptr), view_(nullptr), state_(STOP), period_(0), repeat_(false), runTime_(0), lastRunTime_(0)
{
}
......@@ -130,7 +130,7 @@ public:
* @version 1.0
*/
Animator(AnimatorCallback* callback, UIView* view, uint32_t time, bool repeat)
: callback_(callback), view_(view), state_(STOP), time_(time), repeat_(repeat), runTime_(0), lastRunTime_(0)
: callback_(callback), view_(view), state_(STOP), period_(time), repeat_(repeat), runTime_(0), lastRunTime_(0)
{
}
......@@ -215,7 +215,7 @@ public:
*/
uint32_t GetTime() const
{
return time_;
return period_;
}
/**
......@@ -226,9 +226,9 @@ public:
* @since 1.0
* @version 1.0
*/
void SetTime(uint32_t time)
void SetTime(uint32_t period)
{
time_ = time;
period_ = period;
}
/**
......@@ -275,7 +275,7 @@ protected:
AnimatorCallback* callback_;
UIView* view_;
uint8_t state_;
uint32_t time_;
uint32_t period_;
bool repeat_;
uint32_t runTime_;
uint32_t lastRunTime_;
......
......@@ -63,11 +63,14 @@ public:
* @version 1.0
*/
static int16_t GetBezierInterpolation(int16_t t, int16_t u0, int16_t u1, int16_t u2, int16_t u3);
static int16_t GetBezierY(int16_t x, int16_t x1, int16_t y1, int16_t x2, int16_t y2);
constexpr static int16_t INTERPOLATION_RANGE = 1024;
private:
constexpr static uint16_t BESSEL_COEFFICIENT = 3;
constexpr static uint16_t INTERPOLATION_RANGE = 1024;
constexpr static uint16_t CUBIC_BEZIER_CALCULATE_OFFSET = 30;
static int16_t GetBezierDerivative(int16_t t, int16_t u0, int16_t u1, int16_t u2, int16_t u3);
};
} // namespace OHOS
#endif // GRAPHIC_LITE_INTERPOLATION_H
......@@ -275,7 +275,7 @@ private:
~RootView() {}
inline bool IntersectScreenRect(Rect& rect);
inline Rect GetScreenRect();
void AddInvalidateRectWithLock(Rect& rect, UIView *view);
void AddInvalidateRect(Rect& rect, UIView* view);
void Measure();
......@@ -295,7 +295,6 @@ private:
#endif
OnKeyActListener* onKeyActListener_ {nullptr};
OnVirtualDeviceEventListener* onVirtualEventListener_ {nullptr};
bool enableAnimator_ {false};
#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
pthread_mutex_t lock_;
#endif
......
......@@ -35,6 +35,7 @@
#ifndef GRAPHIC_LITE_UI_BUTTON_H
#define GRAPHIC_LITE_UI_BUTTON_H
#include "animator/animator.h"
#include "common/image.h"
#include "components/ui_view.h"
......@@ -101,6 +102,15 @@ public:
*/
bool OnPreDraw(Rect& invalidatedArea) const override;
#if DEFAULT_ANIMATION
/**
* @fn virtual bool UIButton::OnPostDraw(Rect& invalidatedArea) override
*
* @brief Do something after draw.
* @param [in] invalidate area.
*/
void OnPostDraw(const Rect& invalidatedArea) override;
#endif
/**
* @fn virtual void UIButton::OnDraw(const Rect& invalidatedArea) override;
*
......@@ -253,7 +263,7 @@ public:
{
Style* style = buttonStyles_[state_];
return GetRelativeRect().GetWidth() - (style->paddingLeft_ + style->paddingRight_) -
(style->borderWidth_ * 2); /* 2: left and right border */
(style->borderWidth_ * 2); /* 2: left and right border */
}
/**
......@@ -267,7 +277,7 @@ public:
{
Style* style = buttonStyles_[state_];
return GetRelativeRect().GetHeight() - (style->paddingTop_ + style->paddingBottom_) -
(style->borderWidth_ * 2); /* 2: top and bottom border */
(style->borderWidth_ * 2); /* 2: top and bottom border */
}
/**
......@@ -282,7 +292,7 @@ public:
contentWidth_ = width;
Style* style = buttonStyles_[state_];
UIView::SetWidth(width + (style->paddingLeft_ + style->paddingRight_) +
(style->borderWidth_ * 2)); /* 2: left and right border */
(style->borderWidth_ * 2)); /* 2: left and right border */
}
/**
......@@ -297,7 +307,7 @@ public:
contentHeight_ = height;
Style* style = buttonStyles_[state_];
UIView::SetHeight(height + (style->paddingTop_ + style->paddingBottom_) +
(style->borderWidth_ * 2)); /* 2: top and bottom border */
(style->borderWidth_ * 2)); /* 2: top and bottom border */
}
/**
......@@ -410,6 +420,30 @@ private:
void SetupThemeStyles();
void DrawImg(const Rect& invalidatedArea, OpacityType opaScale);
#if DEFAULT_ANIMATION
friend class ButtonAnimator;
class ButtonAnimator final : public AnimatorCallback {
public:
ButtonAnimator() = delete;
ButtonAnimator(const ButtonAnimator&) = delete;
ButtonAnimator& operator=(const ButtonAnimator&) = delete;
ButtonAnimator(ButtonAnimator&&) = delete;
ButtonAnimator& operator=(ButtonAnimator&&) = delete;
ButtonAnimator(UIButton& button) : animator_(this, nullptr, 0, false), button_(button) {}
~ButtonAnimator() {}
void Start();
void DrawMask(const Rect& invalidatedArea);
void Callback(UIView* view) override;
void OnStop(UIView& view) override;
private:
Animator animator_;
UIButton& button_;
int16_t progress_ = 0;
} animator_;
#endif
};
} // namespace OHOS
#endif // GRAPHIC_LITE_UI_BUTTON_H
......@@ -1469,7 +1469,7 @@ protected:
#endif
ViewExtraMsg* viewExtraMsg_;
uint8_t GetMixOpaScale();
uint8_t GetMixOpaScale() const;
bool IsInvalid(float percent);
private:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册