From f1012828cab1fdc429cac47d7bb7d3335412228f Mon Sep 17 00:00:00 2001 From: caocan Date: Tue, 27 Sep 2022 16:49:47 +0800 Subject: [PATCH] =?UTF-8?q?[UI=E7=BB=84=E4=BB=B6=E9=87=8D=E6=9E=84]Grid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: caocan Change-Id: Ib5770343f1e874b87daecd7c9dd8209e21af9caa --- .../pattern/grid/grid_layout_info.h | 6 +- .../pattern/grid/grid_pattern.cpp | 5 + .../grid_scroll_layout_algorithm.cpp | 277 ++++++++++++++---- .../grid_scroll_layout_algorithm.h | 22 +- .../components_ng/pattern/grid/grid_utils.cpp | 18 ++ .../components_ng/pattern/grid/grid_utils.h | 3 + 6 files changed, 263 insertions(+), 68 deletions(-) diff --git a/frameworks/core/components_ng/pattern/grid/grid_layout_info.h b/frameworks/core/components_ng/pattern/grid/grid_layout_info.h index a222fb0267d..66bd29d2429 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_layout_info.h +++ b/frameworks/core/components_ng/pattern/grid/grid_layout_info.h @@ -41,9 +41,9 @@ struct GridLayoutInfo { bool reachEnd_ = false; bool reachStart_ = false; - // in vertical grid, this map is like: [rowIndex: [itemIndex: fractionCount], [itemIndex: fractionCount]] - // for e.g, when a vertical grid has two [GridItem]s in first row, [gridMatrix_] is like [0: [0: 1fr], [1: 2fr]] - std::map> gridMatrix_; + // Map structure: [mainIndex, [crossIndex, index]], + // when vertical, mainIndex is rowIndex and crossIndex is columnIndex. + std::map> gridMatrix_; // in vertical grid, this map is like: [rowIndex: rowHeight] std::map lineHeightMap_; }; diff --git a/frameworks/core/components_ng/pattern/grid/grid_pattern.cpp b/frameworks/core/components_ng/pattern/grid/grid_pattern.cpp index 24645587154..3084c960eb5 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_pattern.cpp +++ b/frameworks/core/components_ng/pattern/grid/grid_pattern.cpp @@ -36,12 +36,17 @@ RefPtr GridPattern::CreateLayoutAlgorithm() std::swap(crossCount, mainCount); } + // When rowsTemplate and columnsTemplate is both setting, use static layout algorithm. if (!rows.empty() && !cols.empty()) { return MakeRefPtr(gridLayoutInfo_, crossCount, mainCount); } + + // When rowsTemplate and columnsTemplate is both not setting, use adaptive layout algorithm. if (rows.empty() && cols.empty()) { return MakeRefPtr(gridLayoutInfo_); } + + // If only set one of rowTemplate and columnsTemplate, use scrollable layout algorithm. return MakeRefPtr(gridLayoutInfo_, crossCount, mainCount); } diff --git a/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.cpp index c3346a00892..9b624299abe 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.cpp @@ -16,16 +16,16 @@ #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h" #include +#include +#include #include "base/geometry/ng/offset_t.h" +#include "base/geometry/ng/size_t.h" #include "base/utils/utils.h" +#include "core/components_ng/pattern/grid/grid_utils.h" #include "core/components_ng/property/layout_constraint.h" #include "core/components_ng/property/measure_utils.h" -#ifdef NG_BUILD -#include "ace_shell/shell/common/window_manager.h" -#endif - namespace OHOS::Ace::NG { void GridScrollLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) @@ -45,6 +45,8 @@ void GridScrollLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize); MinusPaddingToSize(gridLayoutProperty->CreatePaddingAndBorder(), idealSize); + InitialItemsCrossSize(gridLayoutProperty, idealSize); + // Step2: Measure children that can be displayed in viewport of Grid float mainSize = GetMainAxisSize(idealSize, axis); float crossSize = GetCrossAxisSize(idealSize, axis); @@ -64,37 +66,72 @@ void GridScrollLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) : OffsetF(gridLayoutInfo_.currentOffset_, 0.0f); auto parentOffset = layoutWrapper->GetGeometryNode()->GetParentGlobalOffset() + layoutWrapper->GetGeometryNode()->GetFrameOffset(); - float crossFrWidth = GetCrossAxisSize(size, gridLayoutInfo_.axis_) / static_cast(crossCount_); - // For e.g, when a vertical grid has two [GridItem] in first row, [gridMatrix_] is like {[0: {[0: 1fr], [1: 2fr]}]} - // TODO: Support horizontal Grid float prevLineHeight = 0.0f; for (const auto& line : gridLayoutInfo_.gridMatrix_) { - auto offset = childFrameOffset + OffsetF(0.0, prevLineHeight); + auto prevLineOffset = axis_ == Axis::VERTICAL ? OffsetF(0.0, prevLineHeight) : OffsetF(prevLineHeight, 0.0); + auto offset = childFrameOffset + prevLineOffset; if (line.second.empty()) { LOGE("line %{public}d should not be empty, please check.", line.first); break; } - float prevItemCrossSize = 0.0f; + int32_t itemIdex = -1; for (auto iter = line.second.begin(); iter != line.second.end(); iter++) { - offset += - gridLayoutProperty->IsVertical() ? OffsetF(prevItemCrossSize, 0.0) : OffsetF(0.0, prevItemCrossSize); - auto wrapper = layoutWrapper->GetOrCreateChildByIndex(iter->first); + // If item index is the same, must be the same GridItem, need't layout again. + if (itemIdex == iter->second) { + continue; + } + itemIdex = iter->first; + auto crossOffset = itemsCrossPosition_.at(iter->second); + if (axis_ == Axis::VERTICAL) { + offset.SetX(crossOffset); + } else { + offset.SetY(crossOffset); + } + auto wrapper = layoutWrapper->GetOrCreateChildByIndex(iter->second); if (!wrapper) { - LOGE("item wrapper of index: %{public}d is null, please check.", iter->first); + LOGE("item wrapper of index: %{public}d is null, please check.", iter->second); continue; } wrapper->GetGeometryNode()->SetFrameOffset(offset); wrapper->Layout(parentOffset); - prevItemCrossSize = static_cast(iter->second) * crossFrWidth; } - prevLineHeight += gridLayoutInfo_.lineHeightMap_[line.first]; + prevLineHeight += + gridLayoutInfo_.lineHeightMap_[line.first] + GridUtils::GetMainGap(gridLayoutProperty, size, axis_); + } +} + +void GridScrollLayoutAlgorithm::InitialItemsCrossSize( + const RefPtr& layoutProperty, const SizeF& frameSize) +{ + itemsCrossSize_.clear(); + auto rowsTemplate = layoutProperty->GetRowsTemplate().value_or(""); + auto columnsTemplate = layoutProperty->GetColumnsTemplate().value_or(""); + axis_ = columnsTemplate.empty() ? Axis::HORIZONTAL : Axis::VERTICAL; + auto scale = layoutProperty->GetLayoutConstraint()->scaleProperty; + auto rowsGap = ConvertToPx(layoutProperty->GetRowsGap().value_or(0.0_vp), scale, frameSize.Width()).value_or(0); + auto columnsGap = + ConvertToPx(layoutProperty->GetColumnsGap().value_or(0.0_vp), scale, frameSize.Height()).value_or(0); + std::vector crossLens; + if (!rowsTemplate.empty()) { + crossLens = GridUtils::ParseArgs(rowsTemplate, frameSize.Height(), rowsGap); + } else { + crossLens = GridUtils::ParseArgs(columnsTemplate, frameSize.Width(), columnsGap); + } + + int32_t index = 0; + for (const auto& len : crossLens) { + itemsCrossSize_.try_emplace(index, len); + ++index; } } void GridScrollLayoutAlgorithm::FillGridViewportAndMeasureChildren( float mainSize, float crossSize, const RefPtr& gridLayoutProperty, LayoutWrapper* layoutWrapper) { + crossIndex_ = 0; + mainIndex_ = currentMainLineIndex_; + itemsCrossPosition_.clear(); float mainLength = gridLayoutInfo_.currentOffset_; // Step1: Measure [GridItem] that has been recorded to [gridMatrix_] @@ -118,8 +155,8 @@ void GridScrollLayoutAlgorithm::FillGridViewportAndMeasureChildren( void GridScrollLayoutAlgorithm::FillBlankAtStart(float mainSize, float crossSize, const RefPtr& gridLayoutProperty, LayoutWrapper* layoutWrapper, float& mainLength) { - if (LessOrEqual( - gridLayoutInfo_.currentOffset_, 0.0)) { // If [currentOffset_] is none-positive, it means no blank at start + // If [currentOffset_] is none-positive, it means no blank at start + if (LessOrEqual(gridLayoutInfo_.currentOffset_, 0.0)) { return; } auto blankAtStart = gridLayoutInfo_.currentOffset_; @@ -137,20 +174,20 @@ void GridScrollLayoutAlgorithm::FillBlankAtStart(float mainSize, float crossSize gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_; } -// When a moving up event comes, the [currrentOffset_] may have been reduced too much than the items really need to -// be moved up, so we need to modify [currrentOffset_] accrording to previous position. +// When a moving up event comes, the [currentOffset_] may have been reduced too much than the items really need to +// be moved up, so we need to modify [currentOffset_] according to previous position. void GridScrollLayoutAlgorithm::ModifyCurrentOffsetWhenReachEnd(float mainSize) { - // Step1. Calculate total length of all items in viewport. [lengthOfItemsInViewport] must be greater than or equal - // to viewport height + // Step1. Calculate total length of all items in viewport. + // [lengthOfItemsInViewport] must be greater than or equal to viewport height float lengthOfItemsInViewport = 0.0f; for (auto i = gridLayoutInfo_.startMainLineIndex_; i <= gridLayoutInfo_.endMainLineIndex_; i++) { lengthOfItemsInViewport += gridLayoutInfo_.lineHeightMap_[i]; } // Step2. Calculate real offset that items can only be moved up by. - float realOffsetToMoveUp = - lengthOfItemsInViewport - mainSize + gridLayoutInfo_.prevOffset_; // Hint: [prevOffset_] is a non-positive value + // Hint: [prevOffset_] is a non-positive value + float realOffsetToMoveUp = lengthOfItemsInViewport - mainSize + gridLayoutInfo_.prevOffset_; // Step3. modify [currentOffset_] gridLayoutInfo_.currentOffset_ = gridLayoutInfo_.prevOffset_ - realOffsetToMoveUp; @@ -178,29 +215,29 @@ void GridScrollLayoutAlgorithm::MeasureRecordedItems(float mainSize, float cross { currentMainLineIndex_ = gridLayoutInfo_.startMainLineIndex_ - 1; bool runOutOfRecord = false; - while (LessNotEqual(mainLength, mainSize)) { // Measure grid items row by row + // Measure grid items row by row + while (LessNotEqual(mainLength, mainSize)) { + // If [gridMatrix_] does not contain record of line [currentMainLineIndex_], do [FillNewLineBackward] auto gridMatrixIter = gridLayoutInfo_.gridMatrix_.find(++currentMainLineIndex_); if (gridMatrixIter == gridLayoutInfo_.gridMatrix_.end()) { runOutOfRecord = true; - break; // If [gridMatrix_] does not contain record of line [currentMainLineIndex_], do [FillNewLineBackward] + break; } float lineHeight = -1.0f; int32_t currentIndex = 0; - // One record is like [0: 1fr] or [1: 2fr] for (const auto& gridItemRecord : gridMatrixIter->second) { - currentIndex = gridItemRecord.first; + currentIndex = gridItemRecord.second; auto itemWrapper = layoutWrapper->GetOrCreateChildByIndex(currentIndex); if (!itemWrapper) { LOGE("GridItem wrapper of index %{public}u null", currentIndex); break; } - itemWrapper->Measure( - MakeMeasureConstraintForGridItem(mainSize, crossSize, gridItemRecord.second, gridLayoutProperty)); + MeasureChild(mainSize, crossSize, currentIndex, layoutWrapper, itemWrapper); auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize(); lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight); // Record end index. When fill new line, the [endIndex_] will be the first item index to request - gridLayoutInfo_.endIndex_ = gridItemRecord.first; + gridLayoutInfo_.endIndex_ = gridItemRecord.second; } if (lineHeight > 0) { // Means at least one item has been measured @@ -228,16 +265,15 @@ void GridScrollLayoutAlgorithm::MeasureRecordedItems(float mainSize, float cross float GridScrollLayoutAlgorithm::FillNewLineForward( float crossSize, float mainSize, const RefPtr& gridLayoutProperty, LayoutWrapper* layoutWrapper) { - // To make the code more convinient to read, we name a param in situation of vertical, for exacmple: + // To make the code more convenient to read, we name a param in situation of vertical, for example: // 1. [lineHight] means height of a row when the Grid is vertical; // 2. [lineHight] means width of a column when the Grid is horizontal; // Other params are also named according to this principle. float lineHeight = -1.0f; auto currentIndex = gridLayoutInfo_.startIndex_; - // TODO: need to consider [colunmStart]\[columsEnd] of [GridItem] // TODO: shoule we use policy of adaptive layout according to size of [GridItem] ? if (gridLayoutInfo_.startMainLineIndex_ - 1 < 0) { - LOGI("startMainLineIndex: %{public}d is alreay the first line, no forward line to make", + LOGI("startMainLineIndex: %{public}d is already the first line, no forward line to make", gridLayoutInfo_.startMainLineIndex_); return -1.0f; } @@ -253,16 +289,13 @@ float GridScrollLayoutAlgorithm::FillNewLineForward( LOGE("GridItem wrapper of index %{public}u null", currentIndex); break; } - // Step2. Make constraint and measure child - // TODO: need to consider [colunmStart]\[columsEnd] of [GridItem] + // Step2. Measure child // TODO: need to use [isScrollable_] - itemWrapper->Measure(MakeMeasureConstraintForGridItem(mainSize, crossSize, 1, gridLayoutProperty)); + i += MeasureChild(mainSize, crossSize, currentIndex, layoutWrapper, itemWrapper); // Step3. Measure [GridItem] auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize(); lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight); - // TODO: get [colunmStart]\[columsEnd] of [GridItem] - gridLayoutInfo_.gridMatrix_[gridLayoutInfo_.startMainLineIndex_][currentIndex] = 1; gridLayoutInfo_.startIndex_ = currentIndex; doneCreateNewLine = true; } @@ -283,7 +316,6 @@ float GridScrollLayoutAlgorithm::FillNewLineBackward( float lineHeight = -1.0f; auto currentIndex = gridLayoutInfo_.endIndex_ + 1; currentMainLineIndex_++; // if it fails to fill a new line backward, do [currentMainLineIndex_--] - // TODO: need to consider [colunmStart]\[columsEnd] of [GridItem] // TODO: shoule we use policy of adaptive layout according to size of [GridItem] ? bool doneFillLine = false; for (uint32_t i = 0; i < crossCount_; i++) { @@ -293,16 +325,12 @@ float GridScrollLayoutAlgorithm::FillNewLineBackward( LOGE("GridItem wrapper of index %{public}u null", currentIndex); break; } - // Step2. Make constraint and measure child - // TODO: need to consider [colunmStart]\[columsEnd] of [GridItem] - // TODO: need to use [isScrollable_] - itemWrapper->Measure(MakeMeasureConstraintForGridItem(mainSize, crossSize, 1, gridLayoutProperty)); + // Step2. Measure child + i += MeasureChild(mainSize, crossSize, currentIndex, layoutWrapper, itemWrapper); // Step3. Measure [GridItem] auto itemSize = itemWrapper->GetGeometryNode()->GetFrameSize(); lineHeight = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), lineHeight); - // TODO: get [colunmStart]\[columsEnd] of [GridItem] - gridLayoutInfo_.gridMatrix_[currentMainLineIndex_][currentIndex] = 1; gridLayoutInfo_.endIndex_ = currentIndex; currentIndex++; doneFillLine = true; @@ -318,22 +346,23 @@ float GridScrollLayoutAlgorithm::FillNewLineBackward( } void GridScrollLayoutAlgorithm::StripItemsOutOfViewport(LayoutWrapper* layoutWrapper) { - // Erase records that are out of viewport - // 1. Erase records that are on top of viewport + // Erase records that are out of viewport. if (gridLayoutInfo_.lineHeightMap_.empty() || gridLayoutInfo_.gridMatrix_.empty()) { return; } std::list removeRows; - for (const auto& [rowIndex, rowIndexMap] : gridLayoutInfo_.gridMatrix_) { + for (const auto& [rowIndex, columnMap] : gridLayoutInfo_.gridMatrix_) { + // 1. Erase records that are on top of viewport. if (rowIndex < gridLayoutInfo_.startMainLineIndex_) { - for (auto&& [index, fr] : rowIndexMap) { - layoutWrapper->RemoveChildInRenderTree(index); + for (auto&& [columnIndex, itemIndex] : columnMap) { + layoutWrapper->RemoveChildInRenderTree(itemIndex); } removeRows.emplace_back(rowIndex); } + // 1. Erase records that are on bottom of viewport. if (rowIndex > gridLayoutInfo_.endMainLineIndex_) { - for (auto&& [index, fr] : rowIndexMap) { - layoutWrapper->RemoveChildInRenderTree(index); + for (auto&& [columnIndex, itemIndex] : columnMap) { + layoutWrapper->RemoveChildInRenderTree(itemIndex); } removeRows.emplace_back(rowIndex); } @@ -345,34 +374,158 @@ void GridScrollLayoutAlgorithm::StripItemsOutOfViewport(LayoutWrapper* layoutWra LOGD("grid item size : %{public}d", static_cast(gridLayoutInfo_.gridMatrix_.size())); } -LayoutConstraintF GridScrollLayoutAlgorithm::MakeMeasureConstraintForGridItem(float mainSize, float crossSize, - uint32_t itemFractionCount, const RefPtr& gridLayoutProperty) const +LayoutConstraintF GridScrollLayoutAlgorithm::CreateChildConstraint(float mainSize, float crossSize, + const RefPtr& gridLayoutProperty, int32_t crossStart, int32_t crossSpan) const { float itemMainSize = gridLayoutProperty->IsConfiguredScrollable() ? Infinity() : mainSize / static_cast(mainCount_); - float fractionWidth = crossSize / static_cast(crossCount_); - float itemCrossSize = fractionWidth * static_cast(itemFractionCount); + + auto frameSize = axis_ == Axis::VERTICAL ? SizeF(crossSize, mainSize) : SizeF(mainSize, crossSize); + float itemCrossSize = GridUtils::GetCrossGap(gridLayoutProperty, frameSize, axis_) * (crossSpan - 1); + for (int32_t index = 0; index < crossSpan; ++index) { + int32_t crossIndex = (crossStart + index) % static_cast(crossCount_); + if (crossIndex >= 0 && crossIndex < static_cast(itemsCrossSize_.size())) { + itemCrossSize += itemsCrossSize_.at(crossIndex); + } + } + SizeF itemIdealSize = gridLayoutProperty->IsVertical() ? SizeF(itemCrossSize, itemMainSize) : SizeF(itemMainSize, itemCrossSize); auto itemConstraint = gridLayoutProperty->CreateChildConstraint(); // The percent size of GridItem is based on the fraction size, for e.g., if a GridItem has width of "50%" in Grid - // configured with columnsTemplate = "1fr 1fr", rowsTemplate = "1fr 1fr", then tht GridItem width = [width of 1fr] * - // 50% + // configured with columnsTemplate = "1fr 1fr", rowsTemplate = "1fr 1fr", + // then the GridItem width = [width of 1fr] * 50%, // [itemFractionCount] is now only in direction of cross axis - // TODO: consider rowStart/rowEnd float widthPercentBase = - GreatOrEqual(crossCount_, Infinity()) - ? itemConstraint.percentReference.Width() - : itemConstraint.percentReference.Width() / static_cast(crossCount_ * itemFractionCount); + GreatOrEqual(crossCount_, Infinity()) ? itemConstraint.percentReference.Width() : itemCrossSize; float heightPercentBase = GreatOrEqual(mainCount_, Infinity()) ? itemConstraint.percentReference.Height() : itemConstraint.percentReference.Height() / static_cast(mainCount_); itemConstraint.percentReference = SizeF(widthPercentBase, heightPercentBase); itemConstraint.maxSize = itemIdealSize; + itemConstraint.UpdateIllegalSelfIdealSizeWithCheck(axis_ == Axis::VERTICAL + ? OptionalSizeF(itemCrossSize, std::nullopt) + : OptionalSizeF(std::nullopt, itemCrossSize)); return itemConstraint; } +void GridScrollLayoutAlgorithm::GetNextGrid(int32_t& curMain, int32_t& curCross) const +{ + ++curCross; + if (curCross >= static_cast(crossCount_)) { + curCross = 0; + ++curMain; + } +} + +int32_t GridScrollLayoutAlgorithm::MeasureChild(float mainSize, float crossSize, int32_t itemIndex, + LayoutWrapper* layoutWrapper, const RefPtr& childLayoutWrapper) +{ + auto gridLayoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_RETURN(gridLayoutProperty, 0); + auto childLayoutProperty = DynamicCast(childLayoutWrapper->GetLayoutProperty()); + CHECK_NULL_RETURN(childLayoutProperty, 0); + auto mainCount = static_cast(mainCount_); + auto crossCount = static_cast(crossCount_); + int32_t itemRowStart = childLayoutProperty->GetRowStart().value_or(-1); + int32_t itemColStart = childLayoutProperty->GetColumnStart().value_or(-1); + int32_t itemRowSpan = std::max(childLayoutProperty->GetRowEnd().value_or(-1) - itemRowStart + 1, 1); + int32_t itemColSpan = std::max(childLayoutProperty->GetColumnEnd().value_or(-1) - itemColStart + 1, 1); + auto mainStart = axis_ == Axis::VERTICAL ? itemRowStart : itemColStart; + auto crossStart = axis_ == Axis::VERTICAL ? itemColStart : itemRowStart; + auto mainSpan = axis_ == Axis::VERTICAL ? itemRowSpan : itemColSpan; + auto crossSpan = axis_ == Axis::VERTICAL ? itemColSpan : itemRowSpan; + + if (itemRowStart >= 0 && itemRowStart < mainCount && itemColStart >= 0 && itemColStart < crossCount && + CheckGridPlaced(itemIndex, mainStart, crossStart, mainSpan, crossSpan)) { + childLayoutWrapper->Measure( + CreateChildConstraint(mainSize, crossSize, gridLayoutProperty, crossStart, crossSpan)); + itemsCrossPosition_.try_emplace(itemIndex, ComputeItemCrossPosition(layoutWrapper, crossStart)); + } else { + while (!CheckGridPlaced(itemIndex, mainIndex_, crossIndex_, mainSpan, crossSpan)) { + GetNextGrid(mainIndex_, crossIndex_); + if (mainIndex_ >= mainCount || crossIndex_ >= crossCount) { + break; + } + } + if (mainIndex_ >= mainCount || crossIndex_ >= crossCount) { + return 0; + } + childLayoutWrapper->Measure( + CreateChildConstraint(mainSize, crossSize, gridLayoutProperty, crossIndex_, crossSpan)); + itemsCrossPosition_.try_emplace(itemIndex, ComputeItemCrossPosition(layoutWrapper, crossIndex_)); + } + return crossSpan - 1; +} + +bool GridScrollLayoutAlgorithm::CheckGridPlaced( + int32_t index, int32_t main, int32_t cross, int32_t& mainSpan, int32_t& crossSpan) +{ + // If start position is already exist in gridMatrix, place grid item fail. + auto mainIter = gridLayoutInfo_.gridMatrix_.find(main); + if (mainIter != gridLayoutInfo_.gridMatrix_.end()) { + auto crossIter = mainIter->second.find(cross); + if (crossIter != mainIter->second.end()) { + return false; + } + } + + // If cross length of grid item if out of range, place grid item fail. + if (cross + crossSpan > static_cast(crossCount_)) { + return false; + } + + // If any grid item is already exist in gridMatrix, place grid item fail. + for (int32_t i = 0; i < mainSpan; i++) { + mainIter = gridLayoutInfo_.gridMatrix_.find(i + main); + if (mainIter == gridLayoutInfo_.gridMatrix_.end()) { + continue; + } + for (int32_t j = 0; j < crossSpan; j++) { + auto crossIter = mainIter->second.find(j + cross); + if (crossIter != mainIter->second.end()) { + return false; + } + } + } + + // Padding grid matrix for grid item's range. + for (int32_t i = main; i < main + mainSpan; ++i) { + std::map mainMap; + auto iter = gridLayoutInfo_.gridMatrix_.find(i); + if (iter != gridLayoutInfo_.gridMatrix_.end()) { + mainMap = iter->second; + } + for (int32_t j = cross; j < cross + crossSpan; ++j) { + mainMap.emplace(std::make_pair(j, index)); + } + gridLayoutInfo_.gridMatrix_[i] = mainMap; + } + return true; +} + +float GridScrollLayoutAlgorithm::ComputeItemCrossPosition(LayoutWrapper* layoutWrapper, int32_t crossStart) const +{ + auto layoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_RETURN(layoutProperty, 0); + auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize(); + auto scale = layoutProperty->GetLayoutConstraint()->scaleProperty; + auto rowsGap = ConvertToPx(layoutProperty->GetRowsGap().value_or(0.0_vp), scale, frameSize.Width()).value_or(0); + auto columnsGap = + ConvertToPx(layoutProperty->GetColumnsGap().value_or(0.0_vp), scale, frameSize.Height()).value_or(0); + auto crossGap = axis_ == Axis::VERTICAL ? columnsGap : rowsGap; + + float position = 0.0f; + for (int32_t index = 0; index < crossStart; ++index) { + if (index >= 0 && index < static_cast(itemsCrossSize_.size())) { + position += itemsCrossSize_.at(index); + } + } + position += crossStart * crossGap; + return position; +} + GridLayoutInfo GridScrollLayoutAlgorithm::GetGridLayoutInfo() { return std::move(gridLayoutInfo_); diff --git a/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h b/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h index 8ab13943d1c..b31d9b0b4cb 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h +++ b/frameworks/core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h @@ -18,6 +18,7 @@ #include "core/components_ng/layout/box_layout_algorithm.h" #include "core/components_ng/layout/layout_wrapper.h" +#include "core/components_ng/pattern/grid/grid_item_layout_property.h" #include "core/components_ng/pattern/grid/grid_layout_info.h" #include "core/components_ng/pattern/grid/grid_layout_property.h" @@ -57,16 +58,31 @@ private: float FillNewLineBackward(float crossSize, float mainSize, const RefPtr& gridLayoutProperty, LayoutWrapper* layoutWrapper); - LayoutConstraintF MakeMeasureConstraintForGridItem(float mainSize, float crossSize, uint32_t itemFractionCount, - const RefPtr& gridLayoutProperty) const; + int32_t MeasureChild(float mainSize, float crossSize, int32_t itemIndex, LayoutWrapper* layoutWrapper, + const RefPtr& childLayoutWrapper); + float ComputeItemCrossPosition(LayoutWrapper* layoutWrapper, int32_t crossStart) const; + void GetNextGrid(int32_t& curMain, int32_t& curCross) const; + bool CheckGridPlaced(int32_t index, int32_t main, int32_t cross, int32_t& mainSpan, int32_t& crossSpan); + LayoutConstraintF CreateChildConstraint(float mainSize, float crossSize, + const RefPtr& gridLayoutProperty, int32_t crossStart, int32_t crossSpan) const; void StripItemsOutOfViewport(LayoutWrapper* layoutWrapper); void ModifyCurrentOffsetWhenReachEnd(float mainSize); + void InitialItemsCrossSize(const RefPtr& layoutProperty, const SizeF& frameSize); GridLayoutInfo gridLayoutInfo_; uint32_t crossCount_ = 0; uint32_t mainCount_ = 0; - int32_t currentMainLineIndex_ = 0; // it equals to row index in vertical grid + int32_t currentMainLineIndex_ = 0; // it equals to row index in vertical grid + std::map itemsCrossSize_; // grid item's size in cross axis. + Axis axis_ = Axis::VERTICAL; + + // Store current index when place children. + int32_t mainIndex_ = 0; + int32_t crossIndex_ = 0; + + // Map structure: [index, crossPosition], store cross position of each item. + std::map itemsCrossPosition_; ACE_DISALLOW_COPY_AND_MOVE(GridScrollLayoutAlgorithm); }; diff --git a/frameworks/core/components_ng/pattern/grid/grid_utils.cpp b/frameworks/core/components_ng/pattern/grid/grid_utils.cpp index 5ebc1f6da4f..7a9fe80fd9e 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_utils.cpp +++ b/frameworks/core/components_ng/pattern/grid/grid_utils.cpp @@ -52,4 +52,22 @@ std::vector GridUtils::ParseArgs(const std::string& args, float size, flo return lens; } +float GridUtils::GetMainGap(const RefPtr& gridLayoutProperty, const SizeF& frameSize, Axis axis) +{ + auto scale = gridLayoutProperty->GetLayoutConstraint()->scaleProperty; + auto rowsGap = ConvertToPx(gridLayoutProperty->GetRowsGap().value_or(0.0_vp), scale, frameSize.Width()).value_or(0); + auto columnsGap = + ConvertToPx(gridLayoutProperty->GetColumnsGap().value_or(0.0_vp), scale, frameSize.Height()).value_or(0); + return axis == Axis::HORIZONTAL ? columnsGap : rowsGap; +} + +float GridUtils::GetCrossGap(const RefPtr& gridLayoutProperty, const SizeF& frameSize, Axis axis) +{ + auto scale = gridLayoutProperty->GetLayoutConstraint()->scaleProperty; + auto rowsGap = ConvertToPx(gridLayoutProperty->GetRowsGap().value_or(0.0_vp), scale, frameSize.Width()).value_or(0); + auto columnsGap = + ConvertToPx(gridLayoutProperty->GetColumnsGap().value_or(0.0_vp), scale, frameSize.Height()).value_or(0); + return axis == Axis::HORIZONTAL ? rowsGap : columnsGap; +} + } // namespace OHOS::Ace::NG \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/grid/grid_utils.h b/frameworks/core/components_ng/pattern/grid/grid_utils.h index 41aa7c45e5b..3123d658b6e 100644 --- a/frameworks/core/components_ng/pattern/grid/grid_utils.h +++ b/frameworks/core/components_ng/pattern/grid/grid_utils.h @@ -19,6 +19,7 @@ #include "base/memory/referenced.h" #include "base/utils/utils.h" #include "core/components/common/layout/constants.h" +#include "core/components_ng/pattern/grid/grid_layout_property.h" #include "core/components_ng/property/measure_utils.h" namespace OHOS::Ace::NG { @@ -29,6 +30,8 @@ public: ~GridUtils() = delete; static std::vector ParseArgs(const std::string& args, float size, float gap); + static float GetMainGap(const RefPtr& gridLayoutProperty, const SizeF& frameSize, Axis axis); + static float GetCrossGap(const RefPtr& gridLayoutProperty, const SizeF& frameSize, Axis axis); }; } // namespace OHOS::Ace::NG -- Gitee