From b7cc3866a0b27c4a28d5a524d4cb78b0b82b025f Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 09:56:07 +0800 Subject: [PATCH 1/6] fix cross gap layout Signed-off-by: Tianer Zhou Change-Id: Ic355747bc355fe241d08682554bb333ea0c15ed6 --- .../sliding_window/water_flow_layout_sw.cpp | 4 +- .../waterflow/water_flow_layout_property.cpp | 16 +++++-- .../waterflow/water_flow_sw_layout_test.cpp | 44 +++++++++++++++++++ .../pattern/waterflow/water_flow_test_ng.cpp | 43 ++++++------------ .../waterflow/water_flow_top_down_test.cpp | 44 +++++++++++++++++++ 5 files changed, 117 insertions(+), 34 deletions(-) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp index 75e0833e1c2..cfbbb41f275 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp @@ -72,7 +72,7 @@ void WaterFlowLayoutSW::Layout(LayoutWrapper* wrapper) float crossPos = rtl ? selfCrossLen + mainGap_ : 0.0f; for (size_t i = 0; i < info_->lanes_.size(); ++i) { if (rtl) { - crossPos -= itemCrossSize_[i] + mainGap_; + crossPos -= itemCrossSize_[i] + crossGap_; } auto& lane = info_->lanes_[i]; float mainPos = lane.startPos; @@ -96,7 +96,7 @@ void WaterFlowLayoutSW::Layout(LayoutWrapper* wrapper) mainPos += item.mainSize + mainGap_; } if (!rtl) { - crossPos += itemCrossSize_[i] + mainGap_; + crossPos += itemCrossSize_[i] + crossGap_; } } diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp index 4ef26810a42..b9281624faf 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp @@ -96,19 +96,29 @@ RefPtr WaterFlowLayoutProperty::Clone() const namespace { inline bool UseSegmentedLayout(const RefPtr& host) { - return SystemProperties::WaterFlowUseSegmentedLayout() || host->GetPattern()->GetSections(); + CHECK_NULL_RETURN(host, false); + auto pattern = host->GetPattern(); + return SystemProperties::WaterFlowUseSegmentedLayout() || (pattern && pattern->GetSections()); +} + +inline bool SWLayout(const RefPtr& host) { + CHECK_NULL_RETURN(host, false); + auto pattern = host->GetPattern(); + return pattern && pattern->GetLayoutMode() == WaterFlowLayoutMode::SLIDING_WINDOW; } } // namespace void WaterFlowLayoutProperty::OnRowsGapUpdate(Dimension /* rowsGap */) const { - if (GetAxis() == Axis::VERTICAL || UseSegmentedLayout(GetHost())) { + auto host = GetHost(); + if (GetAxis() == Axis::VERTICAL || UseSegmentedLayout(host) || SWLayout(host)) { ResetWaterflowLayoutInfoAndMeasure(); } } void WaterFlowLayoutProperty::OnColumnsGapUpdate(Dimension /* columnsGap */) const { - if (GetAxis() == Axis::HORIZONTAL || UseSegmentedLayout(GetHost())) { + auto host = GetHost(); + if (GetAxis() == Axis::HORIZONTAL || UseSegmentedLayout(host) || SWLayout(host)) { ResetWaterflowLayoutInfoAndMeasure(); } } diff --git a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp index 3d006cf3b94..3adb21e1049 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp @@ -327,4 +327,48 @@ HWTEST_F(WaterFlowSWTest, Misaligned001, TestSize.Level1) EXPECT_EQ(info_->lanes_[0].startPos, 0.0f); EXPECT_EQ(info_->lanes_[0].items_.front().idx, 0); } + +/** + * @tc.name: PositionController100 + * @tc.desc: Test PositionController AnimateTo and ScrollTo, should be disabled + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowSWTest, PositionController100, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create List Item + */ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("1fr 1fr"); + CreateItem(TOTAL_LINE_NUMBER * 2); + }); + auto controller = pattern_->positionController_; + /** + * @tc.steps: step8. Test AnimateTo function + * @tc.expected: pattern_->isAnimationStop_ is false + */ + pattern_->AnimateTo(1.5, 1.f, Curves::LINEAR, false, false); + EXPECT_TRUE(pattern_->isAnimationStop_); + + /** + * @tc.steps: step8. test event + * @tc.expected: return the scroll event is ture. + */ + bool isOnWillScrollCallBack = false; + Dimension willScrollOffset; + ScrollState willScrollState; + auto onWillScroll = [&willScrollOffset, &willScrollState, &isOnWillScrollCallBack]( + Dimension offset, ScrollState state, ScrollSource source) { + willScrollOffset = offset; + willScrollState = state; + isOnWillScrollCallBack = true; + ScrollFrameResult result; + result.offset = offset; + return result; + }; + + eventHub_->SetOnWillScroll(std::move(onWillScroll)); + pattern_->ScrollTo(ITEM_HEIGHT * 5); + EXPECT_FALSE(isOnWillScrollCallBack); +} } // namespace OHOS::Ace::NG diff --git a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp index fec0c98a450..6cc316d0d9b 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp @@ -351,7 +351,20 @@ HWTEST_F(WaterFlowTestNg, Property008, TestSize.Level1) model.SetRowsGap(Dimension(-5)); model.SetColumnsGap(Dimension(-10)); }); - EXPECT_FALSE(false); + + EXPECT_EQ(GetChildWidth(frameNode_, 0), WATERFLOW_WIDTH / 2.0f); + EXPECT_EQ(GetChildWidth(frameNode_, 1), WATERFLOW_WIDTH / 2.0f); + + layoutProperty_->UpdateColumnsGap(Dimension(5.0f)); + FlushLayoutTask(frameNode_); + EXPECT_EQ(GetChildWidth(frameNode_, 0), (WATERFLOW_WIDTH - 5.0f) / 2.0f); + EXPECT_EQ(GetChildWidth(frameNode_, 1), (WATERFLOW_WIDTH - 5.0f) / 2.0f); + EXPECT_EQ(GetChildX(frameNode_, 1), WATERFLOW_WIDTH / 2.0f + 2.5f); + layoutProperty_->UpdateColumnsGap(Dimension(10.0f)); + FlushLayoutTask(frameNode_); + EXPECT_EQ(GetChildWidth(frameNode_, 0), (WATERFLOW_WIDTH - 10.0f) / 2.0f); + EXPECT_EQ(GetChildWidth(frameNode_, 1), (WATERFLOW_WIDTH - 10.0f) / 2.0f); + EXPECT_EQ(GetChildX(frameNode_, 1), WATERFLOW_WIDTH / 2.0f + 5.0f); } /** @@ -924,13 +937,6 @@ HWTEST_F(WaterFlowTestNg, PositionController006, TestSize.Level1) FlushLayoutTask(frameNode_); } EXPECT_TRUE(pattern_->IsAtTop()); - - /** - * @tc.steps: step8. Test AnimateTo function - * @tc.expected: pattern_->isAnimationStop_ is false - */ - pattern_->AnimateTo(1.5, 1.f, Curves::LINEAR, false, false); - EXPECT_FALSE(pattern_->isAnimationStop_); } namespace { @@ -1197,27 +1203,6 @@ HWTEST_F(WaterFlowTestNg, PositionController009, TestSize.Level1) FlushLayoutTask(frameNode_); } EXPECT_TRUE(pattern_->IsAtTop()); - - /** - * @tc.steps: step8. test event - * @tc.expected: return the scroll event is ture. - */ - bool isOnWillScrollCallBack = false; - Dimension willScrollOffset; - ScrollState willScrollState; - auto onWillScroll = [&willScrollOffset, &willScrollState, &isOnWillScrollCallBack]( - Dimension offset, ScrollState state, ScrollSource source) { - willScrollOffset = offset; - willScrollState = state; - isOnWillScrollCallBack = true; - ScrollFrameResult result; - result.offset = offset; - return result; - }; - - eventHub_->SetOnWillScroll(std::move(onWillScroll)); - pattern_->ScrollTo(ITEM_HEIGHT * 5); - EXPECT_TRUE(isOnWillScrollCallBack); } /** diff --git a/test/unittest/core/pattern/waterflow/water_flow_top_down_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_top_down_test.cpp index 1273c2ebca8..4e26338de7b 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_top_down_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_top_down_test.cpp @@ -435,4 +435,48 @@ HWTEST_F(WaterFlowTestNg, WaterFlowTest012, TestSize.Level1) EXPECT_TRUE(IsEqual(pattern_->GetOverScrollOffset(ITEM_HEIGHT), { 100, 100 })); EXPECT_TRUE(IsEqual(pattern_->GetOverScrollOffset(3 * ITEM_HEIGHT), { 300, 300 })); } + +/** + * @tc.name: PositionController100 + * @tc.desc: Test PositionController AnimateTo and ScrollTo + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowTestNg, PositionController100, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create List Item + */ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("1fr 1fr"); + CreateItem(TOTAL_LINE_NUMBER * 2); + }); + auto controller = pattern_->positionController_; + /** + * @tc.steps: step8. Test AnimateTo function + * @tc.expected: pattern_->isAnimationStop_ is false + */ + pattern_->AnimateTo(1.5, 1.f, Curves::LINEAR, false, false); + EXPECT_FALSE(pattern_->isAnimationStop_); + + /** + * @tc.steps: step8. test event + * @tc.expected: return the scroll event is ture. + */ + bool isOnWillScrollCallBack = false; + Dimension willScrollOffset; + ScrollState willScrollState; + auto onWillScroll = [&willScrollOffset, &willScrollState, &isOnWillScrollCallBack]( + Dimension offset, ScrollState state, ScrollSource source) { + willScrollOffset = offset; + willScrollState = state; + isOnWillScrollCallBack = true; + ScrollFrameResult result; + result.offset = offset; + return result; + }; + + eventHub_->SetOnWillScroll(std::move(onWillScroll)); + pattern_->ScrollTo(ITEM_HEIGHT * 5); + EXPECT_TRUE(isOnWillScrollCallBack); +} } // namespace OHOS::Ace::NG -- Gitee From a35bbbcbed5b772be98a2add3ea1b3cec19a38fc Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 11:39:50 +0800 Subject: [PATCH 2/6] fix reverse layout and illegal template Signed-off-by: Tianer Zhou Change-Id: Id3262a50fe786d86880871f7c83d085e50125fc2 --- .../sliding_window/water_flow_layout_sw.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp index cfbbb41f275..a6a6426349a 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp @@ -23,8 +23,8 @@ #include "core/components_ng/base/frame_node.h" #include "core/components_ng/layout/layout_wrapper.h" #include "core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h" -#include "core/components_ng/pattern/waterflow/water_flow_layout_property.h" #include "core/components_ng/pattern/waterflow/layout/water_flow_layout_utils.h" +#include "core/components_ng/pattern/waterflow/water_flow_layout_property.h" #include "core/components_ng/property/measure_utils.h" #include "core/components_ng/property/templates_parser.h" @@ -82,10 +82,15 @@ void WaterFlowLayoutSW::Layout(LayoutWrapper* wrapper) continue; } auto childNode = child->GetGeometryNode(); + bool vertical = axis_ == Axis::VERTICAL; + auto offset = vertical ? OffsetF { crossPos, mainPos } : OffsetF { mainPos, crossPos }; if (reverse) { - mainPos = mainLen_ - item.mainSize - mainPos; + if (vertical) { + offset.SetY(mainLen_ - item.mainSize - mainPos); + } else { + offset.SetX(mainLen_ - item.mainSize - mainPos); + } } - auto offset = axis_ == Axis::VERTICAL ? OffsetF { crossPos, mainPos } : OffsetF { mainPos, crossPos }; childNode->SetMarginFrameOffset(offset + paddingOffset); if (child->CheckNeedForceMeasureAndLayout()) { @@ -126,6 +131,9 @@ void WaterFlowLayoutSW::Init(const SizeF& frameSize) } else { cross = ParseTemplateArgs(WaterFlowLayoutUtils::PreParseArgs(rowsTemplate), crossSize, crossGap_, itemCnt_); } + if (cross.first.empty()) { + cross.first = { crossSize }; + } if (cross.second) { crossGap_ = 0.0f; } @@ -488,7 +496,7 @@ void WaterFlowLayoutSW::AdjustOverScroll() ApplyDelta(-minStart); } else if (info_->EndIndex() == itemCnt_ - 1 && LessNotEqual(maxEnd, mainLen_)) { float delta = mainLen_ - maxEnd; - if (startIdx == 0) { + if (startIdx == 0) { delta = std::min(-minStart, delta); } ApplyDelta(delta); -- Gitee From 749cc305ebbe3c09a807da7ef4835d57595774a9 Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 11:40:21 +0800 Subject: [PATCH 3/6] fix check misalignment Signed-off-by: Tianer Zhou Change-Id: I2c2dfca8f2e0c4f336be9227b591e944ce078c16 --- .../water_flow_layout_info_sw.cpp | 19 ++++++---- .../pattern/waterflow/water_flow_pattern.cpp | 35 ++++++++++--------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp index 431975904d6..1cb20b183bc 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp @@ -22,11 +22,19 @@ namespace OHOS::Ace::NG { void WaterFlowLayoutInfoSW::Sync(int32_t itemCnt, float mainSize, float mainGap) { + if (lanes_.empty()) { + return; + } startIndex_ = StartIndex(); endIndex_ = EndIndex(); - if (startIndex_ <= endIndex_) { - storedOffset_ = lanes_[idxToLane_.at(startIndex_)].startPos; + if (startIndex_ > endIndex_) { + return; + } + if (!idxToLane_.count(startIndex_) || lanes_.size() <= idxToLane_.at(startIndex_)) { + return; } + storedOffset_ = lanes_[idxToLane_.at(startIndex_)].startPos; + delta_ = 0.0f; lastMainSize_ = mainSize; mainGap_ = mainGap; @@ -361,12 +369,11 @@ bool WaterFlowLayoutInfoSW::IsMisaligned() const if (lanes_.empty()) { return false; } - if (!itemStart_ || !NearZero(StartPos())) { + if (StartIndex() > 0) { return false; } - bool laneNotAligned = std::any_of(lanes_.begin(), lanes_.end(), [](const auto& lane) { - return !NearZero(lane.startPos); - }); + bool laneNotAligned = std::any_of( + lanes_.begin(), lanes_.end(), [this](const auto& lane) { return !NearEqual(lane.startPos, StartPos()); }); return laneNotAligned || lanes_[0].items_.front().idx != 0; } } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp index 745b8d86c20..a381046c206 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp @@ -195,6 +195,22 @@ void WaterFlowPattern::TriggerModifyDone() OnModifyDone(); } +namespace { +// check if layout is misaligned after a scroll event +bool CheckMisalignment(const RefPtr& info) +{ + if (info->Mode() != WaterFlowLayoutMode::SLIDING_WINDOW) { + return false; + } + auto infoSW = AceType::DynamicCast(info); + if (infoSW->IsMisaligned()) { + info->Reset(); + return true; + } + return false; +} +} // namespace + bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) { if (config.skipMeasure && config.skipLayout) { @@ -249,6 +265,9 @@ bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dir isInitialized_ = true; + if (layoutInfo_->startIndex_ == 0 && CheckMisalignment(layoutInfo_)) { + MarkDirtyNodeSelf(); + } return NeedRender(); } @@ -539,22 +558,6 @@ void WaterFlowPattern::MarkDirtyNodeSelf() host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); } -namespace { -// check if layout is misaligned after a scroll event -void CheckMisalignment(const RefPtr& info) -{ - if (info->Mode() != WaterFlowLayoutMode::SLIDING_WINDOW) { - return; - } - auto infoSW = AceType::DynamicCast(info); - if (infoSW->IsMisaligned()) { - infoSW->ResetBeforeJump(0.0f); - info->jumpIndex_ = 0; - info->align_ = ScrollAlign::START; - } -} -} // namespace - void WaterFlowPattern::OnScrollEndCallback() { scrollStop_ = true; -- Gitee From 99902e9c86ae47ed488f38e37619b3f2af14b804 Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 11:40:25 +0800 Subject: [PATCH 4/6] add tests Signed-off-by: Tianer Zhou Change-Id: I75dd93f597cf6c7a94595ab3a1ec227eae39cfb8 --- .../waterflow/water_flow_sw_layout_test.cpp | 10 ++-- .../pattern/waterflow/water_flow_test_ng.cpp | 52 ++++++++++++++++--- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp index 3adb21e1049..1ee390686f0 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp @@ -318,12 +318,14 @@ HWTEST_F(WaterFlowSWTest, Misaligned001, TestSize.Level1) FlushLayoutTask(frameNode_); UpdateCurrentOffset(Infinity()); - EXPECT_TRUE(info_->IsMisaligned()); + EXPECT_EQ(info_->startIndex_, 0); EXPECT_EQ(GetChildY(frameNode_, 1), 100.0f); EXPECT_EQ(GetChildX(frameNode_, 1), 240.0f); - pattern_->OnScrollEndCallback(); + EXPECT_EQ(info_->jumpIndex_, 0); FlushLayoutTask(frameNode_); EXPECT_FALSE(info_->IsMisaligned()); + EXPECT_EQ(GetChildY(frameNode_, 1), 0.0f); + EXPECT_EQ(GetChildX(frameNode_, 1), 0.0f); EXPECT_EQ(info_->lanes_[0].startPos, 0.0f); EXPECT_EQ(info_->lanes_[0].items_.front().idx, 0); } @@ -350,7 +352,7 @@ HWTEST_F(WaterFlowSWTest, PositionController100, TestSize.Level1) pattern_->AnimateTo(1.5, 1.f, Curves::LINEAR, false, false); EXPECT_TRUE(pattern_->isAnimationStop_); - /** + /** * @tc.steps: step8. test event * @tc.expected: return the scroll event is ture. */ @@ -366,7 +368,7 @@ HWTEST_F(WaterFlowSWTest, PositionController100, TestSize.Level1) result.offset = offset; return result; }; - + eventHub_->SetOnWillScroll(std::move(onWillScroll)); pattern_->ScrollTo(ITEM_HEIGHT * 5); EXPECT_FALSE(isOnWillScrollCallBack); diff --git a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp index 6cc316d0d9b..408da38038d 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp @@ -788,7 +788,7 @@ HWTEST_F(WaterFlowTestNg, PositionController005, TestSize.Level1) CreateItem(TOTAL_LINE_NUMBER * 2); }); auto controller = pattern_->positionController_; - + /** * @tc.steps: step2. Scroll to the left edge * expected: Return fixed verify @@ -849,7 +849,7 @@ HWTEST_F(WaterFlowTestNg, PositionController005, TestSize.Level1) } EXPECT_TRUE(pattern_->IsAtTop()); - /** + /** * @tc.steps: step8. Test ScrollBy */ controller->ScrollBy(0, ITEM_HEIGHT, true); @@ -877,7 +877,7 @@ HWTEST_F(WaterFlowTestNg, PositionController006, TestSize.Level1) CreateItem(TOTAL_LINE_NUMBER * 2); }); auto controller = pattern_->positionController_; - + /** * @tc.steps: step2. Scroll to the left edge * expected: Return fixed verify @@ -959,7 +959,7 @@ HWTEST_F(WaterFlowTestNg, PositionController007, TestSize.Level1) CreateItem(TOTAL_LINE_NUMBER * 2); }); auto controller = pattern_->positionController_; - + /** * @tc.steps: step2. Scroll to the left edge * expected: Return fixed verify @@ -1052,7 +1052,7 @@ HWTEST_F(WaterFlowTestNg, PositionController008, TestSize.Level1) CreateItem(TOTAL_LINE_NUMBER * 2); }); auto controller = pattern_->positionController_; - + /** * @tc.steps: step2. Scroll to the left edge * expected: Return fixed verify @@ -1143,7 +1143,7 @@ HWTEST_F(WaterFlowTestNg, PositionController009, TestSize.Level1) CreateItem(TOTAL_LINE_NUMBER * 2); }); auto controller = pattern_->positionController_; - + /** * @tc.steps: step2. Scroll to the left edge * expected: Return fixed verify @@ -1684,4 +1684,44 @@ HWTEST_F(WaterFlowTestNg, MeasureForAnimation001, TestSize.Level1) auto crossIndex = pattern_->layoutInfo_->GetCrossIndex(10); EXPECT_FALSE(IsEqual(crossIndex, -1)); } + +/** + * @tc.name: Illegal001 + * @tc.desc: Test illegal columns template + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowTestNg, Illegal001, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("a"); + model.SetFooter(GetDefaultHeaderBuilder()); + CreateItem(20); + }); + EXPECT_EQ(GetChildWidth(frameNode_, 1), WATERFLOW_WIDTH); + EXPECT_EQ(GetChildWidth(frameNode_, 2), WATERFLOW_WIDTH); + EXPECT_EQ(GetChildX(frameNode_, 1), 0.0f); + EXPECT_EQ(pattern_->layoutInfo_->startIndex_, 0); + EXPECT_EQ(pattern_->layoutInfo_->endIndex_, 5); +} + +/** + * @tc.name: Reverse001 + * @tc.desc: Test reverse layout + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowTestNg, Reverse001, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("a"); + CreateItem(20); + }); + layoutProperty_->UpdateWaterflowDirection(FlexDirection::COLUMN_REVERSE); + FlushLayoutTask(frameNode_); + EXPECT_EQ(GetChildY(frameNode_, 0), 700.0f); + EXPECT_EQ(GetChildY(frameNode_, 1), 500.0f); + EXPECT_EQ(GetChildY(frameNode_, 2), 400.0f); + EXPECT_EQ(GetChildY(frameNode_, 3), 200.0f); + EXPECT_EQ(GetChildY(frameNode_, 4), 100.0f); + EXPECT_EQ(GetChildY(frameNode_, 5), -100.0f); +} } // namespace OHOS::Ace::NG -- Gitee From 8819053592d360474a2e1e9d4e98a2c13764644f Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 14:35:02 +0800 Subject: [PATCH 5/6] review fixes and fix overScroll delta Signed-off-by: Tianer Zhou Change-Id: I203553f452dfe58c3ffb14a1cc18be8cdd5249b8 --- .../water_flow_layout_info_sw.cpp | 17 +++++---- .../water_flow_layout_info_sw.h | 11 ++---- .../sliding_window/water_flow_layout_sw.cpp | 17 ++++----- .../layout/top_down/water_flow_layout_info.h | 5 +++ .../layout/water_flow_layout_info_base.h | 16 ++++++++- .../waterflow/water_flow_layout_property.cpp | 3 +- .../pattern/waterflow/water_flow_pattern.cpp | 32 ++++++++--------- .../pattern/waterflow/water_flow_pattern.h | 3 ++ .../waterflow/water_flow_sw_layout_test.cpp | 35 +++++++++++++++++++ .../pattern/waterflow/water_flow_test_ng.cpp | 12 +++++++ .../pattern/waterflow/water_flow_test_ng.h | 1 + 11 files changed, 107 insertions(+), 45 deletions(-) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp index 1cb20b183bc..297f66d5a14 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp @@ -42,13 +42,18 @@ void WaterFlowLayoutInfoSW::Sync(int32_t itemCnt, float mainSize, float mainGap) endPos_ = EndPos(); itemStart_ = (startIndex_ == 0 && NonNegative(startPos_)) || GreatOrEqual(startPos_, mainSize); - itemEnd_ = endIndex_ == itemCnt - 1 || (itemCnt > 0 && NonPositive(endPos_)); - if (!itemEnd_) { - footerHeight_ = 0.0f; + itemEnd_ = endIndex_ == itemCnt - 1; + if (footerIndex_ == 0) { + itemEnd_ &= LessOrEqual(endPos_, mainSize); } + itemEnd_ |= itemCnt > 0 && NonPositive(endPos_); // extreme overScroll case offsetEnd_ = itemEnd_ && LessOrEqual(endPos_ + footerHeight_, mainSize); maxHeight_ = std::max(endPos_ - startPos_ + footerHeight_, maxHeight_); + if (!itemEnd_) { + footerHeight_ = 0.0f; + } + synced_ = true; } @@ -93,9 +98,9 @@ bool WaterFlowLayoutInfoSW::OutOfBounds() const if (itemStart_ && Positive(lanes_[0].startPos)) { return true; } - if (itemEnd_) { + if (offsetEnd_) { return std::all_of(lanes_.begin(), lanes_.end(), - [mainSize = lastMainSize_](const Lane& lane) { return LessNotEqual(lane.endPos, mainSize); }); + [this](const Lane& lane) { return LessNotEqual(lane.endPos + footerHeight_, lastMainSize_); }); } return false; } @@ -122,7 +127,7 @@ OverScrollOffset WaterFlowLayoutInfoSW::GetOverScrolledDelta(float delta) const return res; } float disToBot = EndPos() + footerHeight_ - lastMainSize_; - if (!itemEnd_) { + if (!offsetEnd_) { res.end = std::min(0.0f, disToBot + delta); } else if (Negative(delta)) { res.end = delta; diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h index b1b87bc3b34..e04dd2683ef 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h @@ -88,6 +88,8 @@ public: void Reset() override; + bool IsMisaligned() const override; + /** * @brief reset layout data before performing a jump. * @@ -125,15 +127,6 @@ public: */ float DistanceToBottom(int32_t item, float mainSize, float mainGap) const; - /** - * @brief Check if the layout is misaligned. - * - * If we jump and scroll back to top, the staring items might not be aligned with the top boundary. - * @return true if 1. any lane misaligned with top boundary. - * 2. the first item is not in the first lane. - */ - bool IsMisaligned() const; - int32_t StartIndex() const; int32_t EndIndex() const; inline bool ItemInView(int32_t idx) const diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp index a6a6426349a..41691162929 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp @@ -82,14 +82,10 @@ void WaterFlowLayoutSW::Layout(LayoutWrapper* wrapper) continue; } auto childNode = child->GetGeometryNode(); - bool vertical = axis_ == Axis::VERTICAL; - auto offset = vertical ? OffsetF { crossPos, mainPos } : OffsetF { mainPos, crossPos }; - if (reverse) { - if (vertical) { - offset.SetY(mainLen_ - item.mainSize - mainPos); - } else { - offset.SetX(mainLen_ - item.mainSize - mainPos); - } + auto offset = + reverse ? OffsetF { crossPos, mainLen_ - item.mainSize - mainPos } : OffsetF { crossPos, mainPos }; + if (axis_ != Axis::VERTICAL) { + offset = OffsetF { offset.GetY(), offset.GetX() }; } childNode->SetMarginFrameOffset(offset + paddingOffset); @@ -514,12 +510,11 @@ float WaterFlowLayoutSW::MeasureChild(const RefPtr& pro void WaterFlowLayoutSW::LayoutFooter(const OffsetF& paddingOffset, bool reverse) { - float endPos = info_->EndPos(); - if (info_->footerIndex_ != 0 || GreatOrEqual(endPos, mainLen_)) { + float mainPos = info_->EndPos(); + if (info_->footerIndex_ != 0 || GreatOrEqual(mainPos, mainLen_)) { return; } auto footer = wrapper_->GetOrCreateChildByIndex(0); - float mainPos = endPos + mainGap_; if (reverse) { mainPos = mainLen_ - info_->footerHeight_ - mainPos; } diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h index 13ec41d6094..d72e7c46137 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h +++ b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h @@ -113,6 +113,11 @@ public: float JumpToTargetAlign(const std::pair& item) const; void JumpTo(const std::pair& item); + bool IsMisaligned() const override + { + return false; + } + /** * @brief Init data structures based on new WaterFlow Sections. * diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h index ee280cc8184..934b76e3009 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h +++ b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h @@ -123,6 +123,15 @@ public: // for compatibility virtual void UpdateStartIndex() {}; + /** + * @brief Check if the layout is misaligned. + * + * If we jump and scroll back to top, the staring items might not be aligned with the top boundary. + * @return true if 1. any lane misaligned with top boundary. + * 2. the first item is not in the first lane. + */ + virtual bool IsMisaligned() const = 0; + virtual void InitSegments(const std::vector& sections, int32_t start) {} /** * @brief Get the Segment index of a FlowItem @@ -133,7 +142,12 @@ public: int32_t GetSegment(int32_t itemIdx) const; bool itemStart_ = false; - bool itemEnd_ = false; // last item is partially in viewport + + /** + * @brief last item is partially in viewport. + * With footer, footer should be considered the last item. + */ + bool itemEnd_ = false; bool offsetEnd_ = false; // last item's bottom is in viewport Axis axis_ = Axis::VERTICAL; diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp index b9281624faf..e0e80c51f3b 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp @@ -101,7 +101,8 @@ inline bool UseSegmentedLayout(const RefPtr& host) return SystemProperties::WaterFlowUseSegmentedLayout() || (pattern && pattern->GetSections()); } -inline bool SWLayout(const RefPtr& host) { +inline bool SWLayout(const RefPtr& host) +{ CHECK_NULL_RETURN(host, false); auto pattern = host->GetPattern(); return pattern && pattern->GetLayoutMode() == WaterFlowLayoutMode::SLIDING_WINDOW; diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp index a381046c206..a5a60d6f033 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.cpp @@ -199,11 +199,7 @@ namespace { // check if layout is misaligned after a scroll event bool CheckMisalignment(const RefPtr& info) { - if (info->Mode() != WaterFlowLayoutMode::SLIDING_WINDOW) { - return false; - } - auto infoSW = AceType::DynamicCast(info); - if (infoSW->IsMisaligned()) { + if (info->IsMisaligned()) { info->Reset(); return true; } @@ -211,22 +207,16 @@ bool CheckMisalignment(const RefPtr& info) } } // namespace -bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) +void WaterFlowPattern::TriggerPostLayoutEvents() { - if (config.skipMeasure && config.skipLayout) { - return false; - } - auto layoutAlgorithmWrapper = dirty->GetLayoutAlgorithm(); - CHECK_NULL_RETURN(layoutAlgorithmWrapper, false); - auto layoutAlgorithm = DynamicCast(layoutAlgorithmWrapper->GetLayoutAlgorithm()); - CHECK_NULL_RETURN(layoutAlgorithm, false); auto host = GetHost(); - CHECK_NULL_RETURN(host, false); + CHECK_NULL_VOID(host); auto eventHub = host->GetEventHub(); - CHECK_NULL_RETURN(eventHub, false); - auto onScroll = eventHub->GetOnScroll(); + CHECK_NULL_VOID(eventHub); float delta = layoutInfo_->GetDelta(prevOffset_); PrintOffsetLog(AceLogTag::ACE_WATERFLOW, host->GetId(), delta); + + auto onScroll = eventHub->GetOnScroll(); if (onScroll) { FireOnScroll(delta, onScroll); } @@ -251,6 +241,14 @@ bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dir onReachEnd(); } OnScrollStop(eventHub->GetOnScrollStop()); +} + +bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) +{ + if (config.skipMeasure && config.skipLayout) { + return false; + } + TriggerPostLayoutEvents(); if (targetIndex_.has_value()) { ScrollToTargetIndex(targetIndex_.value()); @@ -265,7 +263,7 @@ bool WaterFlowPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dir isInitialized_ = true; - if (layoutInfo_->startIndex_ == 0 && CheckMisalignment(layoutInfo_)) { + if (layoutInfo_->itemStart_ && CheckMisalignment(layoutInfo_)) { MarkDirtyNodeSelf(); } return NeedRender(); diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h index d40b355f33d..10bb09b59a1 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h @@ -160,6 +160,9 @@ private: bool OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) override; void CheckScrollable(); bool IsOutOfBoundary(bool useCurrentDelta = true) override; + + void TriggerPostLayoutEvents(); + void SetEdgeEffectCallback(const RefPtr& scrollEffect) override; SizeF GetContentSize() const; void MarkDirtyNodeSelf(); diff --git a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp index 1ee390686f0..3bb256aaa77 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp @@ -373,4 +373,39 @@ HWTEST_F(WaterFlowSWTest, PositionController100, TestSize.Level1) pattern_->ScrollTo(ITEM_HEIGHT * 5); EXPECT_FALSE(isOnWillScrollCallBack); } + +/** + * @tc.name: ScrollToEdge002 + * @tc.desc: ScrollToEdge and check overScroll + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowSWTest, ScrollToEdge002, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetFooter(GetDefaultHeaderBuilder()); + model.SetColumnsTemplate("1fr 1fr 1fr"); + model.SetRowsGap(Dimension(5.0f)); + CreateRandomItem(100); + }); + pattern_->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false); + FlushLayoutTask(frameNode_); + auto info = pattern_->layoutInfo_; + EXPECT_EQ(info->endIndex_, 99); + EXPECT_EQ(GetChildOffset(frameNode_, info->footerIndex_), OffsetF(0.0f, 750.0f)); + EXPECT_EQ(info_->EndPos(), 750.0f); + EXPECT_FALSE(info->OutOfBounds()); + EXPECT_EQ(info->GetOverScrolledDelta(20.0f).end, 0.0f); + EXPECT_EQ(info->GetOverScrolledDelta(-10.0f).end, -10.0f); + + UpdateCurrentOffset(30.0f); + EXPECT_EQ(info->GetOverScrolledDelta(-20.0f).end, 0.0f); + EXPECT_EQ(info->GetOverScrolledDelta(20.0f).end, 0.0f); + + UpdateCurrentOffset(20.0f); + EXPECT_EQ(info->GetOverScrolledDelta(-20.0f).end, 0.0f); + EXPECT_EQ(info->GetOverScrolledDelta(20.0f).end, 0.0f); + + UpdateCurrentOffset(5.0f); + EXPECT_FALSE(info->itemEnd_); +} } // namespace OHOS::Ace::NG diff --git a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp index 408da38038d..1c4b47eea6b 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -141,6 +142,17 @@ void WaterFlowTestNg::CreateItem(int32_t number) } } +void WaterFlowTestNg::CreateRandomItem(int32_t number) +{ + for (int32_t i = 0; i < number; i++) { + WaterFlowItemModelNG waterFlowItemModel; + waterFlowItemModel.Create(); + ViewAbstract::SetWidth(CalcLength(FILL_LENGTH)); + ViewAbstract::SetHeight(CalcLength(std::rand() % 200 + 50.0f)); + ViewStackProcessor::GetInstance()->Pop(); + } +} + void WaterFlowTestNg::AddItems(int32_t number) { for (int i = 0; i < number; ++i) { diff --git a/test/unittest/core/pattern/waterflow/water_flow_test_ng.h b/test/unittest/core/pattern/waterflow/water_flow_test_ng.h index a9d7a62f8a6..817ae576cf2 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.h +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.h @@ -57,6 +57,7 @@ protected: void Create(const std::function& callback = nullptr, bool flushLayout = true); void CreateWithItem(const std::function& callback = nullptr); static void CreateItem(int32_t number = 10); + static void CreateRandomItem(int32_t number); static void CreateItemWithHeight(float height); void UpdateCurrentOffset(float offset, int32_t source = SCROLL_FROM_UPDATE); void MouseSelect(Offset start, Offset end); -- Gitee From 08f71328db5b589fe7a489ef59c77b348343d1c1 Mon Sep 17 00:00:00 2001 From: Tianer Zhou Date: Sat, 25 May 2024 17:10:21 +0800 Subject: [PATCH 6/6] fix extreme overScroll Signed-off-by: Tianer Zhou Change-Id: I92a9b5735c427cc612a99472a75199cffcc33575 --- .../water_flow_layout_info_sw.cpp | 3 +- .../sliding_window/water_flow_layout_sw.cpp | 4 +- .../waterflow/water_flow_sw_layout_test.cpp | 79 ++++++++++++++++--- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp index 297f66d5a14..214382d77f0 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.cpp @@ -41,12 +41,11 @@ void WaterFlowLayoutInfoSW::Sync(int32_t itemCnt, float mainSize, float mainGap) startPos_ = StartPos(); endPos_ = EndPos(); - itemStart_ = (startIndex_ == 0 && NonNegative(startPos_)) || GreatOrEqual(startPos_, mainSize); + itemStart_ = startIndex_ == 0 && NonNegative(startPos_); itemEnd_ = endIndex_ == itemCnt - 1; if (footerIndex_ == 0) { itemEnd_ &= LessOrEqual(endPos_, mainSize); } - itemEnd_ |= itemCnt > 0 && NonPositive(endPos_); // extreme overScroll case offsetEnd_ = itemEnd_ && LessOrEqual(endPos_ + footerHeight_, mainSize); maxHeight_ = std::max(endPos_ - startPos_ + footerHeight_, maxHeight_); diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp index 41691162929..9678a253d11 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp @@ -351,7 +351,7 @@ void WaterFlowLayoutSW::RecoverFront(float viewportBound, int32_t& idx, int32_t void WaterFlowLayoutSW::ClearBack(float bound) { int32_t startIdx = info_->StartIndex(); - for (int32_t i = info_->EndIndex(); i >= startIdx; --i) { + for (int32_t i = info_->EndIndex(); i > startIdx; --i) { size_t laneIdx = info_->idxToLane_.at(i); auto& lane = info_->lanes_[laneIdx]; float itemStartPos = lane.endPos - lane.items_.back().mainSize; @@ -366,7 +366,7 @@ void WaterFlowLayoutSW::ClearBack(float bound) void WaterFlowLayoutSW::ClearFront() { int32_t endIdx = info_->EndIndex(); - for (int32_t i = info_->StartIndex(); i <= endIdx; ++i) { + for (int32_t i = info_->StartIndex(); i < endIdx; ++i) { size_t laneIdx = info_->idxToLane_.at(i); auto& lane = info_->lanes_[laneIdx]; float itemEndPos = lane.startPos + lane.items_.front().mainSize; diff --git a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp index 3bb256aaa77..9356151d7ed 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_sw_layout_test.cpp @@ -242,18 +242,16 @@ HWTEST_F(WaterFlowSWTest, OverScroll001, TestSize.Level1) pattern_->SetAnimateCanOverScroll(true); UpdateCurrentOffset(30000.0f); const float startPos = info_->StartPos(); - EXPECT_TRUE(info_->startIndex_ > info_->endIndex_); EXPECT_GT(info_->StartPos(), 2000.0f); - EXPECT_TRUE(info_->lanes_[0].items_.empty()); - EXPECT_TRUE(info_->lanes_[1].items_.empty()); + EXPECT_EQ(info_->startIndex_, 0); + EXPECT_EQ(info_->endIndex_, 0); info_->delta_ = -50.0f; frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); FlushLayoutTask(frameNode_); EXPECT_EQ(info_->StartPos(), startPos - 50.0f); - EXPECT_TRUE(info_->startIndex_ > info_->endIndex_); - EXPECT_TRUE(info_->lanes_[0].items_.empty()); - EXPECT_TRUE(info_->lanes_[1].items_.empty()); + EXPECT_EQ(info_->startIndex_, 0); + EXPECT_EQ(info_->endIndex_, 0); UpdateCurrentOffset(-35000.0f); EXPECT_EQ(info_->startIndex_, 11); @@ -280,19 +278,24 @@ HWTEST_F(WaterFlowSWTest, OverScroll002, TestSize.Level1) FlushLayoutTask(frameNode_); UpdateCurrentOffset(-30000.0f); - EXPECT_TRUE(info_->startIndex_ > info_->endIndex_); - EXPECT_TRUE(info_->lanes_[0].items_.empty()); - EXPECT_TRUE(info_->lanes_[1].items_.empty()); const float endPos = info_->EndPos(); EXPECT_LT(info_->EndPos(), -2000.0f); + EXPECT_EQ(info_->startIndex_, 49); + EXPECT_EQ(info_->endIndex_, 49); info_->delta_ = 30.0f; frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); FlushLayoutTask(frameNode_); EXPECT_EQ(info_->EndPos(), endPos + 30.0f); - EXPECT_TRUE(info_->startIndex_ > info_->endIndex_); - EXPECT_TRUE(info_->lanes_[0].items_.empty()); - EXPECT_TRUE(info_->lanes_[1].items_.empty()); + EXPECT_EQ(info_->startIndex_, 49); + EXPECT_EQ(info_->endIndex_, 49); + + info_->delta_ = -30.0f; + frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); + FlushLayoutTask(frameNode_); + EXPECT_EQ(info_->EndPos(), endPos); + EXPECT_EQ(info_->startIndex_, 49); + EXPECT_EQ(info_->endIndex_, 49); UpdateCurrentOffset(35000.0f); EXPECT_EQ(info_->startIndex_, 28); @@ -301,6 +304,58 @@ HWTEST_F(WaterFlowSWTest, OverScroll002, TestSize.Level1) EXPECT_GT(info_->EndPos(), 800.0f); } +/** + * @tc.name: OverScroll003 + * @tc.desc: Test overScroll past limits incrementally + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowSWTest, OverScroll003, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("1fr 1fr"); + model.SetEdgeEffect(EdgeEffect::SPRING, true); + CreateRandomItem(50); + }); + pattern_->SetAnimateCanOverScroll(true); + for (int i = 1; i <= 10; ++i) { + info_->delta_ = 100.0f; + frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); + FlushLayoutTask(frameNode_); + EXPECT_EQ(info_->StartPos(), 100.0f * i); + EXPECT_TRUE(info_->itemStart_); + } + EXPECT_EQ(info_->startIndex_, 0); + EXPECT_EQ(info_->endIndex_, 0); + EXPECT_EQ(info_->TopFinalPos(), -1000.0f); +} + +/** + * @tc.name: OverScroll004 + * @tc.desc: Test overScroll past limits incrementally + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowSWTest, OverScroll004, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("1fr 1fr"); + model.SetEdgeEffect(EdgeEffect::SPRING, true); + CreateRandomItem(50); + }); + pattern_->SetAnimateCanOverScroll(true); + pattern_->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false); + FlushLayoutTask(frameNode_); + for (int i = 1; i <= 10; ++i) { + info_->delta_ = -100.0f; + frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF); + FlushLayoutTask(frameNode_); + EXPECT_EQ(info_->EndPos(), -100.0f * i + WATERFLOW_HEIGHT); + EXPECT_TRUE(info_->offsetEnd_); + } + EXPECT_EQ(info_->startIndex_, 49); + EXPECT_EQ(info_->endIndex_, 49); + EXPECT_EQ(info_->BottomFinalPos(WATERFLOW_HEIGHT), 1000.0f); +} + /** * @tc.name: Misaligned001 * @tc.desc: Test misalignment and adjustment -- Gitee