1 /* 2 * Copyright (c) 2022-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_SCROLL_GRID_SCROLL_LAYOUT_ALGORITHM_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_SCROLL_GRID_SCROLL_LAYOUT_ALGORITHM_H 18 19 #include "core/components_ng/pattern/grid/grid_item_layout_property.h" 20 #include "core/components_ng/pattern/grid/grid_layout_base_algorithm.h" 21 #include "core/components_ng/pattern/grid/grid_layout_info.h" 22 #include "core/components_ng/pattern/grid/grid_layout_property.h" 23 #include "core/components_ng/pattern/scrollable/scrollable_properties.h" 24 25 namespace OHOS::Ace::NG { 26 class ACE_EXPORT GridScrollLayoutAlgorithm : public GridLayoutBaseAlgorithm { 27 DECLARE_ACE_TYPE(GridScrollLayoutAlgorithm, GridLayoutBaseAlgorithm); 28 29 public: GridScrollLayoutAlgorithm(GridLayoutInfo gridLayoutInfo,uint32_t crossCount,uint32_t mainCount)30 GridScrollLayoutAlgorithm(GridLayoutInfo gridLayoutInfo, uint32_t crossCount, uint32_t mainCount) 31 : GridLayoutBaseAlgorithm(std::move(gridLayoutInfo)), crossCount_(crossCount), mainCount_(mainCount) {}; 32 ~GridScrollLayoutAlgorithm() override = default; 33 34 void Measure(LayoutWrapper* layoutWrapper) override; 35 void Layout(LayoutWrapper* layoutWrapper) override; 36 SetCanOverScrollStart(bool canOverScroll)37 void SetCanOverScrollStart(bool canOverScroll) 38 { 39 canOverScrollStart_ = canOverScroll; 40 } 41 SetCanOverScrollEnd(bool canOverScroll)42 void SetCanOverScrollEnd(bool canOverScroll) 43 { 44 canOverScrollEnd_ = canOverScroll; 45 } 46 SetScrollSource(int32_t scrollSource)47 void SetScrollSource(int32_t scrollSource) 48 { 49 scrollSource_ = scrollSource; 50 } 51 52 /** 53 * @brief Set enableSkipping_ parameter. When skip is enabled, the algorithm would skip measuring intermediate items 54 * when the offset change is large (larger than the whole viewport). 55 * 56 * @param skip 57 */ SetLineSkipping(bool skip)58 void SetLineSkipping(bool skip) 59 { 60 enableSkipping_ = skip; 61 } 62 MoveInfoCopy()63 std::unique_ptr<GridLayoutInfo>&& MoveInfoCopy() 64 { 65 return std::move(infoCopy_); 66 } 67 68 template<class T> DeleteItemsOutOfScope(std::map<int32_t,T> & map,int32_t startLineIndex,int32_t endLineIndex)69 void DeleteItemsOutOfScope(std::map<int32_t, T>& map, int32_t startLineIndex, int32_t endLineIndex) 70 { 71 auto iter = map.begin(); 72 while (iter != map.end()) { 73 if (iter->first < startLineIndex || iter->first > endLineIndex) { 74 iter = map.erase(iter); 75 } else { 76 ++iter; 77 } 78 } 79 } 80 81 protected: 82 void SkipForwardLines(float mainSize, LayoutWrapper* layoutWrapper); 83 void SkipBackwardLines(float mainSize, LayoutWrapper* layoutWrapper); 84 void SkipRegularLines(bool forward); 85 virtual void SkipIrregularLines(LayoutWrapper* layoutWrapper, bool forward); 86 87 private: 88 void FillGridViewportAndMeasureChildren(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 89 void ReloadToStartIndex(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 90 void ReloadFromUpdateIdxToStartIndex( 91 float mainSize, float crossSize, int32_t updateLineIndex, LayoutWrapper* layoutWrapper); 92 float MeasureRecordedItems(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 93 bool UseCurrentLines(float mainSize, float crossSize, LayoutWrapper* layoutWrapper, float& mainLength); 94 virtual void SkipLargeOffset(float mainSize, LayoutWrapper* layoutWrapper); 95 96 // fill start of viewport 97 bool FillBlankAtStart(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 98 float FillNewLineForward(float crossSize, float mainSize, LayoutWrapper* layoutWrapper); 99 void AddForwardLines(int32_t currentIndex, float crossSize, float mainSize, LayoutWrapper* layoutWrapper); 100 void UpdateMatrixForAddedItems(); 101 // Fill forward one line, but do not update startMainLineIndex_ and startIndex_ 102 virtual void FillOneLineForwardWithoutUpdatingStartIndex( 103 float crossSize, float mainSize, LayoutWrapper* layoutWrapper); 104 105 // fill end of viewport 106 void FillBlankAtEnd(float mainSize, float crossSize, LayoutWrapper* layoutWrapper, float& mainLength); 107 float FillNewLineBackward(float crossSize, float mainSize, LayoutWrapper* layoutWrapper, bool reverse); 108 void FillCurrentLine(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 109 110 // Measure grid item which not exist in grid matrix already, need to place it and save to grid matrix. 111 int32_t MeasureNewChild(const SizeF& frameSize, int32_t itemIndex, LayoutWrapper* layoutWrapper, 112 const RefPtr<LayoutWrapper>& childLayoutWrapper, bool reverse); 113 // Measure grid item which exist in grid matrix already, needn't to place it again. 114 int32_t MeasureChildPlaced(const SizeF& frameSize, int32_t itemIndex, int32_t crossStart, 115 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& childLayoutWrapper); 116 bool CheckNeedMeasure(const RefPtr<LayoutWrapper>& layoutWrapper, const LayoutConstraintF& layoutConstraint) const; 117 bool CheckNeedMeasureWhenStretch( 118 const RefPtr<LayoutWrapper>& layoutWrapper, const LayoutConstraintF& layoutConstraint) const; 119 void MeasureChild(LayoutWrapper* layoutWrapper, const SizeF& frameSize, 120 const RefPtr<LayoutWrapper>& childLayoutWrapper, int32_t crossStart, int32_t crossSpan); 121 122 // Compote position of grid item in cross axis. 123 float ComputeItemCrossPosition(int32_t crossStart) const; 124 virtual void LargeItemLineHeight(const RefPtr<LayoutWrapper>& itemWrapper); 125 // Find next valid cell when current is not valid. 126 bool GetNextGrid(int32_t& curMain, int32_t& curCross, bool reverse) const; 127 // Find a valid cell to place grid item and save to grid matrix. 128 bool CheckGridPlaced(int32_t index, int32_t main, int32_t cross, int32_t mainSpan, int32_t crossSpan); 129 LayoutConstraintF CreateChildConstraint(float mainSize, float crossSize, 130 const RefPtr<GridLayoutProperty>& gridLayoutProperty, int32_t crossStart, int32_t crossSpan) const; 131 void ModifyCurrentOffsetWhenReachEnd(float mainSize, LayoutWrapper* layoutWrapper); 132 void InitialItemsCrossSize( 133 const RefPtr<GridLayoutProperty>& layoutProperty, const SizeF& frameSize, int32_t childrenCount); 134 bool IsIndexInMatrix(int32_t index, int32_t& startLine); 135 void UpdateGridLayoutInfo(LayoutWrapper* layoutWrapper, float mainSize); 136 virtual void GetTargetIndexInfoWithBenchMark( 137 LayoutWrapper* layoutWrapper, bool isTargetBackward, int32_t targetIndex); 138 139 void UpdateOffsetOnVirtualKeyboardHeightChange(LayoutWrapper* layoutWrapper, float mainSize); 140 void AdaptToChildMainSize(LayoutWrapper* layoutWrapper, RefPtr<GridLayoutProperty>& gridLayoutProperty, 141 float mainSize, SizeF idealSize, bool matchChildren); 142 void UpdateOffsetOnHeightChangeDuringAnimation(LayoutWrapper* layoutWrapper, float mainSize); 143 144 virtual int32_t GetStartingItem(LayoutWrapper* layoutWrapper, int32_t currentIndex); 145 146 OffsetF CalculateLargeItemOffset( 147 OffsetF currOffset, int32_t itemIndex, int32_t currLineIndex, int32_t currentCrossIndex); 148 bool NeedAdjust(const RefPtr<GridItemLayoutProperty>& itemLayoutWrapper); 149 virtual void AdjustRowColSpan( 150 const RefPtr<LayoutWrapper>& itemLayoutWrapper, LayoutWrapper* layoutWrapper, int32_t itemIndex); 151 void LargeItemNextLineHeight(int32_t currentLineIndex, LayoutWrapper* layoutWrapper); 152 void LargeItemForwardLineHeight(int32_t currentLineIndex, LayoutWrapper* LayoutWrapper); 153 int32_t CalculateLineIndexForLargeItem(std::map<int32_t, std::map<int32_t, int32_t>>::iterator gridMatrixIter, 154 int32_t currentIndex, int32_t lineIndex, LayoutWrapper* layoutWrapper); 155 void CalculateLineHeightForLargeItem(int32_t lineIndex, int32_t currentLineIndex, 156 std::map<int32_t, std::map<int32_t, int32_t>>::iterator gridMatrixIter, LayoutWrapper* layoutWrapper); 157 void ScrollToIndexStart(LayoutWrapper* layoutWrapper, int32_t targetIndex); 158 void ScrollToIndexAuto(LayoutWrapper* layoutWrapper, float mainSize, int32_t targetIndex); 159 bool IsScrollToEndLine() const; 160 bool IsEndLineInScreenWithGap(int32_t targetLine, float totalViewHeight, float mainSize) const; 161 void UpdateCurrentOffsetForJumpTo(float mainSize); 162 void SupplyAllData2ZeroIndex(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 163 164 void FillCacheLineAtEnd(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 165 float FillNewCacheLineBackward(float crossSize, float mainSize, LayoutWrapper* layoutWrapper, int32_t currentLine); 166 int32_t MeasureCachedChild(const SizeF& frameSize, int32_t itemIndex, LayoutWrapper* layoutWrapper, 167 const RefPtr<LayoutWrapper>& childLayoutWrapper); 168 169 void CreateCachedChildConstraint(LayoutWrapper* layoutWrapper, float mainSize, float crossSize); 170 171 static bool PredictBuildItem(FrameNode& host, int32_t itemIdx, const GridPredictLayoutParam& param); 172 static void SyncGeometry(RefPtr<LayoutWrapper>& wrapper); 173 void CompleteItemCrossPosition(LayoutWrapper* layoutWrapper, const std::map<int32_t, int32_t>& items); 174 /** 175 * @brief Updates the main line during ReloadToStartIndex based on the new crossCount_. 176 * 177 * @param startIdx index of the first GridItem in viewport 178 */ 179 virtual void UpdateMainLineOnReload(int32_t startIdx); 180 181 // get [resetFromStart,resetFromUpdate] 182 std::pair<bool, bool> GetResetMode(LayoutWrapper* layoutWrapper, int32_t updateIdx); 183 184 void CheckReset(float mainSize, float crossSize, LayoutWrapper* layoutWrapper); 185 186 bool CheckLastLineItemFullyShowed(LayoutWrapper* layoutWrapper); 187 188 void ResetOffsetWhenHeightChanged(); 189 190 bool IsIrregularLine(int32_t lineIndex) const override; 191 192 void MergeRemainingLines(std::map<int32_t, std::map<int32_t, int32_t>> matrix, int32_t forwardLines); 193 194 bool SkipLargeLineHeightLines(float mainSize); 195 196 /** 197 * @brief immediately create & measure items in cache range. 198 * 199 * @param cacheLineCnt number of lines to preload above and below viewport. 200 */ 201 void SyncPreload(LayoutWrapper* wrapper, int32_t cacheLineCnt, float crossSize, float mainSize); 202 CalculateCachedCount(LayoutWrapper * layoutWrapper,int32_t cachedCount)203 virtual std::pair<int32_t, int32_t> CalculateCachedCount(LayoutWrapper* layoutWrapper, int32_t cachedCount) 204 { 205 return std::make_pair(cachedCount * crossCount_, cachedCount * crossCount_); 206 } 207 GetReloadReasonStr(GridReloadReason reason)208 std::string GetReloadReasonStr(GridReloadReason reason) 209 { 210 switch (reason) { 211 case GridReloadReason::INIT: 212 return "init"; 213 case GridReloadReason::CROSS_COUNT_CHANGE: 214 return "cross count change"; 215 case GridReloadReason::DATA_RELOAD: 216 return "data reload"; 217 case GridReloadReason::SCROLL_TO_INDEX: 218 return "scroll to index"; 219 case GridReloadReason::SKIP_LARGE_OFFSET: 220 return "skip large offset"; 221 default: 222 return ""; 223 } 224 } 225 226 bool HasLayoutOptions(LayoutWrapper* layoutWrapper); 227 228 virtual void PreloadItems(LayoutWrapper* layoutWrapper); 229 230 void ClearUnlayoutedItems(LayoutWrapper* layoutWrapper); 231 232 protected: 233 uint32_t crossCount_ = 0; 234 uint32_t mainCount_ = 0; 235 int32_t currentItemRowSpan_ = 0; 236 int32_t currentItemColSpan_ = 0; 237 int32_t currentItemRowStart_ = -1; 238 int32_t currentItemColStart_ = -1; 239 int32_t currentItemRowEnd_ = -1; 240 int32_t currentItemColEnd_ = -1; 241 float cellAveLength_ = -1.0f; 242 float mainGap_ = 0; 243 float crossGap_ = 0; 244 std::map<int32_t, float> itemsCrossSize_; // grid item's size in cross axis. 245 std::list<GridPreloadItem> predictBuildList_; 246 LayoutConstraintF cachedChildConstraint_; 247 std::set<int32_t> measuredItems_; 248 249 private: 250 /** 251 * @brief Measure items on a line previously recorded 252 * 253 * @param line index of line to measure 254 * updates @param mainLength by adding this line's measured height 255 * updates @param endIdx with max item index in this line 256 * @return false if line isn't recorded. 257 */ 258 bool MeasureExistingLine(int32_t line, float& mainLength, int32_t& endIdx); 259 260 LayoutWrapper* wrapper_; 261 SizeF frameSize_; 262 int32_t currentMainLineIndex_ = 0; // it equals to row index in vertical grid 263 int32_t moveToEndLineIndex_ = -1; // place index in the last line when scroll to index after matrix 264 Axis axis_ = Axis::VERTICAL; 265 266 float crossPaddingOffset_ = 0; 267 int32_t lastCross_ = 0; 268 bool isChildrenUpdated_ = false; 269 270 bool expandSafeArea_ = false; 271 bool canOverScrollStart_ = false; 272 bool canOverScrollEnd_ = false; 273 bool enableSkipping_ = true; // enables skipping lines on a large offset change. 274 std::unique_ptr<GridLayoutInfo> infoCopy_; // legacy impl to save independent data for animation. 275 276 // Map structure: [index, crossPosition], store cross position of each item. 277 std::map<int32_t, float> itemsCrossPosition_; 278 int32_t scrollSource_ = SCROLL_FROM_NONE; 279 OffsetF childFrameOffset_; 280 GridReloadReason reason_; 281 282 ACE_DISALLOW_COPY_AND_MOVE(GridScrollLayoutAlgorithm); 283 }; 284 285 } // namespace OHOS::Ace::NG 286 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_SCROLL_GRID_SCROLL_LAYOUT_ALGORITHM_H 287