Swiper: ignoreBlank bugfix

Signed-off-by: huzeqi <huzeqi@huawei.com>
Change-Id: Iced28a93e5b8c3cb26319ad0a1f3169a9d45be88
This commit is contained in:
huzeqi 2024-07-30 17:31:01 +08:00
parent b2fa2d3c12
commit 4810956a76
5 changed files with 97 additions and 65 deletions

View File

@ -915,18 +915,13 @@ void SwiperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
auto padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
MinusPaddingToSize(padding, size);
auto paddingOffset = padding.Offset();
auto hostNode = layoutWrapper->GetHostNode();
CHECK_NULL_VOID(hostNode);
auto swiperPattern = hostNode->GetPattern<SwiperPattern>();
CHECK_NULL_VOID(swiperPattern);
auto ignoreBlankOffset = swiperPattern->IgnoreBlankOffset(true);
// layout items.
std::set<int32_t> layoutIndexSet;
for (auto& pos : itemPosition_) {
layoutIndexSet.insert(GetLoopIndex(pos.first));
pos.second.startPos -= currentOffset_ + ignoreBlankOffset;
pos.second.endPos -= currentOffset_ + ignoreBlankOffset;
pos.second.startPos -= currentOffset_;
pos.second.endPos -= currentOffset_;
LayoutItem(layoutWrapper, axis, paddingOffset, pos);
}
for (auto& pos : itemPositionInAnimation_) {
@ -975,6 +970,9 @@ void SwiperLayoutAlgorithm::LayoutSwiperIndicator(
void SwiperLayoutAlgorithm::LayoutItem(LayoutWrapper* layoutWrapper, Axis axis, OffsetF offset,
std::pair<int32_t, SwiperItemInfo> pos)
{
pos.second.startPos += ignoreBlankOffset_;
pos.second.endPos += ignoreBlankOffset_;
auto layoutIndex = GetLoopIndex(pos.first);
if (swipeByGroup_ && layoutIndex >= realTotalCount_) {
return;

View File

@ -304,6 +304,11 @@ public:
nextMarginIgnoreBlank_ = nextMarginIgnoreBlank;
}
void SetIgnoreBlankOffset(float ignoreBlankOffset)
{
ignoreBlankOffset_ = ignoreBlankOffset;
}
private:
void LayoutSwiperIndicator(
LayoutWrapper* layoutWrapper, const RefPtr<SwiperLayoutProperty>& swiperLayoutProperty,
@ -388,6 +393,7 @@ private:
bool isMeasureOneMoreItem_ = false;
bool isFrameAnimation_ = false;
bool nextMarginIgnoreBlank_ = false;
float ignoreBlankOffset_ = 0.0f;
std::set<int32_t> measuredItems_;
std::set<int32_t> activeItems_;
std::set<int32_t> cachedItems_;

View File

@ -183,6 +183,7 @@ RefPtr<LayoutAlgorithm> SwiperPattern::CreateLayoutAlgorithm()
algo->SetIsCaptureReverse(isCaptureReverse_);
algo->SetCachedCount(GetCachedCount());
algo->SetNextMarginIgnoreBlank(nextMarginIgnoreBlank_);
algo->SetIgnoreBlankOffset(ignoreBlankOffset_);
return algo;
}
@ -513,6 +514,7 @@ void SwiperPattern::BeforeCreateLayoutWrapper()
currentIndex_ = GetLoopIndex(currentIndex_);
props->UpdateIndexWithoutMeasure(currentIndex_);
}
UpdateIgnoreBlankOffsetWithIndex();
}
void SwiperPattern::UpdateTargetCapture(bool forceUpdate)
@ -929,10 +931,6 @@ bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty,
UpdateTargetCapture(algo->GetIsNeedUpdateCapture());
}
if (jumpIndex_) {
ignoreBlankSpringOffset_ = IgnoreBlankOffset(true);
}
if (!targetIndex_) {
if (isUserFinish_) {
SetIndicatorJumpIndex(jumpIndex_);
@ -981,8 +979,7 @@ bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty,
auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
auto iter = itemPosition_.find(targetIndexValue);
if (iter != itemPosition_.end()) {
ignoreBlankSpringOffset_ = IgnoreBlankOffset(false);
float targetPos = iter->second.startPos + IgnoreBlankOffset(false);
float targetPos = iter->second.startPos;
auto context = GetContext();
auto props = GetLayoutProperty<SwiperLayoutProperty>();
bool isNeedForwardTranslate = false;
@ -1053,34 +1050,71 @@ bool SwiperPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty,
return GetEdgeEffect() == EdgeEffect::FADE || paddingProperty != nullptr;
}
float SwiperPattern::IgnoreBlankOffset(bool isJump)
float SwiperPattern::AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const
{
float result = 0.0f;
if (!isJump && targetIndex_) {
auto targetIndexValue = IsLoop() ? targetIndex_.value() : GetLoopIndex(targetIndex_.value());
if (!IsLoop()) {
if (targetIndexValue == 0 && prevMarginIgnoreBlank_) {
result += GetPrevMargin() + GetItemSpace();
}
if (targetIndexValue >= (TotalCount() - GetDisplayCount()) && nextMarginIgnoreBlank_) {
result -= GetNextMargin() + GetItemSpace();
}
if (isStartOverScroll && NonNegative(ignoreBlankOffset_)) {
return prevMarginIgnoreBlank_ ? GetPrevMargin() + ignoreBlankOffset_ : ignoreBlankOffset_;
}
if (!isStartOverScroll && NonPositive(ignoreBlankOffset_)) {
return nextMarginIgnoreBlank_ ? -GetNextMargin() + ignoreBlankOffset_ : ignoreBlankOffset_;
}
return 0.0f;
}
void SwiperPattern::UpdateIgnoreBlankOffsetWithIndex()
{
if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
return;
}
if (jumpIndex_.has_value()) {
if (prevMarginIgnoreBlank_ && jumpIndex_.value() == 0) {
ignoreBlankOffset_ = -GetPrevMargin();
} else if (nextMarginIgnoreBlank_ && jumpIndex_.value() >= (TotalCount() - GetDisplayCount())) {
ignoreBlankOffset_ = GetNextMargin();
} else {
ignoreBlankOffset_ = 0.0f;
}
return;
}
if (targetIndex_.has_value()) {
float ignoreBlankOffset = ignoreBlankOffset_;
if (prevMarginIgnoreBlank_ && targetIndex_.value() == 0) {
ignoreBlankOffset_ = -GetPrevMargin();
} else if (nextMarginIgnoreBlank_ && targetIndex_.value() >= (TotalCount() - GetDisplayCount())) {
ignoreBlankOffset_ = GetNextMargin();
} else {
ignoreBlankOffset_ = 0.0f;
}
if (NearEqual(ignoreBlankOffset_, ignoreBlankOffset)) {
return;
}
float adjustOffset = ignoreBlankOffset_ - ignoreBlankOffset;
for (auto& item : itemPosition_) {
item.second.startPos -= adjustOffset;
item.second.endPos -= adjustOffset;
}
}
}
if (jumpIndex_) {
auto targetIndexValue = IsLoop() ? jumpIndex_.value() : GetLoopIndex(jumpIndex_.value());
if (!IsLoop()) {
if (targetIndexValue == 0 && prevMarginIgnoreBlank_) {
result += GetPrevMargin() + GetItemSpace();
}
if (targetIndexValue >= (TotalCount() - GetDisplayCount()) && nextMarginIgnoreBlank_) {
result -= GetNextMargin() + GetItemSpace();
}
}
void SwiperPattern::UpdateIgnoreBlankOffsetWithDrag(bool overScrollDirection)
{
if (IsLoop() || !(prevMarginIgnoreBlank_ || nextMarginIgnoreBlank_)) {
return;
}
float ignoreBlankOffset = ignoreBlankOffset_;
if (prevMarginIgnoreBlank_ && overScrollDirection) {
ignoreBlankOffset_ = -GetPrevMargin();
} else if (nextMarginIgnoreBlank_ && !overScrollDirection) {
ignoreBlankOffset_ = GetNextMargin();
}
if (NearEqual(ignoreBlankOffset_, ignoreBlankOffset)) {
return;
}
float adjustOffset = ignoreBlankOffset_ - ignoreBlankOffset;
for (auto& item : itemPosition_) {
item.second.startPos -= adjustOffset;
item.second.endPos -= adjustOffset;
}
return result;
}
bool SwiperPattern::IsAutoLinear() const
@ -2324,20 +2358,17 @@ bool SwiperPattern::FadeOverScroll(float offset)
return false;
}
if (IsOutOfBoundary(fadeOffset_ + offset)) {
auto onlyUpdateFadeOffset = (itemPosition_.begin()->first == 0 && offset < 0.0f) ||
(itemPosition_.rbegin()->first == TotalCount() - 1 && offset > 0.0f);
if (!IsVisibleChildrenSizeLessThanSwiper() && !onlyUpdateFadeOffset) {
if (!IsVisibleChildrenSizeLessThanSwiper() && NearZero(fadeOffset_)) {
UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart(offset));
auto realOffset = IsOutOfStart(offset) ? -itemPosition_.begin()->second.startPos
: CalculateVisibleSize() - itemPosition_.rbegin()->second.endPos;
currentDelta_ = currentDelta_ - realOffset;
currentDelta_ -= realOffset;
offset -= realOffset;
HandleSwiperCustomAnimation(realOffset);
}
fadeOffset_ += offset;
auto host = GetHost();
CHECK_NULL_RETURN(host, false);
if (itemPosition_.begin()->first == 0 || itemPosition_.rbegin()->first == TotalCount() - 1) {
auto remainOffset = GetDistanceToEdge();
fadeOffset_ += (offset - remainOffset);
}
host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
MarkDirtyNodeSelf();
return true;
@ -2376,7 +2407,6 @@ void SwiperPattern::UpdateNextValidIndex()
void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset, std::optional<int32_t> nextIndex)
{
additionalOffset += ignoreBlankSpringOffset_;
additionalOffset = IsHorizontalAndRightToLeft() ? -additionalOffset : additionalOffset;
if (!indicatorId_.has_value()) {
return;
@ -2399,7 +2429,7 @@ void SwiperPattern::CheckMarkDirtyNodeForRenderIndicator(float additionalOffset,
currentFirstIndex_ = nextIndex.value_or(currentFirstIndex_);
UpdateNextValidIndex();
currentFirstIndex_ = GetLoopIndex(currentFirstIndex_);
CalculateGestureState(additionalOffset - ignoreBlankSpringOffset_, currentTurnPageRate, preFirstIndex);
CalculateGestureState(additionalOffset, currentTurnPageRate, preFirstIndex);
turnPageRate_ = (currentTurnPageRate == FLT_MAX ? turnPageRate_ : currentTurnPageRate);
touchBottomType_ = TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE;
CheckMarkForIndicatorBoundary();
@ -3449,6 +3479,7 @@ void SwiperPattern::CreateSpringProperty()
void SwiperPattern::PlaySpringAnimation(double dragVelocity)
{
UpdateIgnoreBlankOffsetWithDrag(IsOutOfStart());
if (springAnimationIsRunning_) {
return;
}
@ -3468,11 +3499,6 @@ void SwiperPattern::PlaySpringAnimation(double dragVelocity)
if (IsVisibleChildrenSizeLessThanSwiper()) {
delta = extentPair.Trailing();
}
if (LessNotEqual(currentIndexOffset_, 0.0f) && nextMarginIgnoreBlank_) {
delta += GetNextMargin() + GetItemSpace();
} else if (GreatNotEqual(currentIndexOffset_, 0.0f) && prevMarginIgnoreBlank_) {
delta -= GetPrevMargin() + GetItemSpace();
}
// spring curve: (velocity: 0.0, mass: 1.0, stiffness: 228.0, damping: 30.0)
auto springCurve = MakeRefPtr<SpringCurve>(0.0f, 1.0f, 228.0f, 30.0f);
AnimationOption option;
@ -3517,11 +3543,11 @@ bool SwiperPattern::IsOutOfBoundary(float mainOffset) const
return isOutOfStart || isOutOfEnd;
} else {
auto startPos = itemPosition_.begin()->second.startPos;
auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
startPos = NearZero(startPos, PX_EPSILON) ? 0.0 : startPos;
auto isOutOfStart = itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.0);
auto visibleWindowSize = CalculateVisibleSize();
auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
auto isOutOfEnd = itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
@ -3535,7 +3561,7 @@ bool SwiperPattern::IsOutOfStart(float mainOffset) const
return false;
}
auto startPos = itemPosition_.begin()->second.startPos;
auto startPos = itemPosition_.begin()->second.startPos + AdjustIgnoreBlankOverScrollOffSet(true);
startPos = NearZero(startPos, PX_EPSILON) ? 0.f : startPos;
return itemPosition_.begin()->first == 0 && GreatNotEqual(startPos + mainOffset, 0.f);
}
@ -3547,7 +3573,7 @@ bool SwiperPattern::IsOutOfEnd(float mainOffset) const
}
auto visibleWindowSize = CalculateVisibleSize();
auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset;
auto endPos = itemPosition_.rbegin()->second.endPos + mainOffset + AdjustIgnoreBlankOverScrollOffSet(false);
endPos = NearEqual(endPos, visibleWindowSize, PX_EPSILON) ? visibleWindowSize : endPos;
return itemPosition_.rbegin()->first == TotalCount() - 1 && LessNotEqual(endPos, visibleWindowSize);
}

View File

@ -431,7 +431,6 @@ public:
void OnCustomContentTransition(int32_t toIndex);
void OnCustomAnimationFinish(int32_t fromIndex, int32_t toIndex, bool hasOnChanged);
void OnSwiperCustomAnimationFinish(std::pair<int32_t, SwiperItemInfo> item);
float IgnoreBlankOffset(bool isJump);
void SetCustomAnimationToIndex(int32_t toIndex)
{
@ -898,6 +897,11 @@ private:
void PostIdleTask(const RefPtr<FrameNode>& frameNode);
float AdjustIgnoreBlankOverScrollOffSet(bool isStartOverScroll) const;
void UpdateIgnoreBlankOffsetWithIndex();
// overSrollDirection is true means over start boundary, false means over end boundary.
void UpdateIgnoreBlankOffsetWithDrag(bool overSrollDirection);
friend class SwiperHelper;
RefPtr<PanEvent> panEvent_;
@ -996,7 +1000,6 @@ private:
float contentMainSize_ = 0.0f;
float contentCrossSize_ = 0.0f;
bool crossMatchChild_ = false;
float ignoreBlankSpringOffset_ = 0.0f;
std::optional<int32_t> uiCastJumpIndex_;
std::optional<int32_t> jumpIndex_;
@ -1029,6 +1032,7 @@ private:
bool isIndicatorInteractive_ = true;
bool nextMarginIgnoreBlank_ = false;
bool prevMarginIgnoreBlank_ = false;
float ignoreBlankOffset_ = 0.0f;
std::optional<int32_t> cachedCount_;

View File

@ -877,7 +877,7 @@ HWTEST_F(SwiperCommonTestNg, OnKeyEvent005, TestSize.Level1)
/**
* @tc.name: MarginIgnoreBlankTest001
* @tc.desc: Test Swiper PrevMargin IgnoreBlank
* @tc.desc: Test Swiper IgnoreBlank in jumpIndex case
* @tc.type: FUNC
*/
HWTEST_F(SwiperCommonTestNg, MarginIgnoreBlankTest001, TestSize.Level1)
@ -902,11 +902,10 @@ HWTEST_F(SwiperCommonTestNg, MarginIgnoreBlankTest001, TestSize.Level1)
*/
ChangeIndex(0);
EXPECT_EQ(pattern_->GetCurrentShownIndex(), 0);
EXPECT_EQ(GetChildX(frameNode_, 0), itemWidth * 0);
EXPECT_EQ(GetChildX(frameNode_, 1), itemWidth * 1);
EXPECT_EQ(GetChildX(frameNode_, 0), 0.f);
EXPECT_EQ(GetChildX(frameNode_, 1), itemWidth);
EXPECT_EQ(GetChildX(frameNode_, 2), itemWidth * 2);
EXPECT_EQ(GetChildX(frameNode_, 3), itemWidth * 3);
EXPECT_EQ(GetChildX(frameNode_, 4), 0.f); // out of view
/**
* @tc.steps: step3. ChangeIndex to 1
@ -916,20 +915,19 @@ HWTEST_F(SwiperCommonTestNg, MarginIgnoreBlankTest001, TestSize.Level1)
EXPECT_EQ(pattern_->GetCurrentShownIndex(), 1);
EXPECT_EQ(GetChildX(frameNode_, 0), PRE_MARGIN - itemWidth);
EXPECT_EQ(GetChildX(frameNode_, 1), PRE_MARGIN);
EXPECT_EQ(GetChildX(frameNode_, 2), PRE_MARGIN + itemWidth * 1);
EXPECT_EQ(GetChildX(frameNode_, 2), PRE_MARGIN + itemWidth);
EXPECT_EQ(GetChildX(frameNode_, 3), PRE_MARGIN + itemWidth * 2);
EXPECT_EQ(GetChildX(frameNode_, 4), PRE_MARGIN + itemWidth * 3);
/**
* @tc.steps: step4. ChangeIndex to 2
* @tc.expected: Verify ignoreBlank is not effective
* @tc.expected: Verify ignoreBlank on the endpage is effective
*/
ChangeIndex(2);
EXPECT_EQ(pattern_->GetCurrentShownIndex(), 2);
EXPECT_EQ(GetChildX(frameNode_, 0), PRE_MARGIN - itemWidth); // out of view
EXPECT_EQ(GetChildX(frameNode_, 1), PRE_MARGIN + NEXT_MARGIN - itemWidth);
EXPECT_EQ(GetChildX(frameNode_, 2), PRE_MARGIN + NEXT_MARGIN);
EXPECT_EQ(GetChildX(frameNode_, 3), PRE_MARGIN + NEXT_MARGIN + itemWidth * 1);
EXPECT_EQ(GetChildX(frameNode_, 3), PRE_MARGIN + NEXT_MARGIN + itemWidth);
EXPECT_EQ(GetChildX(frameNode_, 4), PRE_MARGIN + NEXT_MARGIN + itemWidth * 2);
}