diff --git a/frameworks/core/components_ng/event/focus_hub.cpp b/frameworks/core/components_ng/event/focus_hub.cpp index 443a04e870c998000a7e2d6d2deb9b99e29f715e..cb1b10b9970c6f76c89a3e8b42c52d8ad81185ee 100644 --- a/frameworks/core/components_ng/event/focus_hub.cpp +++ b/frameworks/core/components_ng/event/focus_hub.cpp @@ -937,8 +937,10 @@ void FocusHub::OnFocusNode() if (parentFocusHub) { parentFocusHub->SetLastFocusNodeIndex(AceType::Claim(this)); } - HandleParentScroll(); // If current focus node has a scroll parent. Handle the scroll event. - PaintFocusState(); + if (PaintFocusState() || isFocusUnit_) { + // If current focus node has focus state or it's a focus unit. Scroll it in parent while it's focused. + HandleParentScroll(); + } auto frameNode = GetFrameNode(); CHECK_NULL_VOID_NOLOG(frameNode); frameNode->OnAccessibilityEvent(AccessibilityEventType::FOCUS); @@ -975,6 +977,13 @@ void FocusHub::CheckFocusStateStyle(bool onFocus) } } +bool FocusHub::HasFocusStateStyle() +{ + auto eventHub = eventHub_.Upgrade(); + CHECK_NULL_RETURN(eventHub, false); + return eventHub->HasStateStyle(UI_STATE_FOCUSED); +} + void FocusHub::OnFocusScope() { std::list> focusNodes; @@ -1020,10 +1029,6 @@ bool FocusHub::PaintFocusState(bool isNeedStateStyles) { auto context = PipelineContext::GetCurrentContext(); CHECK_NULL_RETURN(context, false); - if (isNeedStateStyles && context->GetIsFocusActive()) { - // check focus state style. - CheckFocusStateStyle(true); - } auto frameNode = GetFrameNode(); CHECK_NULL_RETURN(frameNode, false); auto renderContext = frameNode->GetRenderContext(); @@ -1032,6 +1037,11 @@ bool FocusHub::PaintFocusState(bool isNeedStateStyles) return false; } + if (isNeedStateStyles) { + // do focus state style. + CheckFocusStateStyle(true); + } + if (focusStyleType_ == FocusStyleType::CUSTOM_REGION) { CHECK_NULL_RETURN(getInnerFocusRectFunc_, false); RoundRect focusRectInner; @@ -1088,6 +1098,7 @@ bool FocusHub::PaintFocusState(bool isNeedStateStyles) bool FocusHub::PaintAllFocusState() { if (PaintFocusState()) { + HandleParentScroll(); return true; } std::list> focusNodes; @@ -1163,7 +1174,7 @@ void FocusHub::ClearAllFocusState() bool FocusHub::IsNeedPaintFocusState() { - if (focusType_ == FocusType::DISABLE || focusStyleType_ == FocusStyleType::NONE) { + if (focusType_ == FocusType::DISABLE || (focusStyleType_ == FocusStyleType::NONE && !HasFocusStateStyle())) { return false; } if (focusType_ == FocusType::NODE) { @@ -1466,7 +1477,7 @@ void FocusHub::HandleParentScroll() const { auto context = PipelineContext::GetCurrentContext(); CHECK_NULL_VOID(context); - if (!context->GetIsFocusActive() || (focusType_ != FocusType::NODE && !isFocusUnit_)) { + if (!context->GetIsFocusActive() || (focusType_ == FocusType::DISABLE && !isFocusUnit_)) { return; } auto parent = GetParentFocusHub(); @@ -1481,14 +1492,60 @@ void FocusHub::HandleParentScroll() const parent = parent->GetParentFocusHub(); continue; } - parentPattern = parentFrame->GetPattern(); - if (parentPattern && parentPattern->ScrollToNode(GetFrameNode())) { + if (ScrollToTargetFrameRect(parentFrame)) { return; } parent = parent->GetParentFocusHub(); } } +bool FocusHub::ScrollToTargetFrameRect(const RefPtr& tarFrameNode) const +{ + auto curFrameNode = GetFrameNode(); + CHECK_NULL_RETURN(curFrameNode, false); + CHECK_NULL_RETURN(tarFrameNode, false); + auto tarPattern = tarFrameNode->GetPattern(); + CHECK_NULL_RETURN(tarPattern, false); + tarPattern->ScrollToNode(curFrameNode); + + auto scrollAbility = tarPattern->GetScrollAbility(); + auto scrollFunc = scrollAbility.first; + auto scrollAxis = scrollAbility.second; + if (!scrollFunc || scrollAxis == Axis::NONE) { + return false; + } + auto tarGeometryNode = tarFrameNode->GetGeometryNode(); + CHECK_NULL_RETURN(tarGeometryNode, false); + auto tarFrameSize = tarGeometryNode->GetFrameSize(); + auto offsetToTarFrame = curFrameNode->GetOffsetRelativeToWindow() - tarFrameNode->GetOffsetRelativeToWindow(); + auto curGeometry = curFrameNode->GetGeometryNode(); + CHECK_NULL_RETURN(curGeometry, false); + auto curFrameSize = curGeometry->GetFrameSize(); + LOGD("Node: %{public}s/%{public}d - [%{public}f,%{public}f] on focus. Offset to target node: " + "%{public}s/%{public}d - [%{public}f,%{public}f] is (%{public}f,%{public}f).", + curFrameNode->GetTag().c_str(), curFrameNode->GetId(), curFrameSize.Width(), curFrameSize.Height(), + tarFrameNode->GetTag().c_str(), tarFrameNode->GetId(), tarFrameSize.Width(), tarFrameSize.Height(), + offsetToTarFrame.GetX(), offsetToTarFrame.GetY()); + + float diffToTarFrame = scrollAxis == Axis::VERTICAL ? offsetToTarFrame.GetY() : offsetToTarFrame.GetX(); + if (NearZero(diffToTarFrame)) { + return false; + } + float curFrameLength = scrollAxis == Axis::VERTICAL ? curFrameSize.Height() : curFrameSize.Width(); + float tarFrameLength = scrollAxis == Axis::VERTICAL ? tarFrameSize.Height() : tarFrameSize.Width(); + float moveOffset = 0.0; + if (LessNotEqual(diffToTarFrame, 0)) { + moveOffset = -diffToTarFrame; + } else if (GreatNotEqual(diffToTarFrame + curFrameLength, tarFrameLength)) { + moveOffset = tarFrameLength - diffToTarFrame - curFrameLength; + } + if (!NearZero(moveOffset)) { + LOGD("Scroll offset: %{public}f on axis: %{public}d", moveOffset, scrollAxis); + return scrollFunc(moveOffset); + } + return false; +} + bool FocusHub::RequestFocusImmediatelyById(const std::string& id) { auto focusNode = GetChildFocusNodeById(id); diff --git a/frameworks/core/components_ng/event/focus_hub.h b/frameworks/core/components_ng/event/focus_hub.h index 3cf2eafd28de7e317a7c7b41ade40b36c31294cd..8f09d9a50cb40a4c03529e8c058b6ba844d395e5 100644 --- a/frameworks/core/components_ng/event/focus_hub.h +++ b/frameworks/core/components_ng/event/focus_hub.h @@ -28,6 +28,7 @@ class FrameNode; class FocusHub; class EventHub; +using FocusScrollFunc = std::function; using TabIndexNodeList = std::list>>; constexpr int32_t DEFAULT_TAB_FOCUSED_INDEX = -2; constexpr int32_t NONE_TAB_FOCUSED_INDEX = -1; @@ -529,6 +530,7 @@ public: RefPtr GetChildFocusNodeByType(FocusNodeType nodeType = FocusNodeType::DEFAULT); RefPtr GetChildFocusNodeById(const std::string& id); void HandleParentScroll() const; + bool ScrollToTargetFrameRect(const RefPtr& tarFrameNode) const; int32_t GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes); bool RequestFocusImmediatelyById(const std::string& id); @@ -878,6 +880,7 @@ private: void ScrollToLastFocusIndex() const; void CheckFocusStateStyle(bool onFocus); + bool HasFocusStateStyle(); bool IsNeedPaintFocusState(); diff --git a/frameworks/core/components_ng/pattern/grid/grid_pattern.h b/frameworks/core/components_ng/pattern/grid/grid_pattern.h index 633ca0b205836630e43334833aeb6dd4c22228cc..20feca4c960c2e1654299501b2c1fe5a2bda25f2 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_pattern.h +++ b/frameworks/core/components_ng/pattern/grid/grid_pattern.h @@ -104,6 +104,19 @@ public: void ScrollToFocusNodeIndex(int32_t index) override; + std::pair GetScrollAbility() override + { + return { [wp = WeakClaim(this)](float moveOffset) -> bool { + auto pattern = wp.Upgrade(); + if (pattern) { + pattern->ScrollBy(moveOffset); + return true; + } + return false; + }, + GetAxis() }; + } + bool ScrollToNode(const RefPtr& focusFrameNode) override; RefPtr CreateEventHub() override diff --git a/frameworks/core/components_ng/pattern/list/list_pattern.cpp b/frameworks/core/components_ng/pattern/list/list_pattern.cpp index f09887dab06f65245d7dbe2cf9d2b89afbcbb587..d61cce575bb0d07844251f33abe4d25f25243cc6 100644 --- a/frameworks/core/components_ng/pattern/list/list_pattern.cpp +++ b/frameworks/core/components_ng/pattern/list/list_pattern.cpp @@ -1092,16 +1092,28 @@ WeakPtr ListPattern::GetChildFocusNodeByIndex(int32_t tarMainIndex, in bool ListPattern::ScrollToNode(const RefPtr& focusFrameNode) { - CHECK_NULL_RETURN_NOLOG(focusFrameNode, false); - auto focusPattern = focusFrameNode->GetPattern(); - CHECK_NULL_RETURN_NOLOG(focusPattern, false); - auto curIndex = focusPattern->GetIndexInList(); - ScrollToIndex(curIndex, smooth_, ScrollAlign::AUTO); - auto pipeline = PipelineContext::GetCurrentContext(); - if (pipeline) { - pipeline->FlushUITasks(); + auto curFrameNode = GetHost(); + CHECK_NULL_RETURN(curFrameNode, false); + auto tarFrameNode = focusFrameNode; + while (tarFrameNode) { + auto tarPattern = tarFrameNode->GetPattern(); + auto tarFocusParent = tarFrameNode->GetFocusParent(); + if (!tarPattern || !tarFocusParent || tarFocusParent != curFrameNode) { + tarFrameNode = tarFocusParent; + continue; + } + auto curIndex = tarPattern->GetIndexInList(); + LOGI("Target scroll ListItem is %{public}s/%{public}d. Index in %{public}s/%{public}d is %{public}d", + tarFrameNode->GetTag().c_str(), tarFrameNode->GetId(), curFrameNode->GetTag().c_str(), + curFrameNode->GetId(), curIndex); + ScrollToIndex(curIndex, smooth_, ScrollAlign::AUTO); + auto pipeline = PipelineContext::GetCurrentContext(); + if (pipeline) { + pipeline->FlushUITasks(); + } + return true; } - return true; + return false; } WeakPtr ListPattern::ScrollAndFindFocusNode(int32_t nextIndex, int32_t curIndex, int32_t& nextIndexInGroup, diff --git a/frameworks/core/components_ng/pattern/list/list_pattern.h b/frameworks/core/components_ng/pattern/list/list_pattern.h index d52dc6af84049a544ecaed8542509a80b17882d3..f8107ce78a260735b864f5c2c54264bfda03edd2 100644 --- a/frameworks/core/components_ng/pattern/list/list_pattern.h +++ b/frameworks/core/components_ng/pattern/list/list_pattern.h @@ -136,6 +136,19 @@ public: }); } + std::pair GetScrollAbility() override + { + return { [wp = WeakClaim(this)](float moveOffset) -> bool { + auto pattern = wp.Upgrade(); + if (pattern) { + pattern->ScrollBy(-moveOffset); + return true; + } + return false; + }, + GetAxis() }; + } + bool ScrollToNode(const RefPtr& focusFrameNode) override; const ListLayoutAlgorithm::PositionMap& GetItemPosition() const diff --git a/frameworks/core/components_ng/pattern/pattern.h b/frameworks/core/components_ng/pattern/pattern.h index f80a31e7684458e2d2aa5b8e9b18274eb1cf89dc..e00f653b68386d16b05cef0cd58d997600fd2fae 100644 --- a/frameworks/core/components_ng/pattern/pattern.h +++ b/frameworks/core/components_ng/pattern/pattern.h @@ -308,6 +308,11 @@ public: return ScopeFocusAlgorithm(); } + virtual std::pair GetScrollAbility() + { + return { nullptr, Axis::NONE }; + } + virtual bool ScrollToNode(const RefPtr& focusFrameNode) { return false; diff --git a/frameworks/core/components_ng/pattern/scroll/scroll_pattern.cpp b/frameworks/core/components_ng/pattern/scroll/scroll_pattern.cpp index cd658a7a3bd5c0970a33d6695bb6bc2dbe8fb572..af2e2e49dab9bdc179ee0510758bc319b45dce89 100644 --- a/frameworks/core/components_ng/pattern/scroll/scroll_pattern.cpp +++ b/frameworks/core/components_ng/pattern/scroll/scroll_pattern.cpp @@ -603,73 +603,6 @@ void ScrollPattern::SetAccessibilityAction() }); } -OffsetF ScrollPattern::GetOffsetToScroll(const RefPtr& childFrame) const -{ - auto frameNode = GetHost(); - CHECK_NULL_RETURN(frameNode, OffsetF()); - CHECK_NULL_RETURN(childFrame, OffsetF()); - auto childGeometryNode = childFrame->GetGeometryNode(); - CHECK_NULL_RETURN(childGeometryNode, OffsetF()); - OffsetF result = childGeometryNode->GetFrameOffset(); - auto parent = childFrame->GetParent(); - while (parent) { - auto parentFrame = AceType::DynamicCast(parent); - if (!parentFrame) { - parent = parent->GetParent(); - continue; - } - if (parentFrame == frameNode) { - return result; - } - auto parentGeometryNode = parentFrame->GetGeometryNode(); - if (!parentGeometryNode) { - parent = parent->GetParent(); - continue; - } - result += parentGeometryNode->GetFrameOffset(); - parent = parent->GetParent(); - } - return OffsetF(0.0, 0.0); -} - -bool ScrollPattern::ScrollToNode(const RefPtr& focusFrameNode) -{ - CHECK_NULL_RETURN(focusFrameNode, false); - auto focusGeometryNode = focusFrameNode->GetGeometryNode(); - CHECK_NULL_RETURN(focusGeometryNode, false); - auto focusNodeSize = focusGeometryNode->GetFrameSize(); - auto focusNodeOffsetToScrolll = GetOffsetToScroll(focusFrameNode); - auto scrollFrame = GetHost(); - CHECK_NULL_RETURN(scrollFrame, false); - auto scrollGeometry = scrollFrame->GetGeometryNode(); - CHECK_NULL_RETURN(scrollGeometry, false); - auto scrollFrameSize = scrollGeometry->GetFrameSize(); - LOGD("Child: %{public}s/%{public}d on focus. Size is (%{public}f,%{public}f). Offset to Scroll is " - "(%{public}f,%{public}f). Scroll size is (%{public}f,%{public}f)", - focusFrameNode->GetTag().c_str(), focusFrameNode->GetId(), focusNodeSize.Width(), focusNodeSize.Height(), - focusNodeOffsetToScrolll.GetX(), focusNodeOffsetToScrolll.GetY(), scrollFrameSize.Width(), - scrollFrameSize.Height()); - - float focusNodeDiffToScroll = - GetAxis() == Axis::VERTICAL ? focusNodeOffsetToScrolll.GetY() : focusNodeOffsetToScrolll.GetX(); - if (NearZero(focusNodeDiffToScroll)) { - return false; - } - float focusNodeLength = GetAxis() == Axis::VERTICAL ? focusNodeSize.Height() : focusNodeSize.Width(); - float scrollFrameLength = GetAxis() == Axis::VERTICAL ? scrollFrameSize.Height() : scrollFrameSize.Width(); - float moveOffset = 0.0; - if (LessNotEqual(focusNodeDiffToScroll, 0)) { - moveOffset = -focusNodeDiffToScroll; - } else if (GreatNotEqual(focusNodeDiffToScroll + focusNodeLength, scrollFrameLength)) { - moveOffset = scrollFrameLength - focusNodeDiffToScroll - focusNodeLength; - } - if (!NearZero(moveOffset)) { - LOGD("Scroll offset: %{public}f on axis: %{public}d", moveOffset, GetAxis()); - return OnScrollCallback(moveOffset, SCROLL_FROM_FOCUS_JUMP); - } - return false; -} - std::optional ScrollPattern::CalePredictSnapOffset(float delta) { std::optional predictSnapOffset; diff --git a/frameworks/core/components_ng/pattern/scroll/scroll_pattern.h b/frameworks/core/components_ng/pattern/scroll/scroll_pattern.h index 91f9895eb9fed702109f68bf3d35a6a344628b73..4e217156368df4f88250375a9190430583a13a39 100644 --- a/frameworks/core/components_ng/pattern/scroll/scroll_pattern.h +++ b/frameworks/core/components_ng/pattern/scroll/scroll_pattern.h @@ -169,7 +169,14 @@ public: return { FocusType::SCOPE, true }; } - bool ScrollToNode(const RefPtr& focusFrameNode) override; + std::pair GetScrollAbility() override + { + return { [wp = WeakClaim(this)](float moveOffset) -> bool { + auto pattern = wp.Upgrade(); + return pattern ? pattern->OnScrollCallback(moveOffset, SCROLL_FROM_FOCUS_JUMP) : false; + }, + GetAxis() }; + } bool IsAtTop() const override; bool IsAtBottom() const override; @@ -291,7 +298,6 @@ private: void FireOnScrollStop(); void SetAccessibilityAction(); void CheckScrollable(); - OffsetF GetOffsetToScroll(const RefPtr& childFrame) const; RefPtr positionController_; float currentOffset_ = 0.0f; diff --git a/frameworks/core/components_ng/test/mock/pattern/grid/mock_grid_pattern.cpp b/frameworks/core/components_ng/test/mock/pattern/grid/mock_grid_pattern.cpp index ff11ff66f83ed0ccac4de5c91447bd55ac251ec9..56f5d446342a1906fd91d4d082d5819c4612094b 100644 --- a/frameworks/core/components_ng/test/mock/pattern/grid/mock_grid_pattern.cpp +++ b/frameworks/core/components_ng/test/mock/pattern/grid/mock_grid_pattern.cpp @@ -53,6 +53,8 @@ bool GridPattern::ScrollToNode(const RefPtr& focusFrameNode) return false; } +void GridPattern::ScrollBy(float offset) {}; + CanvasDrawFunction GridPaintMethod::GetForegroundDrawFunction(PaintWrapper* /* paintWrapper */) { return [](RSCanvas& canvas) {}; diff --git a/frameworks/core/components_ng/test/mock/pattern/list/mock_list_pattern.cpp b/frameworks/core/components_ng/test/mock/pattern/list/mock_list_pattern.cpp index c84b08f8499a132b23aff1a0fcddd05c97596073..d9a6076f21aaf984eeb7a60c4e02738b0d5a7cbd 100644 --- a/frameworks/core/components_ng/test/mock/pattern/list/mock_list_pattern.cpp +++ b/frameworks/core/components_ng/test/mock/pattern/list/mock_list_pattern.cpp @@ -55,6 +55,8 @@ bool ListPattern::ScrollToNode(const RefPtr& focusFrameNode) return false; } +void ListPattern::ScrollBy(float offset) {}; + bool ListPattern::IsAtBottom() const { return false;