diff --git a/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js b/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js index ebaa29d15f2..6922d497e93 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js +++ b/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js @@ -609,4 +609,12 @@ var ItemState ItemState[ItemState["Disabled"] = 1] = "Disabled"; ItemState[ItemState["Waiting"] = 2] = "Waiting"; ItemState[ItemState["Skip"] = 3] = "Skip"; -})(ItemState || (ItemState = {})); \ No newline at end of file +})(ItemState || (ItemState = {})); + +var HoverEffect; +(function (HoverEffect) { + HoverEffect[HoverEffect["Auto"] = 4] = "Auto"; + HoverEffect[HoverEffect["Scale"] = 2] = "Scale"; + HoverEffect[HoverEffect["Board"] = 3] = "Board"; + HoverEffect[HoverEffect["None"] = 0] = "None"; +})(HoverEffect || (HoverEffect = {})); \ No newline at end of file diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp index f3b4c0316c3..f0240a85fdc 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp @@ -3128,6 +3128,7 @@ void JSViewAbstract::JSBind() JSClass::StaticMethod("hueRotate", &JSViewAbstract::JsHueRotate); JSClass::StaticMethod("clip", &JSViewAbstract::JsClip); JSClass::StaticMethod("mask", &JSViewAbstract::JsMask); + JSClass::StaticMethod("hoverEffect", &JSViewAbstract::JsHoverEffect); #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM) JSClass::StaticMethod("debugLine", &JSViewAbstract::JsDebugLine); #endif @@ -3719,4 +3720,14 @@ RefPtr JSViewAbstract::GetThemeConstants() return themeManager->GetThemeConstants(); } +void JSViewAbstract::JsHoverEffect(const JSCallbackInfo& info) +{ + if (!info[0]->IsNumber()) { + LOGE("info[0] is not a number"); + return; + } + auto boxComponent = ViewStackProcessor::GetInstance()->GetBoxComponent(); + boxComponent->SetMouseAnimationType(static_cast(info[0]->ToNumber())); +} + } // namespace OHOS::Ace::Framework diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h index 70e1e483bcb..c15ab3a8ad4 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h @@ -101,6 +101,7 @@ public: static void JsGridSpan(const JSCallbackInfo& Info); static void JsGridOffset(const JSCallbackInfo& info); static void JsUseSizeType(const JSCallbackInfo& Info); + static void JsHoverEffect(const JSCallbackInfo& info); // for number and string with no unit, use default dimension unit. static bool ParseJsDimension(const JSRef& jsValue, Dimension& result, DimensionUnit defaultUnit); diff --git a/frameworks/core/components/box/box_component.h b/frameworks/core/components/box/box_component.h index f49edd7e338..9af4b6ca017 100644 --- a/frameworks/core/components/box/box_component.h +++ b/frameworks/core/components/box/box_component.h @@ -24,11 +24,6 @@ namespace OHOS::Ace { -enum class HoverAnimationType : int32_t { - NONE, - OPACITY, - SCALE, -}; using OnDragFunc = std::function& info)>; diff --git a/frameworks/core/components/box/flutter_render_box.cpp b/frameworks/core/components/box/flutter_render_box.cpp index 76416e551f4..59ffa4dc81f 100644 --- a/frameworks/core/components/box/flutter_render_box.cpp +++ b/frameworks/core/components/box/flutter_render_box.cpp @@ -35,6 +35,7 @@ #include "core/components/common/properties/color.h" #include "core/components/flex/render_flex.h" #include "core/components/image/image_component.h" +#include "core/components/transform/flutter_render_transform.h" #include "core/pipeline/base/flutter_render_context.h" #include "core/pipeline/base/scoped_canvas_state.h" #include "core/pipeline/layers/flutter_scene_builder.h" @@ -243,6 +244,19 @@ void FlutterRenderBox::PerformLayout() CalculateRepeatParam(); } +void FlutterRenderBox::UpdateLayer() +{ + float translateX = GetLayoutSize().Width() / 2.0 * (1.0 - scale_); + float translateY = GetLayoutSize().Height() / 2.0 * (1.0 - scale_); + Matrix4 translateMatrix = Matrix4::CreateTranslate(translateX, translateY, 0.0); + Matrix4 scaleMatrix = Matrix4::CreateScale(scale_, scale_, 1.0); + Matrix4 transformMatrix = translateMatrix * scaleMatrix; + transformMatrix = FlutterRenderTransform::GetTransformByOffset(transformMatrix, GetGlobalOffset()); + if (transformLayer_) { + transformLayer_->Update(transformMatrix); + } +} + void FlutterRenderBox::Paint(RenderContext& context, const Offset& offset) { const auto renderContext = static_cast(&context); @@ -601,8 +615,14 @@ RenderLayer FlutterRenderBox::GetRenderLayer() } renderLayer_->SetStaticOffset(alignOffset_.GetX(), alignOffset_.GetY()); } - - return AceType::RawPtr(renderLayer_); + if (isZoom) { + if (!transformLayer_) { + transformLayer_ = AceType::MakeRefPtr(Matrix4::CreateIdentity(), 0.0, 0.0); + } + return AceType::RawPtr(transformLayer_); + } else { + return AceType::RawPtr(renderLayer_); + } } flutter::RRect FlutterRenderBox::GetBoxRRect( diff --git a/frameworks/core/components/box/flutter_render_box.h b/frameworks/core/components/box/flutter_render_box.h index 8c9a008ea82..ef87d85d61d 100644 --- a/frameworks/core/components/box/flutter_render_box.h +++ b/frameworks/core/components/box/flutter_render_box.h @@ -28,6 +28,7 @@ #include "core/pipeline/layers/clip_layer.h" #include "core/pipeline/layers/container_layer.h" #include "core/pipeline/layers/offset_layer.h" +#include "core/pipeline/layers/transform_layer.h" namespace OHOS::Ace { @@ -47,6 +48,7 @@ public: return true; } void DrawOnPixelMap() override; + void UpdateLayer(); protected: virtual bool MaybeRelease() override; @@ -166,6 +168,7 @@ private: RefPtr renderTaskHolder_; UploadSuccessCallback uploadSuccessCallback_; + RefPtr transformLayer_; }; } // namespace OHOS::Ace diff --git a/frameworks/core/components/box/render_box.cpp b/frameworks/core/components/box/render_box.cpp index 8ff0eda5059..d3ec94c16f2 100644 --- a/frameworks/core/components/box/render_box.cpp +++ b/frameworks/core/components/box/render_box.cpp @@ -65,6 +65,8 @@ void RenderBox::Update(const RefPtr& component) UpdateBackDecoration(box->GetBackDecoration()); UpdateFrontDecoration(box->GetFrontDecoration()); animationType_ = box->GetMouseAnimationType(); + hoverAnimationType_ = animationType_; + isZoom = animationType_ == HoverAnimationType::SCALE; MarkNeedLayout(); auto tapGesture = box->GetOnClick(); @@ -643,6 +645,26 @@ void RenderBox::OnMouseHoverExitAnimation() controllerExit_->SetFillMode(FillMode::FORWARDS); } +void RenderBox::CreateFloatAnimation( + RefPtr>& floatAnimation, float beginValue, float endValue) +{ + if (!floatAnimation) { + return; + } + auto keyframeBegin = AceType::MakeRefPtr>(0.0, beginValue); + auto keyframeEnd = AceType::MakeRefPtr>(1.0, endValue); + floatAnimation->AddKeyframe(keyframeBegin); + floatAnimation->AddKeyframe(keyframeEnd); + WeakPtr weakDecoration = WeakPtr(backDecoration_); + floatAnimation->AddListener([weakBox = AceType::WeakClaim(this), weakDecoration](float value) { + auto box = weakBox.Upgrade(); + if (box) { + box->scale_ = value; + box->MarkNeedRender(); + } + }); +} + void RenderBox::CreateColorAnimation( RefPtr>& colorAnimation, const Color& beginValue, const Color& endValue) { @@ -668,6 +690,28 @@ void RenderBox::CreateColorAnimation( }); } +void RenderBox::MouseHoverEnterTest() +{ + ResetController(controllerExit_); + if (!controllerEnter_) { + controllerEnter_ = AceType::MakeRefPtr(context_); + } + if (animationType_ == HoverAnimationType::SCALE) { + scaleAnimationEnter_ = AceType::MakeRefPtr>(); + CreateFloatAnimation(scaleAnimationEnter_,1.0, 1.05); + controllerEnter_->AddInterpolator(scaleAnimationEnter_); + } else if (animationType_ == HoverAnimationType::BOARD) { + colorAnimationEnter_ = AceType::MakeRefPtr>(); + CreateColorAnimation(colorAnimationEnter_, hoverColor_, Color::FromRGBO(0, 0, 0, 0.05)); + controllerEnter_->AddInterpolator(colorAnimationEnter_); + } else { + return; + } + controllerEnter_->SetDuration(HOVER_ANIMATION_DURATION); + controllerEnter_->Play(); + controllerEnter_->SetFillMode(FillMode::FORWARDS); +} + void RenderBox::ResetController(RefPtr& controller) { if (controller) { @@ -678,6 +722,29 @@ void RenderBox::ResetController(RefPtr& controller) } } +void RenderBox::MouseHoverExitTest() +{ + ResetController(controllerEnter_); + if (!controllerExit_) { + controllerExit_ = AceType::MakeRefPtr(context_); + } + if (animationType_ == HoverAnimationType::SCALE) { + scaleAnimationExit_ = AceType::MakeRefPtr>(); + auto begin = scale_; + CreateFloatAnimation(scaleAnimationExit_, begin, 1.0); + controllerExit_->AddInterpolator(scaleAnimationExit_); + } else if (animationType_ == HoverAnimationType::BOARD) { + colorAnimationExit_ = AceType::MakeRefPtr>(); + CreateColorAnimation(colorAnimationExit_, hoverColor_, Color::FromRGBO(0, 0, 0, 0.0)); + controllerExit_->AddInterpolator(colorAnimationExit_); + } else { + return; + } + controllerExit_->SetDuration(HOVER_ANIMATION_DURATION); + controllerExit_->Play(); + controllerExit_->SetFillMode(FillMode::FORWARDS); +} + void RenderBox::StopMouseHoverAnimation() { if (controllerExit_) { diff --git a/frameworks/core/components/box/render_box.h b/frameworks/core/components/box/render_box.h index bd6d47d8106..b21418ae3dd 100644 --- a/frameworks/core/components/box/render_box.h +++ b/frameworks/core/components/box/render_box.h @@ -153,12 +153,15 @@ public: AnimatableDimension GetBackdropRadius() const; void SetWindowBlurProgress(double progress); double GetWindowBlurProgress() const; + void CreateFloatAnimation(RefPtr>& floatAnimation, float beginValue, float endValue); Size GetBorderSize() const override; ColorPropertyAnimatable::SetterMap GetColorPropertySetterMap() override; ColorPropertyAnimatable::GetterMap GetColorPropertyGetterMap() override; Offset GetGlobalOffsetExternal() const override; Offset GetGlobalOffset() const override; + void MouseHoverEnterTest() override; + void MouseHoverExitTest() override; void OnTouchTestHit( const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result) override; @@ -215,8 +218,12 @@ protected: RefPtr controllerExit_; RefPtr> colorAnimationEnter_; RefPtr> colorAnimationExit_; + RefPtr> scaleAnimationEnter_; + RefPtr> scaleAnimationExit_; HoverAnimationType animationType_ = HoverAnimationType::NONE; Color hoverColor_ = Color::TRANSPARENT; + float scale_ = 1.0f; + bool isZoom = false; private: void ResetController(RefPtr& controller); diff --git a/frameworks/core/pipeline/base/component.h b/frameworks/core/pipeline/base/component.h index 2fdafeee4c1..f4a07e99514 100644 --- a/frameworks/core/pipeline/base/component.h +++ b/frameworks/core/pipeline/base/component.h @@ -50,6 +50,14 @@ enum class UpdateRenderType : uint32_t { EVENT = 1 << 2 }; +enum class HoverAnimationType : int32_t { + NONE, + OPACITY, + SCALE, + BOARD, + AUTO, +}; + // Component is a read-only structure, represent the basic information how to display it. class ACE_EXPORT Component : public virtual AceType { DECLARE_ACE_TYPE(Component, AceType); diff --git a/frameworks/core/pipeline/base/render_node.cpp b/frameworks/core/pipeline/base/render_node.cpp index 3f56fcc17de..74caac5caa6 100644 --- a/frameworks/core/pipeline/base/render_node.cpp +++ b/frameworks/core/pipeline/base/render_node.cpp @@ -698,7 +698,11 @@ bool RenderNode::MouseHoverTest(const Point& parentLocalPoint) } // mouse state of the node is from NONE to HOVER, the callback of hover enter is triggered. if (mouseState_ == MouseState::NONE) { - OnMouseHoverEnterTest(); + if (hoverAnimationType_ == HoverAnimationType::AUTO) { + OnMouseHoverEnterTest(); + } else { + MouseHoverEnterTest(); + } mouseState_ = MouseState::HOVER; HandleMouseHoverEvent(MouseState::HOVER); } @@ -709,7 +713,11 @@ bool RenderNode::MouseHoverTest(const Point& parentLocalPoint) } // mouse state of the node is from HOVER to NONE, the callback of hover exit is triggered. if (mouseState_ == MouseState::HOVER) { - OnMouseHoverExitTest(); + if (hoverAnimationType_ == HoverAnimationType::AUTO) { + OnMouseHoverExitTest(); + } else { + MouseHoverExitTest(); + } mouseState_ = MouseState::NONE; HandleMouseHoverEvent(MouseState::NONE); } diff --git a/frameworks/core/pipeline/base/render_node.h b/frameworks/core/pipeline/base/render_node.h index 7d148f5d8fb..46d40c5c106 100644 --- a/frameworks/core/pipeline/base/render_node.h +++ b/frameworks/core/pipeline/base/render_node.h @@ -908,6 +908,8 @@ protected: virtual void OnMouseTestHit(const Offset& coordinateOffset, MouseTestResult& result) {} virtual void OnMouseHoverEnterTest() {} virtual void OnMouseHoverExitTest() {} + virtual void MouseHoverEnterTest() {} + virtual void MouseHoverExitTest() {} void PrepareLayout(); @@ -980,6 +982,7 @@ protected: bool needWindowBlur_ = false; bool needUpdateAccessibility_ = true; bool disabled_ = false; + HoverAnimationType hoverAnimationType_ = HoverAnimationType::AUTO; int32_t minPlatformVersion_ = 0; MouseState mouseState_ = MouseState::NONE;