diff --git a/frameworks/bridge/declarative_frontend/jsview/js_swiper.cpp b/frameworks/bridge/declarative_frontend/jsview/js_swiper.cpp index a9c4a17e5af562597d0b7485a2233bcad776dec1..c2c0bdd7e805af085ce1def4e8fc06aaa136b060 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_swiper.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_swiper.cpp @@ -637,9 +637,10 @@ void JSSwiper::SetSize(const JSCallbackInfo& info) void JSSwiperController::JSBind(BindingTarget globalObj) { JSClass::Declare("SwiperController"); + JSClass::CustomMethod("swipeTo", &JSSwiperController::SwipeTo); JSClass::CustomMethod("showNext", &JSSwiperController::ShowNext); - JSClass::CustomMethod("finishAnimation", &JSSwiperController::FinishAnimation); JSClass::CustomMethod("showPrevious", &JSSwiperController::ShowPrevious); + JSClass::CustomMethod("finishAnimation", &JSSwiperController::FinishAnimation); JSClass::Bind(globalObj, JSSwiperController::Constructor, JSSwiperController::Destructor); } diff --git a/frameworks/bridge/declarative_frontend/jsview/js_swiper.h b/frameworks/bridge/declarative_frontend/jsview/js_swiper.h index c1f37f573fc24cf508507c52ad55e086d4c6f193..b8333d4cc8d9bb3597362cd3db5ed8a5a26aaf32 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_swiper.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_swiper.h @@ -64,6 +64,17 @@ public: static void Constructor(const JSCallbackInfo& args); static void Destructor(JSSwiperController* scroller); + void SwipeTo(const JSCallbackInfo& args) + { + if (args.Length() < 1 || !args[0]->IsNumber()) { + LOGE("Param is not valid"); + return; + } + if (controller_) { + controller_->SwipeTo(args[0]->ToNumber()); + } + } + void ShowNext(const JSCallbackInfo& args) { if (controller_) { diff --git a/frameworks/core/components_ng/base/frame_node.h b/frameworks/core/components_ng/base/frame_node.h index b58c18381a2b50019fbbfd2ca176c1873255187b..da9195800af6fb3378b05bacc4e89f6fec444535 100644 --- a/frameworks/core/components_ng/base/frame_node.h +++ b/frameworks/core/components_ng/base/frame_node.h @@ -68,6 +68,11 @@ public: ~FrameNode() override; + int32_t FrameCount() const override + { + return 1; + } + void InitializePatternAndContext(); void MarkModifyDone(); diff --git a/frameworks/core/components_ng/base/ui_node.cpp b/frameworks/core/components_ng/base/ui_node.cpp index 4b8d8714bf8aed6de6c18bde8a4294abfd56ed7d..1ee471777e029a64855705f84caceefc33c0f012 100644 --- a/frameworks/core/components_ng/base/ui_node.cpp +++ b/frameworks/core/components_ng/base/ui_node.cpp @@ -222,4 +222,18 @@ bool UINode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint return preventBubbling; } +int32_t UINode::FrameCount() const +{ + return TotalChildCount(); +} + +int32_t UINode::TotalChildCount() const +{ + int32_t count = 0; + for (const auto& child : GetChildren()) { + count += child->FrameCount(); + } + return count; +} + } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/base/ui_node.h b/frameworks/core/components_ng/base/ui_node.h index cea4e630a9baf0e010ba5b41c291fed730905070..2a9380c235dcdc768315a45347baffe00586b04c 100644 --- a/frameworks/core/components_ng/base/ui_node.h +++ b/frameworks/core/components_ng/base/ui_node.h @@ -42,6 +42,8 @@ public: // In ets UI compiler, the atomic node does not Add Pop function, only have Create function. virtual bool IsAtomicNode() const = 0; + virtual int32_t FrameCount() const; + // Tree operation start. void AddChild(const RefPtr& child, int32_t slot = DEFAULT_NODE_SLOT); void RemoveChild(const RefPtr& child); @@ -51,6 +53,8 @@ public: void AttachToMainTree(); void DetachFromMainTree(); + int32_t TotalChildCount() const; + const std::list>& GetChildren() const { return children_; diff --git a/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.cpp index 044938a2e4bf8bb778c3c315a5f593301a383d30..2f008affb97c20be2f89e8749e9113426dbd0dfa 100644 --- a/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.cpp @@ -77,10 +77,35 @@ void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) auto displayCount = swiperLayoutProperty->GetDisplayCount().value_or(1); auto size = layoutWrapper->GetGeometryNode()->GetFrameSize(); auto childrenSize = layoutWrapper->GetTotalChildCount(); + auto itemWidth = (axis == Axis::HORIZONTAL ? (size.Width() / displayCount) : (size.Height() / displayCount)); auto parentOffset = layoutWrapper->GetGeometryNode()->GetParentGlobalOffset() + layoutWrapper->GetGeometryNode()->GetFrameOffset(); + // Effect when difference between current index and target index is greater than 1. + // eg. Current index is 0, call swipeTo method to jump to index 2, + // change item's position only 0 and 2, ignore others. + if (targetIndex_.has_value() && std::abs(targetIndex_.value() - currentIndex_) > 1) { + auto currentOffset = axis == Axis::HORIZONTAL ? OffsetF(currentOffset_, 0.0f) : OffsetF(0.0f, currentOffset_); + // Layout current item. + auto currentWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex_); + if (currentWrapper && currentWrapper->GetGeometryNode()) { + currentWrapper->GetGeometryNode()->SetFrameOffset(currentOffset); + currentWrapper->Layout(parentOffset); + } + + // Layout target item. + auto targetMainOffset = targetIndex_ > currentIndex_ ? itemWidth : -itemWidth; + auto targetOffset = + axis == Axis::HORIZONTAL ? OffsetF(targetMainOffset, 0.0f) : OffsetF(0.0f, targetMainOffset); + auto targetWrapper = layoutWrapper->GetOrCreateChildByIndex(targetIndex_.value()); + if (targetWrapper && targetWrapper->GetGeometryNode()) { + targetWrapper->GetGeometryNode()->SetFrameOffset(currentOffset + targetOffset); + targetWrapper->Layout(parentOffset); + } + return; + } + // layout children. for (auto index = startIndex_.value(); index <= endIndex_.value(); ++index) { // When enable loop, adjust offset. @@ -92,7 +117,6 @@ void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) } auto offset = OffsetF(0.0, 0.0); - auto itemWidth = (axis == Axis::HORIZONTAL ? (size.Width() / displayCount) : (size.Height() / displayCount)); if (axis == Axis::HORIZONTAL) { offset += OffsetF((loopIndex - currentIndex_) * itemWidth + currentOffset_, 0.0f); } else if (axis == Axis::VERTICAL) { diff --git a/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.h b/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.h index 884f851069042ddc07701b4e4c437906e79d34e1..29d2496a85b521faa4b76a7eedfb61bdbd9a9360 100644 --- a/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.h +++ b/frameworks/core/components_ng/pattern/swiper/swiper_layout_algorithm.h @@ -18,6 +18,7 @@ #include #include +#include #include "base/geometry/axis.h" #include "base/memory/referenced.h" @@ -57,12 +58,23 @@ public: return endIndex_.value_or(0); } + void SetTargetIndex(std::optional targetIndex) + { + targetIndex_ = targetIndex; + } + + void ResetTargetIndex() + { + targetIndex_.reset(); + } + void Measure(LayoutWrapper* layoutWrapper) override; void Layout(LayoutWrapper* layoutWrapper) override; private: int32_t currentIndex_ = 0; + std::optional targetIndex_; int32_t preStartIndex_ = 0; int32_t preEndIndex_ = 0; std::optional startIndex_; diff --git a/frameworks/core/components_ng/pattern/swiper/swiper_pattern.cpp b/frameworks/core/components_ng/pattern/swiper/swiper_pattern.cpp index 6954932d0918743a27b2d2c15ad5d330979c5a6b..0bc7b2fdc4a24968c0702d11825928cac08dff59 100644 --- a/frameworks/core/components_ng/pattern/swiper/swiper_pattern.cpp +++ b/frameworks/core/components_ng/pattern/swiper/swiper_pattern.cpp @@ -72,7 +72,7 @@ void SwiperPattern::OnModifyDone() auto gestureHub = hub->GetOrCreateGestureEventHub(); CHECK_NULL_VOID(gestureHub); - auto childrenSize = static_cast(host->GetChildren().size()); + auto childrenSize = TotalCount(); if (CurrentIndex() >= 0 && CurrentIndex() < childrenSize) { currentIndex_ = CurrentIndex(); } else { @@ -112,11 +112,29 @@ void SwiperPattern::FireChangeEvent() const swiperEventHub->FireChangeEvent(currentIndex_); } +void SwiperPattern::SwipeTo(int32_t index) +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto targetIndex = std::clamp(index, 0, TotalCount() - 1); + if (currentIndex_ == targetIndex) { + LOGD("Target index is same with current index."); + return; + } + + StopAutoPlay(); + StopTranslateAnimation(); + targetIndex_ = targetIndex; + // TODO Adapt displayCount. + auto translateOffset = targetIndex_.value() > currentIndex_ ? -MainSize() : MainSize(); + PlayTranslateAnimation(0, translateOffset, targetIndex_.value(), true); +} + void SwiperPattern::ShowNext() { auto host = GetHost(); CHECK_NULL_VOID(host); - auto childrenSize = static_cast(host->GetChildren().size()); + auto childrenSize = TotalCount(); if (currentIndex_ >= childrenSize - 1 && !IsLoop()) { LOGW("already last one, can't show next"); return; @@ -130,7 +148,7 @@ void SwiperPattern::ShowPrevious() { auto host = GetHost(); CHECK_NULL_VOID(host); - auto childrenSize = static_cast(host->GetChildren().size()); + auto childrenSize = TotalCount(); if (currentIndex_ <= 0 && !IsLoop()) { LOGW("already first one, can't show previous"); return; @@ -160,6 +178,14 @@ void SwiperPattern::InitSwiperController() if (swiperController_->HasInitialized()) { return; } + + swiperController_->SetSwipeToImpl([weak = WeakClaim(this)](int32_t index, bool reverse) { + auto swiper = weak.Upgrade(); + if (swiper) { + swiper->SwipeTo(index); + } + }); + swiperController_->SetShowNextImpl([weak = WeakClaim(this)]() { auto swiper = weak.Upgrade(); if (swiper) { @@ -291,16 +317,16 @@ void SwiperPattern::Tick(uint64_t duration) auto host = GetHost(); CHECK_NULL_VOID(host); + auto childrenSize = TotalCount(); elapsedTime_ += duration; if (elapsedTime_ >= static_cast(GetInterval())) { - if (currentIndex_ >= static_cast(host->GetChildren().size()) - 1 && !IsLoop()) { + if (currentIndex_ >= childrenSize - 1 && !IsLoop()) { LOGD("already last one, stop auto play because not loop"); if (scheduler_) { scheduler_->Stop(); } } else { - PlayTranslateAnimation( - 0, -MainSize(), (currentIndex_ + 1) % static_cast(host->GetChildren().size())); + PlayTranslateAnimation(0, -MainSize(), (currentIndex_ + 1) % childrenSize); } elapsedTime_ = 0; } @@ -322,7 +348,7 @@ void SwiperPattern::StartAutoPlay() if (!scheduler_ || !IsAutoPlay()) { return; } - bool reachEnd = currentIndex_ >= static_cast(host->GetChildren().size()) - 1 && !IsLoop(); + bool reachEnd = currentIndex_ >= TotalCount() - 1 && !IsLoop(); if (reachEnd && scheduler_->IsActive()) { scheduler_->Stop(); } else { @@ -444,7 +470,7 @@ void SwiperPattern::HandleDragEnd(double dragVelocity) } // Adjust next item index when loop and index is out of range. - auto childrenSize = static_cast(host->GetChildren().size()); + auto childrenSize = TotalCount(); if (IsLoop()) { if (nextIndex < 0) { nextIndex = childrenSize + nextIndex; @@ -492,6 +518,7 @@ void SwiperPattern::PlayTranslateAnimation(float startPos, float endPos, int32_t auto swiper = weak.Upgrade(); CHECK_NULL_VOID(swiper); swiper->currentOffset_ = 0.0; + swiper->targetIndex_.reset(); if (swiper->currentIndex_ != nextIndex) { swiper->currentIndex_ = nextIndex; swiper->FireChangeEvent(); @@ -578,9 +605,8 @@ bool SwiperPattern::IsOutOfBoundary(double mainOffset) const } mainOffset = std::fmod(currentOffset_, MainSize()); - auto childrenSize = static_cast(host->GetChildren().size()); auto isOutOfStart = currentIndex_ == 0 && GreatOrEqual(mainOffset, 0.0); - auto isOutOfEnd = currentIndex_ == childrenSize - 1 && LessOrEqual(mainOffset, 0.0); + auto isOutOfEnd = currentIndex_ == TotalCount() - 1 && LessOrEqual(mainOffset, 0.0); return isOutOfStart || isOutOfEnd; } @@ -658,4 +684,11 @@ bool SwiperPattern::IsDisableSwipe() const return swiperPaintProperty->GetDisableSwipe().value_or(false); } +int32_t SwiperPattern::TotalCount() const +{ + auto host = GetHost(); + CHECK_NULL_RETURN(host, 0); + return host->TotalChildCount(); +} + } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/swiper/swiper_pattern.h b/frameworks/core/components_ng/pattern/swiper/swiper_pattern.h index b897afd773e6991f0fdf5f079e6bf4876bcbb7c7..a79d563c5f676d481acce86692528e53ea0d4d37 100644 --- a/frameworks/core/components_ng/pattern/swiper/swiper_pattern.h +++ b/frameworks/core/components_ng/pattern/swiper/swiper_pattern.h @@ -16,6 +16,8 @@ #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_PATTERN_H #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_PATTERN_H +#include + #include "base/geometry/axis.h" #include "base/memory/referenced.h" #include "core/components/common/layout/constants.h" @@ -56,6 +58,7 @@ public: { auto layoutAlgorithm = MakeRefPtr(currentIndex_, startIndex_, endIndex_); layoutAlgorithm->SetCurrentOffset(currentOffset_); + layoutAlgorithm->SetTargetIndex(targetIndex_); return layoutAlgorithm; } @@ -109,6 +112,7 @@ private: void PlayFadeAnimation(); // Implement of swiper controller + void SwipeTo(int32_t index); void ShowNext(); void ShowPrevious(); void FinishAnimation(); @@ -131,6 +135,7 @@ private: bool IsAutoPlay() const; bool IsLoop() const; bool IsDisableSwipe() const; + int32_t TotalCount() const; RefPtr panEvent_; RefPtr touchEvent_; @@ -151,6 +156,7 @@ private: int32_t startIndex_ = 0; int32_t endIndex_ = 0; int32_t currentIndex_ = 0; + std::optional targetIndex_; float currentOffset_ = 0.0f;