From d5d183109ea844be5ac7025845edb22388d751d4 Mon Sep 17 00:00:00 2001 From: yeyinglong Date: Thu, 18 Jan 2024 21:35:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84List=E9=AB=98=E5=BA=A6?= =?UTF-8?q?=E5=81=8F=E7=A7=BB=E9=87=8F=E4=BC=B0=E7=AE=97=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yeyinglong --- .../list/list_height_offset_calculator.h | 172 +++++++++++++++--- .../pattern/list/list_item_group_pattern.cpp | 14 +- .../pattern/list/list_item_group_pattern.h | 5 + .../pattern/list/list_layout_algorithm.cpp | 50 +---- .../pattern/list/list_layout_algorithm.h | 8 +- .../pattern/list/list_pattern.cpp | 35 ++-- 6 files changed, 187 insertions(+), 97 deletions(-) diff --git a/frameworks/core/components_ng/pattern/list/list_height_offset_calculator.h b/frameworks/core/components_ng/pattern/list/list_height_offset_calculator.h index 0a55f0b6e42..975b9dcdd3c 100644 --- a/frameworks/core/components_ng/pattern/list/list_height_offset_calculator.h +++ b/frameworks/core/components_ng/pattern/list/list_height_offset_calculator.h @@ -20,6 +20,7 @@ #include "core/components_ng/syntax/lazy_for_each_node.h" #include "core/components_ng/pattern/list/list_item_group_pattern.h" #include "core/components_ng/pattern/list/list_item_pattern.h" +#include "core/components_ng/pattern/list/list_layout_algorithm.h" namespace OHOS::Ace::NG { namespace { @@ -27,27 +28,37 @@ constexpr float DEFAULT_ITEM_HEIGHT = 64.f; } class ListHeightOffsetCalculator { public: - ListHeightOffsetCalculator(int32_t index, std::pair pos, float space, Axis axis) + ListHeightOffsetCalculator(const ListLayoutAlgorithm::PositionMap& itemPosition, float space, + int32_t lanes, Axis axis) : axis_(axis), spaceWidth_(space), lanes_(lanes), itemPosition_(itemPosition) { - axis_ = axis; - targetPos_ = pos; - targetIndex_ = index; - spaceWidth_ = space; + if (!itemPosition.empty()) { + targetPos_ = { itemPosition.begin()->second.startPos, itemPosition.begin()->second.endPos }; + startIndex_ = itemPosition.begin()->first; + endIndex_ = itemPosition.rbegin()->first; + float itemsSize = itemPosition.rbegin()->second.endPos - itemPosition.begin()->second.startPos + space; + estimateItemHeight_ = itemsSize / itemPosition.size() - space; + } } - void GetFrameNodeEstimateHeightOffset(RefPtr frameNode) + void CalculateFrameNode(RefPtr frameNode) { CHECK_NULL_VOID(frameNode); auto listItemPatten = frameNode->GetPattern(); if (listItemPatten) { - if (currentIndex_ > 0) { + if (currentIndex_ > 0 && currLane_ == 0) { estimateHeight_ += spaceWidth_; } - if (currentIndex_ == targetIndex_) { + if (currentIndex_ == startIndex_) { estimateOffset_ = estimateHeight_ - targetPos_.first; } float height = listItemPatten->GetEstimateHeight(GetAverageItemHeight(), axis_); - estimateHeight_ += height; + currRowHeight_ = std::max(currRowHeight_, height); + currLane_++; + if (currLane_ == lanes_) { + estimateHeight_ += currRowHeight_; + currLane_ = 0; + currRowHeight_ = 0.0f; + } currentIndex_++; if (listItemPatten->GetLayouted()) { totalItemHeight_ += height; @@ -60,27 +71,131 @@ public: if (currentIndex_ > 0) { estimateHeight_ += spaceWidth_; } - if (currentIndex_ == targetIndex_) { + if (currentIndex_ == startIndex_) { estimateOffset_ = listItemGroupPatten->GetEstimateOffset(estimateHeight_, targetPos_); } + if (currLane_ > 0) { + estimateHeight_ += currRowHeight_; + currLane_ = 0; + currRowHeight_ = 0.0f; + } estimateHeight_ += listItemGroupPatten->GetEstimateHeight(groupedItemHeight_); currentIndex_++; } } - bool GetEstimateHeightAndOffset(RefPtr node) + void CalculateUINode(RefPtr node) { - CHECK_NULL_RETURN(node, false); + CHECK_NULL_VOID(node); auto children = node->GetChildren(); for (const auto& child : children) { if (AceType::InstanceOf(child)) { auto frameNode = AceType::DynamicCast(child); - GetFrameNodeEstimateHeightOffset(frameNode); + CalculateFrameNode(frameNode); } else if (AceType::InstanceOf(child)) { - return false; + auto lazyForEach = AceType::DynamicCast(child); + CalculateLazyForEachNode(lazyForEach); + } else { + CalculateUINode(child); + } + } + } + + float GetLazyForEachIndexAverageHeight(RefPtr node, + int32_t startIndex, int32_t endIndex, bool &hasGroup) + { + auto itor = itemPosition_.find(startIndex); + float totalHeight = 0.0f; + int32_t itemCount = 0; + while (itor != itemPosition_.end() && itor->first <= endIndex) { + if (!itor->second.isGroup) { + totalHeight += itor->second.endPos - itor->second.startPos; + itor++; + itemCount++; + continue; + } + hasGroup = true; + if (itor->first == startIndex_ || itor->first == endIndex_) { + auto child = node->GetFrameChildByIndex(itor->first - currentIndex_, false); + auto frameNode = AceType::DynamicCast(child); + auto group = frameNode->GetPattern(); + if (!group->HasLayoutedItem()) { + itor++; + continue; + } + totalHeight += group->GetEstimateHeight(groupedItemHeight_); } else { - GetEstimateHeightAndOffset(child); + totalHeight += itor->second.endPos - itor->second.startPos; + } + itor++; + itemCount++; + } + if (itemCount == 0) { + return estimateItemHeight_; + } + return totalHeight / itemCount; + } + + float CalculateOffset(RefPtr node, float averageHeight) + { + auto itor = itemPosition_.begin(); + float skipHeight = 0.0f; + while (itor != itemPosition_.end() && itor->second.isGroup) { + auto child = node->GetFrameChildByIndex(itor->first - currentIndex_, false); + auto frameNode = AceType::DynamicCast(child); + auto group = frameNode->GetPattern(); + if (group->HasLayoutedItem()) { + std::pair pos = { itor->second.startPos, itor->second.endPos }; + return group->GetEstimateOffset(estimateOffset_ + skipHeight, pos); } + skipHeight += averageHeight; + itor++; + } + return estimateOffset_ - targetPos_.first; + } + + void CalculateLazyForEachNode(RefPtr node) + { + int32_t count = node->FrameCount(); + if (count <= 0) { + return; + } + if ((endIndex_ < currentIndex_) || (startIndex_ >= currentIndex_ + count)) { + estimateHeight_ += (estimateItemHeight_ + spaceWidth_) * GetLines(lanes_, count); + if (currentIndex_ > 0) { + estimateHeight_ -= spaceWidth_; + } + currentIndex_ += count; + return; + } + + bool hasGroup = false; + int32_t startIndex = std::max(currentIndex_, startIndex_); + int32_t endIndex = std::min(currentIndex_ + count - 1, endIndex_); + float averageHeight = GetLazyForEachIndexAverageHeight(node, startIndex, endIndex, hasGroup); + int32_t lanes = hasGroup ? 1 : lanes_; + if (startIndex == startIndex_) { + int32_t curr = GetLines(lanes, startIndex_ - currentIndex_); + estimateOffset_ = estimateHeight_ + (averageHeight + spaceWidth_) * curr; + estimateOffset_ = CalculateOffset(node, averageHeight); + if (startIndex_ > 0) { + estimateOffset_ -= spaceWidth_; + } + } + estimateHeight_ += (averageHeight + spaceWidth_) * GetLines(lanes, count); + if (currentIndex_ > 0) { + estimateHeight_ -= spaceWidth_; + } + currentIndex_ += count; + } + + bool GetEstimateHeightAndOffset(RefPtr node) + { + CalculateUINode(node); + if (currLane_ > 0) { + estimateHeight_ += currRowHeight_; + currLane_ = 0; + currRowHeight_ = 0.0f; } return true; } @@ -95,11 +210,6 @@ public: return estimateOffset_; } - void SetEstimatedItemHeight(float itemHeight) - { - estimateItemHeight_ = itemHeight; - } - private: float GetAverageItemHeight() const { @@ -109,9 +219,23 @@ private: return estimateItemHeight_; } + static int32_t GetLines(int32_t lanes, int32_t count) + { + if (lanes > 1) { + int32_t lines = count / lanes; + if (count % lanes > 0) { + lines += 1; + } + return lines; + } else { + return count; + } + } + Axis axis_ = Axis::VERTICAL; int32_t currentIndex_ = 0; - int32_t targetIndex_ = 0; + int32_t startIndex_ = 0; + int32_t endIndex_ = 0; std::pair targetPos_ = { 0.0f, 0.0f }; float estimateHeight_ = 0.0f; float estimateOffset_ = 0.0f; @@ -122,6 +246,12 @@ private: float estimateItemHeight_ = DEFAULT_ITEM_HEIGHT; float groupedItemHeight_ = DEFAULT_ITEM_HEIGHT; + + int32_t lanes_ = 1; + int32_t currLane_ = 0; + float currRowHeight_ = 0.0f; + + const ListLayoutAlgorithm::PositionMap& itemPosition_; }; } // namespace OHOS::Ace::NG #endif diff --git a/frameworks/core/components_ng/pattern/list/list_item_group_pattern.cpp b/frameworks/core/components_ng/pattern/list/list_item_group_pattern.cpp index af623c0db8b..6cc5d7a98b4 100644 --- a/frameworks/core/components_ng/pattern/list/list_item_group_pattern.cpp +++ b/frameworks/core/components_ng/pattern/list/list_item_group_pattern.cpp @@ -98,6 +98,7 @@ bool ListItemGroupPattern::OnDirtyLayoutWrapperSwap(const RefPtr& headerMainSize_ = layoutAlgorithm->GetHeaderMainSize(); footerMainSize_ = layoutAlgorithm->GetFooterMainSize(); layoutedItemInfo_ = layoutAlgorithm->GetLayoutedItemInfo(); + layouted_ = true; CheckListDirectionInCardStyle(); auto host = GetHost(); CHECK_NULL_RETURN(host, false); @@ -111,6 +112,11 @@ bool ListItemGroupPattern::OnDirtyLayoutWrapperSwap(const RefPtr& float ListItemGroupPattern::GetEstimateOffset(float height, const std::pair& targetPos) const { + if (layoutedItemInfo_.has_value() && layoutedItemInfo_.value().startIndex > 0) { + float averageHeight = 0.0f; + float estimateHeight = GetEstimateHeight(averageHeight); + return height + estimateHeight - targetPos.second; + } return height - targetPos.first; } @@ -120,7 +126,13 @@ float ListItemGroupPattern::GetEstimateHeight(float& averageHeight) const auto totalHeight = (layoutedItemInfo_.value().endPos - layoutedItemInfo_.value().startPos + spaceWidth_); auto itemCount = layoutedItemInfo_.value().endIndex - layoutedItemInfo_.value().startIndex + 1; averageHeight = totalHeight / itemCount; - return averageHeight * itemTotalCount_ + headerMainSize_ + footerMainSize_; + } + if (layouted_) { + if (itemTotalCount_ > 0) { + return itemTotalCount_ * averageHeight + headerMainSize_ + footerMainSize_ - spaceWidth_; + } else { + return headerMainSize_ + footerMainSize_; + } } auto host = GetHost(); auto totalItem = host->GetTotalChildCount(); diff --git a/frameworks/core/components_ng/pattern/list/list_item_group_pattern.h b/frameworks/core/components_ng/pattern/list/list_item_group_pattern.h index 8241aca855b..4a0eb971df2 100644 --- a/frameworks/core/components_ng/pattern/list/list_item_group_pattern.h +++ b/frameworks/core/components_ng/pattern/list/list_item_group_pattern.h @@ -175,6 +175,10 @@ public: float GetEstimateOffset(float height, const std::pair& targetPos) const; float GetEstimateHeight(float& averageHeight) const; + bool HasLayoutedItem() const + { + return layouted_ && (layoutedItemInfo_.has_value() || itemTotalCount_ == 0); + } private: bool IsNeedInitClickEventRecorder() const override @@ -201,6 +205,7 @@ private: float_t footerMainSize_ = 0.0f; std::optional layoutedItemInfo_; + bool layouted_ = false; ListItemGroupLayoutAlgorithm::PositionMap itemPosition_; float spaceWidth_ = 0.0f; diff --git a/frameworks/core/components_ng/pattern/list/list_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/list/list_layout_algorithm.cpp index b6abf48e4ff..096b47add0d 100644 --- a/frameworks/core/components_ng/pattern/list/list_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/list/list_layout_algorithm.cpp @@ -186,54 +186,6 @@ float ListLayoutAlgorithm::GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Ax return maxCrossSize; } -void ListLayoutAlgorithm::CalculateEstimateOffset(ScrollAlign align) -{ - if (itemPosition_.empty()) { - estimateOffset_ = 0.0f; - return; - } - float itemsHeight = (itemPosition_.rbegin()->second.endPos - itemPosition_.begin()->second.startPos) + spaceWidth_; - auto lines = static_cast(itemPosition_.size()); - if (GetLanes() > 1) { - lines = (lines / GetLanes()) + (lines % GetLanes() > 0 ? 1 : 0); - } - if (lines > 0) { - float averageHeight = itemsHeight / static_cast(lines); - switch (align) { - case ScrollAlign::START: - case ScrollAlign::NONE: - estimateOffset_ = averageHeight * static_cast(jumpIndex_.value() / GetLanes()) - - contentStartOffset_; - break; - case ScrollAlign::CENTER: - estimateOffset_ = averageHeight * static_cast(jumpIndex_.value() / GetLanes()) - - contentMainSize_ / 2.0f + (averageHeight - spaceWidth_) / 2.0f; - break; - case ScrollAlign::END: - estimateOffset_ = averageHeight * static_cast(jumpIndex_.value() / GetLanes() + 1) - - spaceWidth_ - contentMainSize_ + contentEndOffset_; - break; - case ScrollAlign::AUTO: - switch (scrollAutoType_) { - case ScrollAutoType::NOT_CHANGE: - estimateOffset_ = averageHeight * static_cast(itemPosition_.begin()->first / - GetLanes()) - itemPosition_.begin()->second.startPos; - break; - case ScrollAutoType::START: - estimateOffset_ = averageHeight * static_cast(jumpIndex_.value() / GetLanes()); - break; - case ScrollAutoType::END: - estimateOffset_ = averageHeight * static_cast(jumpIndex_.value() / GetLanes() + 1) - - spaceWidth_ - contentMainSize_; - break; - } - break; - } - } else { - estimateOffset_ = 0.0f; - } -} - void ListLayoutAlgorithm::ClearAllItemPosition(LayoutWrapper* layoutWrapper) { for (auto& pos : itemPosition_) { @@ -763,7 +715,7 @@ void ListLayoutAlgorithm::MeasureList(LayoutWrapper* layoutWrapper) HandleJumpAuto(layoutWrapper, startIndex, endIndex, startPos, endPos); break; } - CalculateEstimateOffset(scrollAlign_); + needEstimateOffset_ = true; } else if (targetIndex_.has_value()) { if (LessOrEqual(startIndex, targetIndex_.value())) { LayoutForward(layoutWrapper, startIndex, startPos); diff --git a/frameworks/core/components_ng/pattern/list/list_layout_algorithm.h b/frameworks/core/components_ng/pattern/list/list_layout_algorithm.h index 650cb8a70d9..59540a641c3 100644 --- a/frameworks/core/components_ng/pattern/list/list_layout_algorithm.h +++ b/frameworks/core/components_ng/pattern/list/list_layout_algorithm.h @@ -187,9 +187,9 @@ public: return spaceWidth_; } - std::optional GetEstimateOffset() const + bool NeedEstimateOffset() const { - return estimateOffset_; + return needEstimateOffset_; } void SetContentStartOffset(float startOffset) @@ -360,8 +360,6 @@ private: void MeasureList(LayoutWrapper* layoutWrapper); void CheckJumpToIndex(); - void CalculateEstimateOffset(ScrollAlign align); - std::pair RequestNewItemsForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos, Axis axis); @@ -414,7 +412,7 @@ private: V2::ListItemAlign listItemAlign_ = V2::ListItemAlign::START; - std::optional estimateOffset_; + bool needEstimateOffset_ = false; bool mainSizeIsDefined_ = false; bool crossMatchChild_ = false; diff --git a/frameworks/core/components_ng/pattern/list/list_pattern.cpp b/frameworks/core/components_ng/pattern/list/list_pattern.cpp index 9df41c57f1f..4c04c9a9046 100644 --- a/frameworks/core/components_ng/pattern/list/list_pattern.cpp +++ b/frameworks/core/components_ng/pattern/list/list_pattern.cpp @@ -137,16 +137,18 @@ bool ListPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, c float relativeOffset = listLayoutAlgorithm->GetCurrentOffset(); auto predictSnapOffset = listLayoutAlgorithm->GetPredictSnapOffset(); auto predictSnapEndPos = listLayoutAlgorithm->GetPredictSnapEndPosition(); - if (listLayoutAlgorithm->GetEstimateOffset().has_value()) { - float absoluteOffset = listLayoutAlgorithm->GetEstimateOffset().value_or(currentOffset_); - relativeOffset += absoluteOffset - currentOffset_; + if (listLayoutAlgorithm->NeedEstimateOffset()) { + auto calculate = ListHeightOffsetCalculator(itemPosition_, spaceWidth_, lanes_, GetAxis()); + calculate.GetEstimateHeightAndOffset(GetHost()); + currentOffset_ = calculate.GetEstimateOffset(); isJump = true; - } - // correct the currentOffset when the startIndex is 0. - if (listLayoutAlgorithm->GetStartIndex() == 0) { - currentOffset_ = -itemPosition_.begin()->second.startPos; } else { - currentOffset_ = currentOffset_ + relativeOffset; + // correct the currentOffset when the startIndex is 0. + if (listLayoutAlgorithm->GetStartIndex() == 0) { + currentOffset_ = -itemPosition_.begin()->second.startPos; + } else { + currentOffset_ = currentOffset_ + relativeOffset; + } } if (targetIndex_) { AnimateToTarget(targetIndex_.value(), targetIndexInGroup_, scrollAlign_); @@ -1565,19 +1567,10 @@ void ListPattern::UpdateScrollBarOffset() if (!GetScrollBar() && !GetScrollBarProxy()) { return; } - float itemsSize = itemPosition_.rbegin()->second.endPos - itemPosition_.begin()->second.startPos + spaceWidth_; - float currentOffset = itemsSize / itemPosition_.size() * itemPosition_.begin()->first - startMainPos_; - auto estimatedHeight = itemsSize / itemPosition_.size() * (maxListItemIndex_ + 1) - spaceWidth_; - if (lanes_ == 1) { - const auto& begin = *itemPosition_.begin(); - auto calculate = ListHeightOffsetCalculator( - begin.first, { begin.second.startPos, begin.second.endPos }, spaceWidth_, GetAxis()); - calculate.SetEstimatedItemHeight(itemsSize / itemPosition_.size() - spaceWidth_); - if (calculate.GetEstimateHeightAndOffset(GetHost())) { - currentOffset = calculate.GetEstimateOffset(); - estimatedHeight = calculate.GetEstimateHeight(); - } - } + auto calculate = ListHeightOffsetCalculator(itemPosition_, spaceWidth_, lanes_, GetAxis()); + calculate.GetEstimateHeightAndOffset(GetHost()); + float currentOffset = calculate.GetEstimateOffset(); + float estimatedHeight = calculate.GetEstimateHeight(); if (GetAlwaysEnabled()) { estimatedHeight = estimatedHeight - spaceWidth_; } -- Gitee