1 /*
2 * Copyright (c) 2022-2024 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 #include "core/components_ng/pattern/grid/grid_pattern.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/perfmonitor/perf_constants.h"
20 #include "base/perfmonitor/perf_monitor.h"
21 #include "core/components_ng/base/observer_handler.h"
22 #include "core/components_ng/pattern/grid/grid_adaptive/grid_adaptive_layout_algorithm.h"
23 #include "core/components_ng/pattern/grid/grid_layout/grid_layout_algorithm.h"
24 #include "core/components_ng/pattern/grid/grid_paint_method.h"
25 #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_with_options_layout_algorithm.h"
26 #include "core/components_ng/pattern/grid/grid_utils.h"
27 #include "core/components_ng/pattern/grid/irregular/grid_irregular_layout_algorithm.h"
28 #include "core/components_ng/pattern/grid/irregular/grid_layout_utils.h"
29 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
30
31 namespace OHOS::Ace::NG {
32
33 namespace {
34 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
35
36 const int32_t MAX_NUM_SIZE = 4;
37 } // namespace
38
CreateLayoutAlgorithm()39 RefPtr<LayoutAlgorithm> GridPattern::CreateLayoutAlgorithm()
40 {
41 auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
42 CHECK_NULL_RETURN(gridLayoutProperty, nullptr);
43 std::vector<std::string> cols;
44 StringUtils::StringSplitter(gridLayoutProperty->GetColumnsTemplate().value_or(""), ' ', cols);
45 std::vector<std::string> rows;
46 StringUtils::StringSplitter(gridLayoutProperty->GetRowsTemplate().value_or(""), ' ', rows);
47
48 // When rowsTemplate and columnsTemplate is both not setting, use adaptive layout algorithm.
49 if (rows.empty() && cols.empty()) {
50 return MakeRefPtr<GridAdaptiveLayoutAlgorithm>(info_);
51 }
52
53 auto crossCount = cols.empty() ? Infinity<int32_t>() : static_cast<int32_t>(cols.size());
54 auto mainCount = rows.empty() ? Infinity<int32_t>() : static_cast<int32_t>(rows.size());
55 if (!gridLayoutProperty->IsVertical()) {
56 std::swap(crossCount, mainCount);
57 }
58 info_.crossCount_ = crossCount;
59 if (targetIndex_.has_value()) {
60 info_.targetIndex_ = targetIndex_;
61 }
62 // When rowsTemplate and columnsTemplate is both setting, use static layout algorithm.
63 if (!rows.empty() && !cols.empty()) {
64 return MakeRefPtr<GridLayoutAlgorithm>(info_, crossCount, mainCount);
65 }
66
67 // If only set one of rowTemplate and columnsTemplate, use scrollable layout algorithm.
68 const bool disableSkip = IsOutOfBoundary(true) || (ScrollablePattern::AnimateRunning() && !IsBackToTopRunning());
69 const bool canOverScrollStart = CanOverScrollStart(GetScrollSource()) || preSpring_;
70 const bool canOverScrollEnd = CanOverScrollEnd(GetScrollSource()) || preSpring_;
71 if (UseIrregularLayout()) {
72 auto algo = MakeRefPtr<GridIrregularLayoutAlgorithm>(info_, canOverScrollStart, canOverScrollEnd);
73 algo->SetEnableSkip(!disableSkip);
74 return algo;
75 }
76 RefPtr<GridScrollLayoutAlgorithm> result;
77 if (!gridLayoutProperty->GetLayoutOptions().has_value()) {
78 result = MakeRefPtr<GridScrollLayoutAlgorithm>(info_, crossCount, mainCount);
79 } else {
80 result = MakeRefPtr<GridScrollWithOptionsLayoutAlgorithm>(info_, crossCount, mainCount);
81 }
82 result->SetCanOverScrollStart(canOverScrollStart);
83 result->SetCanOverScrollEnd(canOverScrollEnd);
84 result->SetScrollSource(GetScrollSource());
85 if (ScrollablePattern::AnimateRunning()) {
86 result->SetLineSkipping(!disableSkip);
87 }
88 return result;
89 }
90
BeforeCreateLayoutWrapper()91 void GridPattern::BeforeCreateLayoutWrapper()
92 {
93 auto host = GetHost();
94 CHECK_NULL_VOID(host);
95 info_.childrenCount_ = host->GetTotalChildCount();
96 }
97
CreatePaintProperty()98 RefPtr<PaintProperty> GridPattern::CreatePaintProperty()
99 {
100 auto defaultDisplayMode = GetDefaultScrollBarDisplayMode();
101 auto property = MakeRefPtr<GridPaintProperty>();
102 property->UpdateScrollBarMode(defaultDisplayMode);
103 return property;
104 }
105
CreateNodePaintMethod()106 RefPtr<NodePaintMethod> GridPattern::CreateNodePaintMethod()
107 {
108 auto paint = MakeRefPtr<GridPaintMethod>(GetAxis() == Axis::HORIZONTAL, IsReverse(), GetScrollBar());
109 CHECK_NULL_RETURN(paint, nullptr);
110 paint->SetScrollBarOverlayModifier(GetScrollBarOverlayModifier());
111 auto scrollEffect = GetScrollEdgeEffect();
112 if (scrollEffect && scrollEffect->IsFadeEffect()) {
113 paint->SetEdgeEffect(scrollEffect);
114 }
115 if (!gridContentModifier_) {
116 gridContentModifier_ = AceType::MakeRefPtr<GridContentModifier>();
117 }
118 paint->SetContentModifier(gridContentModifier_);
119 UpdateFadingEdge(paint);
120 return paint;
121 }
122
OnModifyDone()123 void GridPattern::OnModifyDone()
124 {
125 Pattern::OnModifyDone();
126 auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
127 CHECK_NULL_VOID(gridLayoutProperty);
128
129 if (multiSelectable_ && !isMouseEventInit_) {
130 InitMouseEvent();
131 }
132
133 if (!multiSelectable_ && isMouseEventInit_) {
134 UninitMouseEvent();
135 }
136
137 info_.axis_ = gridLayoutProperty->IsVertical() ? Axis::VERTICAL : Axis::HORIZONTAL;
138 isConfigScrollable_ = gridLayoutProperty->IsConfiguredScrollable();
139 if (!isConfigScrollable_) {
140 return;
141 }
142 SetAxis(info_.axis_);
143 if (!GetScrollableEvent()) {
144 AddScrollEvent();
145 #ifdef SUPPORT_DIGITAL_CROWN
146 SetDigitalCrownEvent();
147 #endif
148 }
149
150 SetEdgeEffect();
151
152 auto paintProperty = GetPaintProperty<ScrollablePaintProperty>();
153 CHECK_NULL_VOID(paintProperty);
154 if (paintProperty->GetScrollBarProperty()) {
155 SetScrollBar(paintProperty->GetScrollBarProperty());
156 }
157
158 auto host = GetHost();
159 CHECK_NULL_VOID(host);
160 auto focusHub = host->GetFocusHub();
161 if (focusHub) {
162 InitOnKeyEvent(focusHub);
163 }
164 SetAccessibilityAction();
165 Register2DragDropManager();
166 auto overlayNode = host->GetOverlayNode();
167 if (!overlayNode && paintProperty->GetFadingEdge().value_or(false)) {
168 CreateAnalyzerOverlay(host);
169 }
170 }
171
MultiSelectWithoutKeyboard(const RectF & selectedZone)172 void GridPattern::MultiSelectWithoutKeyboard(const RectF& selectedZone)
173 {
174 auto host = GetHost();
175 CHECK_NULL_VOID(host);
176 std::list<RefPtr<FrameNode>> children;
177 host->GenerateOneDepthVisibleFrame(children);
178 for (const auto& itemFrameNode : children) {
179 auto itemEvent = itemFrameNode->GetEventHub<EventHub>();
180 CHECK_NULL_VOID(itemEvent);
181 if (!itemEvent->IsEnabled()) {
182 continue;
183 }
184
185 auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
186 CHECK_NULL_VOID(itemPattern);
187 if (!itemPattern->Selectable()) {
188 continue;
189 }
190 auto itemGeometry = itemFrameNode->GetGeometryNode();
191 CHECK_NULL_VOID(itemGeometry);
192 auto context = itemFrameNode->GetRenderContext();
193 CHECK_NULL_VOID(context);
194
195 auto itemRect = itemGeometry->GetFrameRect();
196 auto iter = itemToBeSelected_.find(itemFrameNode->GetId());
197 if (iter == itemToBeSelected_.end()) {
198 auto result = itemToBeSelected_.emplace(itemFrameNode->GetId(), ItemSelectedStatus());
199 iter = result.first;
200 iter->second.onSelected = itemPattern->GetEventHub<GridItemEventHub>()->GetOnSelect();
201 iter->second.selectChangeEvent = itemPattern->GetEventHub<GridItemEventHub>()->GetSelectChangeEvent();
202 }
203 auto startMainOffset = mouseStartOffset_.GetMainOffset(info_.axis_);
204 if (info_.axis_ == Axis::VERTICAL) {
205 iter->second.rect = itemRect + OffsetF(0, totalOffsetOfMousePressed_ - startMainOffset);
206 } else {
207 iter->second.rect = itemRect + OffsetF(totalOffsetOfMousePressed_ - startMainOffset, 0);
208 }
209
210 if (!selectedZone.IsIntersectWith(itemRect)) {
211 itemPattern->MarkIsSelected(false);
212 iter->second.selected = false;
213 context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
214 } else {
215 itemPattern->MarkIsSelected(true);
216 iter->second.selected = true;
217 context->OnMouseSelectUpdate(true, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
218 }
219 }
220
221 DrawSelectedZone(selectedZone);
222 }
223
ClearMultiSelect()224 void GridPattern::ClearMultiSelect()
225 {
226 auto host = GetHost();
227 CHECK_NULL_VOID(host);
228 std::list<RefPtr<FrameNode>> children;
229 host->GenerateOneDepthAllFrame(children);
230 for (const auto& item : children) {
231 if (!AceType::InstanceOf<FrameNode>(item)) {
232 continue;
233 }
234
235 auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
236 auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
237 CHECK_NULL_VOID(itemPattern);
238 auto selectedStatus = itemToBeSelected_.find(itemFrameNode->GetId());
239 if (selectedStatus != itemToBeSelected_.end()) {
240 selectedStatus->second.selected = false;
241 }
242 itemPattern->MarkIsSelected(false);
243 auto renderContext = itemFrameNode->GetRenderContext();
244 CHECK_NULL_VOID(renderContext);
245 renderContext->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
246 }
247
248 ClearSelectedZone();
249 }
250
IsItemSelected(float offsetX,float offsetY)251 bool GridPattern::IsItemSelected(float offsetX, float offsetY)
252 {
253 auto host = GetHost();
254 CHECK_NULL_RETURN(host, false);
255 auto node = host->FindChildByPosition(offsetX, offsetY);
256 CHECK_NULL_RETURN(node, false);
257 auto itemPattern = node->GetPattern<GridItemPattern>();
258 CHECK_NULL_RETURN(itemPattern, false);
259 return itemPattern->IsSelected();
260 }
261
FireOnScrollStart()262 void GridPattern::FireOnScrollStart()
263 {
264 ScrollablePattern::RecordScrollEvent(Recorder::EventType::SCROLL_START);
265 UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
266 AceType::WeakClaim(this), ScrollEventType::SCROLL_START);
267 SuggestOpIncGroup(true);
268 PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_LIST_FLING, PerfActionType::FIRST_MOVE, "");
269 if (GetScrollAbort()) {
270 return;
271 }
272 if (scrollStop_) {
273 // onScrollStart triggers immediately on gesture dragStart, but onScrollStop marks scrollStop_ to true on
274 // gesture dragEnd, and consumes it/fires onScrollStop after layout. When the user quickly swipes twice, the
275 // second onScrollStart can trigger before the first onScrollEnd. In this case, we let the two events annihilate
276 // each other and fire neither.
277 scrollStop_ = false;
278 return;
279 }
280 auto scrollBar = GetScrollBar();
281 if (scrollBar) {
282 scrollBar->PlayScrollBarAppearAnimation();
283 }
284 StopScrollBarAnimatorByProxy();
285 FireObserverOnScrollStart();
286 auto pipeline = GetContext();
287 if (pipeline) {
288 pipeline->GetFocusManager()->SetNeedTriggerScroll(std::nullopt);
289 }
290 auto host = GetHost();
291 CHECK_NULL_VOID(host);
292 auto hub = host->GetEventHub<GridEventHub>();
293 CHECK_NULL_VOID(hub);
294 auto onScrollStart = hub->GetOnScrollStart();
295 CHECK_NULL_VOID(onScrollStart);
296 onScrollStart();
297 }
298
FireOnReachStart(const OnReachEvent & onReachStart)299 void GridPattern::FireOnReachStart(const OnReachEvent& onReachStart)
300 {
301 auto host = GetHost();
302 CHECK_NULL_VOID(host);
303 if (info_.startIndex_ == 0) {
304 if (!isInitialized_) {
305 FireObserverOnReachStart();
306 if (onReachStart) {
307 onReachStart();
308 AddEventsFiredInfo(ScrollableEventType::ON_REACH_START);
309 }
310 }
311 auto finalOffset = info_.currentHeight_ - info_.prevHeight_;
312 if (!NearZero(finalOffset)) {
313 bool scrollUpToStart = GreatOrEqual(info_.prevHeight_, 0.0) && LessOrEqual(info_.currentHeight_, 0.0);
314 bool scrollDownToStart = LessNotEqual(info_.prevHeight_, 0.0) && GreatOrEqual(info_.currentHeight_, 0.0);
315 if (scrollUpToStart || scrollDownToStart) {
316 FireObserverOnReachStart();
317 CHECK_NULL_VOID(onReachStart);
318 ACE_SCOPED_TRACE("OnReachStart, scrollUpToStart:%u, scrollDownToStart:%u, id:%d, tag:Grid",
319 scrollUpToStart, scrollDownToStart, static_cast<int32_t>(host->GetAccessibilityId()));
320 onReachStart();
321 AddEventsFiredInfo(ScrollableEventType::ON_REACH_START);
322 }
323 }
324 }
325 }
326
FireOnReachEnd(const OnReachEvent & onReachEnd)327 void GridPattern::FireOnReachEnd(const OnReachEvent& onReachEnd)
328 {
329 auto host = GetHost();
330 CHECK_NULL_VOID(host);
331 if (info_.endIndex_ == (info_.childrenCount_ - 1)) {
332 if (!isInitialized_) {
333 FireObserverOnReachEnd();
334 }
335 auto finalOffset = info_.currentHeight_ - info_.prevHeight_;
336 if (!NearZero(finalOffset)) {
337 bool scrollDownToEnd =
338 LessNotEqual(info_.prevHeight_, endHeight_) && GreatOrEqual(info_.currentHeight_, endHeight_);
339 bool scrollUpToEnd =
340 GreatNotEqual(info_.prevHeight_, endHeight_) && LessOrEqual(info_.currentHeight_, endHeight_);
341 if (scrollDownToEnd || scrollUpToEnd) {
342 FireObserverOnReachEnd();
343 CHECK_NULL_VOID(onReachEnd);
344 ACE_SCOPED_TRACE("OnReachEnd, scrollUpToEnd:%u, scrollDownToEnd:%u, id:%d, tag:Grid", scrollUpToEnd,
345 scrollDownToEnd, static_cast<int32_t>(host->GetAccessibilityId()));
346 onReachEnd();
347 AddEventsFiredInfo(ScrollableEventType::ON_REACH_END);
348 }
349 }
350 }
351 }
352
FireOnScrollIndex(bool indexChanged,const ScrollIndexFunc & onScrollIndex)353 void GridPattern::FireOnScrollIndex(bool indexChanged, const ScrollIndexFunc& onScrollIndex)
354 {
355 CHECK_NULL_VOID(indexChanged && onScrollIndex);
356 onScrollIndex(info_.startIndex_, info_.endIndex_);
357 }
358
GetContentSize() const359 SizeF GridPattern::GetContentSize() const
360 {
361 auto host = GetHost();
362 CHECK_NULL_RETURN(host, SizeF());
363 auto geometryNode = host->GetGeometryNode();
364 CHECK_NULL_RETURN(geometryNode, SizeF());
365 return geometryNode->GetPaddingSize();
366 }
367
GetMainGap() const368 float GridPattern::GetMainGap() const
369 {
370 float mainGap = 0.0;
371 auto host = GetHost();
372 CHECK_NULL_RETURN(host, 0.0);
373 auto geometryNode = host->GetGeometryNode();
374 CHECK_NULL_RETURN(geometryNode, 0.0);
375 auto viewScopeSize = geometryNode->GetPaddingSize();
376 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
377 mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info_.axis_);
378 return mainGap;
379 }
380
IsFadingBottom() const381 bool GridPattern::IsFadingBottom() const
382 {
383 float mainSize = info_.lastMainSize_ - info_.contentEndPadding_;
384 if (info_.startIndex_ == 0 && (info_.endIndex_ == info_.childrenCount_ - 1) &&
385 LessNotEqual(info_.totalHeightOfItemsInView_, mainSize)) {
386 return Positive(info_.currentOffset_);
387 } else {
388 return !info_.offsetEnd_;
389 }
390 }
391
UpdateCurrentOffset(float offset,int32_t source)392 bool GridPattern::UpdateCurrentOffset(float offset, int32_t source)
393 {
394 if (!isConfigScrollable_ || !scrollable_) {
395 return true;
396 }
397
398 auto host = GetHost();
399 CHECK_NULL_RETURN(host, false);
400
401 // check edgeEffect is not springEffect
402 if (!HandleEdgeEffect(offset, source, GetContentSize())) {
403 if (IsOutOfBoundary(true)) {
404 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
405 }
406 return false;
407 }
408 SetScrollSource(source);
409 FireAndCleanScrollingListener();
410 if (info_.synced_) {
411 info_.prevOffset_ = info_.currentOffset_;
412 info_.synced_ = false;
413 }
414 // When finger moves down, offset is positive.
415 // When finger moves up, offset is negative.
416 bool irregular = UseIrregularLayout();
417 float mainGap = GetMainGap();
418 auto itemsHeight = info_.GetTotalHeightOfItemsInView(mainGap, irregular);
419 if (info_.offsetEnd_) {
420 if (source == SCROLL_FROM_UPDATE) {
421 float overScroll = 0.0f;
422 if (irregular) {
423 overScroll = info_.GetDistanceToBottom(GetMainContentSize(), itemsHeight, mainGap);
424 } else {
425 overScroll = info_.currentOffset_ - (GetMainContentSize() - itemsHeight);
426 }
427 auto friction = CalculateFriction(std::abs(overScroll) / GetMainContentSize());
428 offset *= friction;
429 }
430 auto userOffset = FireOnWillScroll(-offset);
431 info_.currentOffset_ -= userOffset;
432
433 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
434
435 if (GreatNotEqual(info_.currentOffset_, GetMainContentSize() - itemsHeight)) {
436 info_.offsetEnd_ = false;
437 info_.reachEnd_ = false;
438 }
439
440 return true;
441 }
442 if (info_.reachStart_) {
443 if (source == SCROLL_FROM_UPDATE) {
444 auto friction = CalculateFriction(std::abs(info_.currentOffset_) / GetMainContentSize());
445 offset *= friction;
446 }
447 auto userOffset = FireOnWillScroll(-offset);
448 info_.currentOffset_ -= userOffset;
449
450 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
451
452 if (LessNotEqual(info_.currentOffset_, 0.0)) {
453 info_.reachStart_ = false;
454 }
455 return true;
456 }
457 auto userOffset = FireOnWillScroll(-offset);
458 info_.currentOffset_ -= userOffset;
459 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
460 return true;
461 }
462
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)463 bool GridPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
464 {
465 if (config.skipMeasure && config.skipLayout) {
466 return false;
467 }
468 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
469 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
470 auto gridLayoutAlgorithm = DynamicCast<GridLayoutBaseAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
471 CHECK_NULL_RETURN(gridLayoutAlgorithm, false);
472 const auto& gridLayoutInfo = gridLayoutAlgorithm->GetGridLayoutInfo();
473 auto eventhub = GetEventHub<GridEventHub>();
474 CHECK_NULL_RETURN(eventhub, false);
475 Dimension offset(0, DimensionUnit::VP);
476 Dimension offsetPx(gridLayoutInfo.currentOffset_, DimensionUnit::PX);
477 auto offsetVpValue = offsetPx.ConvertToVp();
478 offset.SetValue(offsetVpValue);
479 scrollbarInfo_ = eventhub->FireOnScrollBarUpdate(gridLayoutInfo.startIndex_, offset);
480 if (!isInitialized_ || info_.startIndex_ != gridLayoutInfo.startIndex_) {
481 eventhub->FireOnScrollToIndex(gridLayoutInfo.startIndex_);
482 }
483
484 bool indexChanged =
485 (gridLayoutInfo.startIndex_ != info_.startIndex_) || (gridLayoutInfo.endIndex_ != info_.endIndex_);
486 bool offsetEnd = info_.offsetEnd_;
487 info_ = gridLayoutInfo;
488 info_.synced_ = true;
489 AnimateToTarget(scrollAlign_, layoutAlgorithmWrapper);
490
491 info_.reachStart_ = info_.startIndex_ == 0 && GreatOrEqual(info_.currentOffset_, 0.0f);
492
493 auto curDelta = info_.currentOffset_ - info_.prevOffset_;
494 info_.currentHeight_ = EstimateHeight();
495 bool sizeDiminished =
496 IsOutOfBoundary(true) && !NearZero(curDelta) && (info_.prevHeight_ - info_.currentHeight_ - curDelta > 0.1f);
497
498 if (!offsetEnd && info_.offsetEnd_) {
499 endHeight_ = info_.currentHeight_;
500 }
501 ProcessEvent(indexChanged, info_.currentHeight_ - info_.prevHeight_);
502 info_.prevHeight_ = info_.currentHeight_;
503 info_.extraOffset_.reset();
504 UpdateScrollBarOffset();
505 SetScrollSource(SCROLL_FROM_NONE);
506 if (config.frameSizeChange) {
507 if (GetScrollBar() != nullptr) {
508 GetScrollBar()->ScheduleDisappearDelayTask();
509 }
510 }
511 if (!preSpring_) {
512 CheckRestartSpring(sizeDiminished);
513 }
514 CheckScrollable();
515 MarkSelectedItems();
516 isInitialized_ = true;
517 auto paintProperty = GetPaintProperty<ScrollablePaintProperty>();
518 CHECK_NULL_RETURN(paintProperty, false);
519 return paintProperty->GetFadingEdge().value_or(false) || paintProperty->HasContentClip();
520 }
521
CheckScrollable()522 void GridPattern::CheckScrollable()
523 {
524 auto host = GetHost();
525 CHECK_NULL_VOID(host);
526 auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
527 CHECK_NULL_VOID(gridLayoutProperty);
528 if (((info_.endIndex_ - info_.startIndex_ + 1) < info_.childrenCount_) ||
529 (info_.GetTotalHeightOfItemsInView(GetMainGap()) > GetMainContentSize())) {
530 scrollable_ = true;
531 } else {
532 scrollable_ = info_.startMainLineIndex_ != 0 || GetAlwaysEnabled();
533 }
534
535 SetScrollEnabled(scrollable_);
536
537 if (!gridLayoutProperty->GetScrollEnabled().value_or(scrollable_)) {
538 SetScrollEnabled(false);
539 }
540 }
541
ProcessEvent(bool indexChanged,float finalOffset)542 void GridPattern::ProcessEvent(bool indexChanged, float finalOffset)
543 {
544 auto host = GetHost();
545 CHECK_NULL_VOID(host);
546 auto gridEventHub = host->GetEventHub<GridEventHub>();
547 CHECK_NULL_VOID(gridEventHub);
548
549 auto onScroll = gridEventHub->GetOnScroll();
550 PrintOffsetLog(AceLogTag::ACE_GRID, host->GetId(), finalOffset);
551 if (onScroll) {
552 FireOnScroll(finalOffset, onScroll);
553 }
554 FireObserverOnDidScroll(finalOffset);
555 auto onDidScroll = gridEventHub->GetOnDidScroll();
556 if (onDidScroll) {
557 FireOnScroll(finalOffset, onDidScroll);
558 }
559 auto onScrollIndex = gridEventHub->GetOnScrollIndex();
560 FireOnScrollIndex(indexChanged, onScrollIndex);
561 if (indexChanged) {
562 host->OnAccessibilityEvent(AccessibilityEventType::SCROLLING_EVENT, info_.startIndex_, info_.endIndex_);
563 }
564 auto onReachStart = gridEventHub->GetOnReachStart();
565 FireOnReachStart(onReachStart);
566 auto onReachEnd = gridEventHub->GetOnReachEnd();
567 FireOnReachEnd(onReachEnd);
568 OnScrollStop(gridEventHub->GetOnScrollStop());
569 if (isSmoothScrolling_ && scrollStop_) {
570 isSmoothScrolling_ = false;
571 }
572 CHECK_NULL_VOID(isConfigScrollable_);
573 focusHandler_.ProcessFocusEvent(keyEvent_, indexChanged);
574 }
575
MarkDirtyNodeSelf()576 void GridPattern::MarkDirtyNodeSelf()
577 {
578 auto host = GetHost();
579 CHECK_NULL_VOID(host);
580 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
581 }
582
OnScrollEndCallback()583 void GridPattern::OnScrollEndCallback()
584 {
585 isSmoothScrolling_ = false;
586 if (AnimateStoped()) {
587 scrollStop_ = true;
588 MarkDirtyNodeSelf();
589 }
590 }
591
GetFocusNodeIndex(const RefPtr<FocusHub> & focusNode)592 int32_t GridPattern::GetFocusNodeIndex(const RefPtr<FocusHub>& focusNode)
593 {
594 return focusHandler_.GetFocusNodeIndex(focusNode);
595 }
596
ScrollToFocusNodeIndex(int32_t index)597 void GridPattern::ScrollToFocusNodeIndex(int32_t index)
598 {
599 StopAnimate();
600 UpdateStartIndex(index);
601 auto pipeline = GetContext();
602 if (pipeline) {
603 pipeline->FlushUITasks();
604 }
605 auto tarFocusNodeWeak = focusHandler_.GetChildFocusNodeByIndex(-1, -1, index);
606 auto tarFocusNode = tarFocusNodeWeak.Upgrade();
607 if (tarFocusNode) {
608 tarFocusNode->RequestFocusImmediately();
609 }
610 }
611
ScrollToNode(const RefPtr<FrameNode> & focusFrameNode)612 bool GridPattern::ScrollToNode(const RefPtr<FrameNode>& focusFrameNode)
613 {
614 CHECK_NULL_RETURN(focusFrameNode, false);
615 auto focusHub = focusFrameNode->GetFocusHub();
616 CHECK_NULL_RETURN(focusHub, false);
617 auto scrollToIndex = focusHandler_.GetFocusNodeIndex(focusHub);
618 if (scrollToIndex < 0) {
619 return false;
620 }
621 StopAnimate();
622 auto ret = UpdateStartIndex(scrollToIndex);
623 auto* pipeline = GetContext();
624 if (pipeline) {
625 pipeline->FlushUITasks();
626 }
627 return ret;
628 }
629
GetScrollOffsetAbility()630 ScrollOffsetAbility GridPattern::GetScrollOffsetAbility()
631 {
632 return { [wp = WeakClaim(this)](float moveOffset) -> bool {
633 auto pattern = wp.Upgrade();
634 CHECK_NULL_RETURN(pattern, false);
635 pattern->ScrollBy(-moveOffset);
636 return true;
637 },
638 GetAxis() };
639 }
640
GetScrollIndexAbility()641 std::function<bool(int32_t)> GridPattern::GetScrollIndexAbility()
642 {
643 return [wp = WeakClaim(this)](int32_t index) -> bool {
644 auto pattern = wp.Upgrade();
645 CHECK_NULL_RETURN(pattern, false);
646 if (index == FocusHub::SCROLL_TO_HEAD) {
647 pattern->ScrollToEdge(ScrollEdgeType::SCROLL_TOP, false);
648 } else if (index == FocusHub::SCROLL_TO_TAIL) {
649 pattern->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false);
650 } else {
651 pattern->UpdateStartIndex(index);
652 }
653 return true;
654 };
655 }
656
ScrollBy(float offset)657 void GridPattern::ScrollBy(float offset)
658 {
659 StopAnimate();
660 UpdateCurrentOffset(-offset, SCROLL_FROM_JUMP);
661 // AccessibilityEventType::SCROLL_END
662 }
663
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const664 void GridPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
665 {
666 ScrollablePattern::ToJsonValue(json, filter);
667 /* no fixed attr below, just return */
668 if (filter.IsFastFilter()) {
669 return;
670 }
671 json->PutExtAttr("multiSelectable", multiSelectable_ ? "true" : "false", filter);
672 json->PutExtAttr("supportAnimation", supportAnimation_ ? "true" : "false", filter);
673 }
674
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)675 void GridPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
676 {
677 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
678 auto pattern = wp.Upgrade();
679 if (pattern) {
680 return pattern->OnKeyEvent(event);
681 }
682 return false;
683 };
684 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
685 }
686
OnKeyEvent(const KeyEvent & event)687 bool GridPattern::OnKeyEvent(const KeyEvent& event)
688 {
689 if (event.action != KeyAction::DOWN) {
690 return false;
691 }
692 if ((event.code == KeyCode::KEY_PAGE_DOWN) || (event.code == KeyCode::KEY_PAGE_UP)) {
693 ScrollPage(event.code == KeyCode::KEY_PAGE_UP);
694 }
695
696 if (FocusHub::IsFocusStepKey(event.code)) {
697 if (focusHandler_.ScrollToLastFocusIndex(event.code)) {
698 keyEvent_ = event;
699 return true;
700 }
701 }
702 return false;
703 }
704
ScrollPage(bool reverse,bool smooth,AccessibilityScrollType scrollType)705 void GridPattern::ScrollPage(bool reverse, bool smooth, AccessibilityScrollType scrollType)
706 {
707 float distance = reverse ? GetMainContentSize() : -GetMainContentSize();
708 if (scrollType == AccessibilityScrollType::SCROLL_HALF) {
709 distance = distance / 2.f;
710 }
711 if (smooth) {
712 float position = -info_.currentHeight_ + distance;
713 ScrollablePattern::AnimateTo(-position, -1, nullptr, true, false, false);
714 return;
715 } else {
716 if (!isConfigScrollable_) {
717 return;
718 }
719 StopAnimate();
720 UpdateCurrentOffset(distance, SCROLL_FROM_JUMP);
721 }
722 // AccessibilityEventType::SCROLL_END
723 }
724
UpdateStartIndex(int32_t index)725 bool GridPattern::UpdateStartIndex(int32_t index)
726 {
727 if (!isConfigScrollable_) {
728 return false;
729 }
730 auto host = GetHost();
731 CHECK_NULL_RETURN(host, false);
732 info_.jumpIndex_ = index;
733 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
734 // AccessibilityEventType::SCROLL_END
735 SetScrollSource(SCROLL_FROM_JUMP);
736 return true;
737 }
738
UpdateStartIndex(int32_t index,ScrollAlign align)739 bool GridPattern::UpdateStartIndex(int32_t index, ScrollAlign align)
740 {
741 info_.scrollAlign_ = align;
742 return UpdateStartIndex(index);
743 }
744
OnAnimateStop()745 void GridPattern::OnAnimateStop()
746 {
747 if (!GetIsDragging() || GetScrollAbort()) {
748 scrollStop_ = true;
749 MarkDirtyNodeSelf();
750 }
751 }
752
AnimateTo(float position,float duration,const RefPtr<Curve> & curve,bool smooth,bool canOverScroll,bool useTotalOffset)753 void GridPattern::AnimateTo(
754 float position, float duration, const RefPtr<Curve>& curve, bool smooth, bool canOverScroll, bool useTotalOffset)
755 {
756 if (!isConfigScrollable_) {
757 return;
758 }
759 ScrollablePattern::AnimateTo(position, duration, curve, smooth, canOverScroll);
760 }
761
ScrollTo(float position)762 void GridPattern::ScrollTo(float position)
763 {
764 if (!isConfigScrollable_) {
765 return;
766 }
767 TAG_LOGI(AceLogTag::ACE_GRID, "ScrollTo:%{public}f", position);
768 StopAnimate();
769 UpdateCurrentOffset(GetTotalOffset() - position, SCROLL_FROM_JUMP);
770 // AccessibilityEventType::SCROLL_END
771 }
772
EstimateHeight() const773 float GridPattern::EstimateHeight() const
774 {
775 if (!isConfigScrollable_) {
776 return 0.0f;
777 }
778 // During the scrolling animation, the exact current position is used. Other times use the estimated location
779 if (isSmoothScrolling_) {
780 const auto* infoPtr = UseIrregularLayout() ? &info_ : infoCopy_.get();
781 CHECK_NULL_RETURN(infoPtr, 0.0f);
782 return infoPtr->GetTotalHeightFromZeroIndex(info_.startMainLineIndex_, GetMainGap()) - info_.currentOffset_;
783 }
784 auto host = GetHost();
785 CHECK_NULL_RETURN(host, 0.0);
786 auto geometryNode = host->GetGeometryNode();
787 CHECK_NULL_RETURN(geometryNode, 0.0);
788 const auto& info = info_;
789 auto viewScopeSize = geometryNode->GetPaddingSize();
790 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
791 auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
792 if (UseIrregularLayout()) {
793 return info.GetIrregularOffset(mainGap);
794 }
795 if (!layoutProperty->GetLayoutOptions().has_value()) {
796 return info.GetContentOffset(mainGap);
797 }
798
799 return info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
800 }
801
GetAverageHeight() const802 float GridPattern::GetAverageHeight() const
803 {
804 auto host = GetHost();
805 CHECK_NULL_RETURN(host, 0.0);
806 auto geometryNode = host->GetGeometryNode();
807 CHECK_NULL_RETURN(geometryNode, 0.0);
808 const auto& info = info_;
809 auto viewScopeSize = geometryNode->GetPaddingSize();
810 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
811
812 float heightSum = 0;
813 int32_t itemCount = 0;
814 auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
815 for (const auto& item : info.lineHeightMap_) {
816 auto line = info.gridMatrix_.find(item.first);
817 if (line == info.gridMatrix_.end()) {
818 continue;
819 }
820 if (line->second.empty()) {
821 continue;
822 }
823 auto lineStart = line->second.begin()->second;
824 auto lineEnd = line->second.rbegin()->second;
825 itemCount += (lineEnd - lineStart + 1);
826 heightSum += item.second + mainGap;
827 }
828 if (itemCount == 0) {
829 return 0;
830 }
831 return heightSum / itemCount;
832 }
833
GetTotalHeight() const834 float GridPattern::GetTotalHeight() const
835 {
836 if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
837 return scrollbarInfo_.second.value();
838 }
839 auto host = GetHost();
840 CHECK_NULL_RETURN(host, 0.0f);
841 auto geometryNode = host->GetGeometryNode();
842 CHECK_NULL_RETURN(geometryNode, 0.0f);
843 auto viewScopeSize = geometryNode->GetPaddingSize();
844 auto props = host->GetLayoutProperty<GridLayoutProperty>();
845 auto mainGap = GridUtils::GetMainGap(props, viewScopeSize, info_.axis_);
846 if (UseIrregularLayout()) {
847 return info_.GetIrregularHeight(mainGap);
848 }
849 if (props->HasLayoutOptions()) {
850 return info_.GetContentHeight(*props->GetLayoutOptions(), info_.childrenCount_, mainGap);
851 }
852 return info_.GetContentHeight(mainGap);
853 }
854
UpdateScrollBarOffset()855 void GridPattern::UpdateScrollBarOffset()
856 {
857 CheckScrollBarOff();
858 if ((!GetScrollBar() && !GetScrollBarProxy()) || !isConfigScrollable_) {
859 return;
860 }
861 auto host = GetHost();
862 CHECK_NULL_VOID(host);
863 auto geometryNode = host->GetGeometryNode();
864 CHECK_NULL_VOID(geometryNode);
865 const auto& info = info_;
866 float offset = 0;
867 float estimatedHeight = 0.f;
868 if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
869 offset = scrollbarInfo_.first.value();
870 estimatedHeight = scrollbarInfo_.second.value();
871 } else {
872 auto viewScopeSize = geometryNode->GetPaddingSize();
873 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
874 auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
875 if (UseIrregularLayout()) {
876 offset = info.GetIrregularOffset(mainGap);
877 estimatedHeight = info.GetIrregularHeight(mainGap);
878 } else if (!layoutProperty->GetLayoutOptions().has_value()) {
879 offset = info.GetContentOffset(mainGap);
880 estimatedHeight = info.GetContentHeight(mainGap);
881 } else {
882 offset = info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
883 estimatedHeight =
884 info.GetContentHeight(layoutProperty->GetLayoutOptions().value(), info.childrenCount_, mainGap);
885 }
886 }
887 if (info.startMainLineIndex_ != 0 && info.startIndex_ == 0) {
888 for (int32_t lineIndex = info.startMainLineIndex_ - 1; lineIndex >= 0; lineIndex--) {
889 offset += info.lineHeightMap_.find(lineIndex)->second;
890 }
891 }
892 auto viewSize = geometryNode->GetFrameSize();
893 auto overScroll = 0.0f;
894 if (info_.reachStart_ && Positive(info_.currentOffset_)) {
895 overScroll = info_.currentOffset_;
896 } else {
897 overScroll = info_.lastMainSize_ - estimatedHeight + offset;
898 overScroll = Positive(overScroll) ? overScroll : 0.0f;
899 }
900 if (info_.offsetEnd_ && NearZero(overScroll)) {
901 offset = estimatedHeight - info_.lastMainSize_;
902 }
903 HandleScrollBarOutBoundary(overScroll);
904 UpdateScrollBarRegion(offset, estimatedHeight, Size(viewSize.Width(), viewSize.Height()), Offset(0.0f, 0.0f));
905 }
906
GetDefaultScrollBarDisplayMode() const907 DisplayMode GridPattern::GetDefaultScrollBarDisplayMode() const
908 {
909 auto defaultDisplayMode = DisplayMode::OFF;
910 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
911 defaultDisplayMode = DisplayMode::AUTO;
912 }
913 return defaultDisplayMode;
914 }
915
GetOriginalIndex() const916 int32_t GridPattern::GetOriginalIndex() const
917 {
918 return info_.GetOriginalIndex();
919 }
920
GetCrossCount() const921 int32_t GridPattern::GetCrossCount() const
922 {
923 return info_.crossCount_;
924 }
925
GetChildrenCount() const926 int32_t GridPattern::GetChildrenCount() const
927 {
928 return info_.childrenCount_;
929 }
930
ClearDragState()931 void GridPattern::ClearDragState()
932 {
933 info_.ClearDragState();
934 MarkDirtyNodeSelf();
935 }
936
UpdateRectOfDraggedInItem(int32_t insertIndex)937 void GridPattern::UpdateRectOfDraggedInItem(int32_t insertIndex)
938 {
939 auto host = GetHost();
940 CHECK_NULL_VOID(host);
941 std::list<RefPtr<FrameNode>> children;
942 host->GenerateOneDepthAllFrame(children);
943 for (const auto& item : children) {
944 auto itemPattern = item->GetPattern<GridItemPattern>();
945 CHECK_NULL_VOID(itemPattern);
946 auto itemProperty = itemPattern->GetLayoutProperty<GridItemLayoutProperty>();
947 CHECK_NULL_VOID(itemProperty);
948 auto mainIndex = itemProperty->GetMainIndex().value_or(-1);
949 auto crossIndex = itemProperty->GetCrossIndex().value_or(-1);
950 if (mainIndex * info_.crossCount_ + crossIndex == insertIndex) {
951 auto size = item->GetRenderContext()->GetPaintRectWithTransform();
952 size.SetOffset(item->GetTransformRelativeOffset());
953 info_.currentRect_ = size;
954 break;
955 }
956 }
957 }
958
MoveItems(int32_t itemIndex,int32_t insertIndex)959 void GridPattern::MoveItems(int32_t itemIndex, int32_t insertIndex)
960 {
961 if (insertIndex < 0 || insertIndex >= ((itemIndex == -1) ? (info_.childrenCount_ + 1) : info_.childrenCount_)) {
962 return;
963 }
964
965 if (itemIndex == -1) {
966 UpdateRectOfDraggedInItem(insertIndex);
967 }
968
969 info_.SwapItems(itemIndex, insertIndex);
970
971 auto host = GetHost();
972 CHECK_NULL_VOID(host);
973 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
974 auto pipeline = GetContext();
975 if (pipeline) {
976 pipeline->FlushUITasks();
977 }
978 }
979
IsOutOfBoundary(bool)980 bool GridPattern::IsOutOfBoundary(bool /*useCurrentDelta*/)
981 {
982 const bool scrollable = GetAlwaysEnabled() || (info_.startIndex_ > 0) ||
983 (info_.endIndex_ < info_.childrenCount_ - 1) ||
984 GreatNotEqual(info_.totalHeightOfItemsInView_, info_.lastMainSize_);
985 return scrollable && (info_.IsOutOfStart() || info_.IsOutOfEnd(GetMainGap(), UseIrregularLayout()));
986 }
987
GetEndOffset()988 float GridPattern::GetEndOffset()
989 {
990 auto& info = info_;
991 float contentHeight = info.lastMainSize_ - info.contentEndPadding_;
992 const float mainGap = GetMainGap();
993 const bool irregular = UseIrregularLayout();
994 float heightInView = info.GetTotalHeightOfItemsInView(mainGap, irregular);
995
996 const float totalHeight = GetTotalHeight();
997 if (GetAlwaysEnabled() && LessNotEqual(totalHeight, contentHeight)) {
998 // overScroll with contentHeight < viewport
999 if (irregular) {
1000 return info.GetHeightInRange(0, info.startMainLineIndex_, mainGap);
1001 }
1002 return totalHeight - heightInView;
1003 }
1004
1005 if (!irregular) {
1006 return contentHeight - heightInView;
1007 }
1008 float disToBot = info_.GetDistanceToBottom(contentHeight, heightInView, mainGap);
1009 return info_.currentOffset_ - disToBot;
1010 }
1011
SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)1012 void GridPattern::SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect)
1013 {
1014 scrollEffect->SetCurrentPositionCallback([weak = AceType::WeakClaim(this)]() -> double {
1015 auto grid = weak.Upgrade();
1016 CHECK_NULL_RETURN(grid, 0.0);
1017 if (!grid->info_.synced_) {
1018 grid->SyncLayoutBeforeSpring();
1019 }
1020 return grid->info_.currentOffset_;
1021 });
1022 scrollEffect->SetLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1023 auto grid = weak.Upgrade();
1024 CHECK_NULL_RETURN(grid, 0.0);
1025 return grid->GetEndOffset();
1026 });
1027 scrollEffect->SetTrailingCallback([]() -> double { return 0.0; });
1028 scrollEffect->SetInitLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1029 auto grid = weak.Upgrade();
1030 CHECK_NULL_RETURN(grid, 0.0);
1031 return grid->GetEndOffset();
1032 });
1033 scrollEffect->SetInitTrailingCallback([]() -> double { return 0.0; });
1034 }
1035
SyncLayoutBeforeSpring()1036 void GridPattern::SyncLayoutBeforeSpring()
1037 {
1038 auto& info = info_;
1039 if (info.synced_) {
1040 return;
1041 }
1042 if (!UseIrregularLayout()) {
1043 const float delta = info.currentOffset_ - info.prevOffset_;
1044 if (!info.lineHeightMap_.empty() && LessOrEqual(delta, -info_.lastMainSize_)) {
1045 // old layout can't handle large overScroll offset. Avoid by skipping this layout.
1046 // Spring animation plays immediately afterwards, so losing this frame's offset is fine
1047 info.currentOffset_ = info.prevOffset_;
1048 info.synced_ = true;
1049 return;
1050 }
1051 }
1052 auto host = GetHost();
1053 CHECK_NULL_VOID(host);
1054
1055 preSpring_ = true;
1056 host->SetActive();
1057 auto* context = host->GetContext();
1058 if (context) {
1059 context->FlushUITaskWithSingleDirtyNode(host);
1060 }
1061 preSpring_ = false;
1062 }
1063
GetEndOverScrollIrregular(OverScrollOffset & offset,float delta) const1064 void GridPattern::GetEndOverScrollIrregular(OverScrollOffset& offset, float delta) const
1065 {
1066 const float mainGap = GetMainGap();
1067 const float viewport = info_.lastMainSize_ - info_.contentEndPadding_;
1068 float heightInView = info_.totalHeightOfItemsInView_;
1069 if (info_.HeightSumSmaller(viewport, mainGap)) {
1070 // content < viewport, use viewport height to calculate overScroll
1071 heightInView = viewport - info_.GetHeightInRange(0, info_.startMainLineIndex_, mainGap);
1072 }
1073 float disToBot = info_.GetDistanceToBottom(viewport, heightInView, mainGap);
1074 if (!info_.IsOutOfEnd(mainGap, true)) {
1075 offset.end = std::min(0.0f, disToBot + delta);
1076 } else if (Negative(delta)) {
1077 offset.end = delta;
1078 } else {
1079 offset.end = std::min(delta, -disToBot);
1080 }
1081 }
1082
GetOverScrollOffset(double delta) const1083 OverScrollOffset GridPattern::GetOverScrollOffset(double delta) const
1084 {
1085 OverScrollOffset offset = { 0, 0 };
1086 if (info_.startIndex_ == 0 && info_.startMainLineIndex_ == 0) {
1087 auto startPos = info_.currentOffset_;
1088 auto newStartPos = startPos + delta;
1089 if (startPos > 0 && newStartPos > 0) {
1090 offset.start = delta;
1091 }
1092 if (startPos > 0 && newStartPos <= 0) {
1093 offset.start = -startPos;
1094 }
1095 if (startPos <= 0 && newStartPos > 0) {
1096 offset.start = newStartPos;
1097 }
1098 }
1099 if (UseIrregularLayout()) {
1100 GetEndOverScrollIrregular(offset, static_cast<float>(delta));
1101 return offset;
1102 }
1103 if (info_.endIndex_ == info_.childrenCount_ - 1) {
1104 float endPos = info_.currentOffset_ + info_.totalHeightOfItemsInView_;
1105 float mainSize = info_.lastMainSize_ - info_.contentEndPadding_;
1106 if (GreatNotEqual(GetMainContentSize(), info_.currentOffset_ + info_.totalHeightOfItemsInView_)) {
1107 endPos = info_.currentOffset_ + GetMainContentSize();
1108 }
1109 float newEndPos = endPos + delta;
1110 if (endPos < mainSize && newEndPos < mainSize) {
1111 offset.end = delta;
1112 }
1113 if (endPos < mainSize && newEndPos >= mainSize) {
1114 offset.end = mainSize - endPos;
1115 }
1116 if (endPos >= mainSize && newEndPos < mainSize) {
1117 offset.end = newEndPos - mainSize;
1118 }
1119 }
1120 return offset;
1121 }
1122
DumpAdvanceInfo()1123 void GridPattern::DumpAdvanceInfo()
1124 {
1125 auto property = GetLayoutProperty<GridLayoutProperty>();
1126 CHECK_NULL_VOID(property);
1127 ScrollablePattern::DumpAdvanceInfo();
1128 if (!property->HasLayoutOptions()) {
1129 DumpLog::GetInstance().AddDesc("GridLayoutOptions:null");
1130 } else {
1131 DumpLog::GetInstance().AddDesc("GridLayoutOptions:true");
1132 DumpLog::GetInstance().AddDesc(GetIrregularIndexesString());
1133 }
1134 supportAnimation_ ? DumpLog::GetInstance().AddDesc("supportAnimation:true")
1135 : DumpLog::GetInstance().AddDesc("supportAnimation:false");
1136 isConfigScrollable_ ? DumpLog::GetInstance().AddDesc("isConfigScrollable:true")
1137 : DumpLog::GetInstance().AddDesc("isConfigScrollable:false");
1138 info_.lastCrossCount_.has_value()
1139 ? DumpLog::GetInstance().AddDesc("lastCrossCount:" + std::to_string(info_.lastCrossCount_.value()))
1140 : DumpLog::GetInstance().AddDesc("lastCrossCount:null");
1141 info_.reachEnd_ ? DumpLog::GetInstance().AddDesc("reachEnd:true")
1142 : DumpLog::GetInstance().AddDesc("reachEnd:false");
1143 info_.reachStart_ ? DumpLog::GetInstance().AddDesc("reachStart:true")
1144 : DumpLog::GetInstance().AddDesc("reachStart:false");
1145 info_.offsetEnd_ ? DumpLog::GetInstance().AddDesc("offsetEnd:true")
1146 : DumpLog::GetInstance().AddDesc("offsetEnd:false");
1147 info_.hasBigItem_ ? DumpLog::GetInstance().AddDesc("hasBigItem:true")
1148 : DumpLog::GetInstance().AddDesc("hasBigItem:false");
1149 info_.synced_ ? DumpLog::GetInstance().AddDesc("synced:true") : DumpLog::GetInstance().AddDesc("synced:false");
1150 DumpLog::GetInstance().AddDesc("scrollStop:" + std::to_string(scrollStop_));
1151 DumpLog::GetInstance().AddDesc("prevHeight:" + std::to_string(info_.prevHeight_));
1152 DumpLog::GetInstance().AddDesc("currentHeight:" + std::to_string(info_.currentHeight_));
1153 DumpLog::GetInstance().AddDesc("endHeight:" + std::to_string(endHeight_));
1154 DumpLog::GetInstance().AddDesc("currentOffset:" + std::to_string(info_.currentOffset_));
1155 DumpLog::GetInstance().AddDesc("prevOffset:" + std::to_string(info_.prevOffset_));
1156 DumpLog::GetInstance().AddDesc("lastMainSize:" + std::to_string(info_.lastMainSize_));
1157 DumpLog::GetInstance().AddDesc("totalHeightOfItemsInView:" + std::to_string(info_.totalHeightOfItemsInView_));
1158 DumpLog::GetInstance().AddDesc("startIndex:" + std::to_string(info_.startIndex_));
1159 DumpLog::GetInstance().AddDesc("endIndex:" + std::to_string(info_.endIndex_));
1160 DumpLog::GetInstance().AddDesc("jumpIndex:" + std::to_string(info_.jumpIndex_));
1161 DumpLog::GetInstance().AddDesc("crossCount:" + std::to_string(info_.crossCount_));
1162 DumpLog::GetInstance().AddDesc("childrenCount:" + std::to_string(info_.childrenCount_));
1163 DumpLog::GetInstance().AddDesc("RowsTemplate:", property->GetRowsTemplate()->c_str());
1164 DumpLog::GetInstance().AddDesc("ColumnsTemplate:", property->GetColumnsTemplate()->c_str());
1165 property->GetRowsGap().has_value()
1166 ? DumpLog::GetInstance().AddDesc("RowsGap:" + std::to_string(property->GetRowsGap().value().Value()))
1167 : DumpLog::GetInstance().AddDesc("RowsGap:null");
1168 property->GetColumnsGap().has_value()
1169 ? DumpLog::GetInstance().AddDesc("ColumnsGap:" + std::to_string(property->GetColumnsGap().value().Value()))
1170 : DumpLog::GetInstance().AddDesc("ColumnsGap:null");
1171 property->GetCachedCount().has_value()
1172 ? DumpLog::GetInstance().AddDesc("CachedCount:" + std::to_string(property->GetCachedCount().value()))
1173 : DumpLog::GetInstance().AddDesc("CachedCount:null");
1174 property->GetMaxCount().has_value()
1175 ? DumpLog::GetInstance().AddDesc("MaxCount:" + std::to_string(property->GetMaxCount().value()))
1176 : DumpLog::GetInstance().AddDesc("MaxCount:null");
1177 property->GetMinCount().has_value()
1178 ? DumpLog::GetInstance().AddDesc("MinCount:" + std::to_string(property->GetMinCount().value()))
1179 : DumpLog::GetInstance().AddDesc("MinCount:null");
1180 property->GetCellLength().has_value()
1181 ? DumpLog::GetInstance().AddDesc("CellLength:" + std::to_string(property->GetCellLength().value()))
1182 : DumpLog::GetInstance().AddDesc("CellLength:null");
1183 property->GetEditable().has_value()
1184 ? DumpLog::GetInstance().AddDesc("Editable:" + std::to_string(property->GetEditable().value()))
1185 : DumpLog::GetInstance().AddDesc("Editable:null");
1186 property->GetScrollEnabled().has_value()
1187 ? DumpLog::GetInstance().AddDesc("ScrollEnabled:" + std::to_string(property->GetScrollEnabled().value()))
1188 : DumpLog::GetInstance().AddDesc("ScrollEnabled:null");
1189 switch (property->GetAlignItems().value_or(GridItemAlignment::DEFAULT)) {
1190 case GridItemAlignment::STRETCH: {
1191 DumpLog::GetInstance().AddDesc("AlignItems:GridItemAlignment.STRETCH");
1192 break;
1193 }
1194 default: {
1195 DumpLog::GetInstance().AddDesc("AlignItems:GridItemAlignment.DEFAULT");
1196 break;
1197 }
1198 }
1199 switch (info_.scrollAlign_) {
1200 case ScrollAlign::NONE: {
1201 DumpLog::GetInstance().AddDesc("ScrollAlign:NONE");
1202 break;
1203 }
1204 case ScrollAlign::CENTER: {
1205 DumpLog::GetInstance().AddDesc("ScrollAlign:CENTER");
1206 break;
1207 }
1208 case ScrollAlign::END: {
1209 DumpLog::GetInstance().AddDesc("ScrollAlign:END");
1210 break;
1211 }
1212 case ScrollAlign::START: {
1213 DumpLog::GetInstance().AddDesc("ScrollAlign:START");
1214 break;
1215 }
1216 case ScrollAlign::AUTO: {
1217 DumpLog::GetInstance().AddDesc("ScrollAlign:AUTO");
1218 break;
1219 }
1220 default: {
1221 break;
1222 }
1223 }
1224 if (!info_.gridMatrix_.empty()) {
1225 DumpLog::GetInstance().AddDesc("-----------start print gridMatrix------------");
1226 std::string res = std::string("");
1227 for (auto item : info_.gridMatrix_) {
1228 res.append(std::to_string(item.first));
1229 res.append(": ");
1230 for (auto index : item.second) {
1231 res.append("[")
1232 .append(std::to_string(index.first))
1233 .append(",")
1234 .append(std::to_string(index.second))
1235 .append("] ");
1236 }
1237 DumpLog::GetInstance().AddDesc(res);
1238 res.clear();
1239 }
1240 DumpLog::GetInstance().AddDesc("-----------end print gridMatrix------------");
1241 }
1242 if (!info_.lineHeightMap_.empty()) {
1243 DumpLog::GetInstance().AddDesc("-----------start print lineHeightMap------------");
1244 for (auto item : info_.lineHeightMap_) {
1245 DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1246 }
1247 DumpLog::GetInstance().AddDesc("-----------end print lineHeightMap------------");
1248 }
1249 if (!info_.irregularItemsPosition_.empty()) {
1250 DumpLog::GetInstance().AddDesc("-----------start print irregularItemsPosition_------------");
1251 for (auto item : info_.irregularItemsPosition_) {
1252 DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1253 }
1254 DumpLog::GetInstance().AddDesc("-----------end print irregularItemsPosition_------------");
1255 }
1256 }
1257
GetIrregularIndexesString() const1258 std::string GridPattern::GetIrregularIndexesString() const
1259 {
1260 auto property = GetLayoutProperty<GridLayoutProperty>();
1261 if (!property || !property->HasLayoutOptions()) {
1262 return std::string("");
1263 }
1264 const auto& options = *property->GetLayoutOptions();
1265 if (options.irregularIndexes.empty()) {
1266 return std::string("");
1267 }
1268 std::string irregularIndexes = std::string("IrregularIndexes: [");
1269 int count = 0;
1270 for (const auto& index : options.irregularIndexes) {
1271 if (count > 0) {
1272 irregularIndexes.append(", ");
1273 }
1274 irregularIndexes.append(std::to_string(index));
1275 count++;
1276 if (count == MAX_NUM_SIZE) {
1277 irregularIndexes.append("...");
1278 break;
1279 }
1280 }
1281 irregularIndexes.append("]");
1282 return irregularIndexes;
1283 }
1284
ProvideRestoreInfo()1285 std::string GridPattern::ProvideRestoreInfo()
1286 {
1287 return std::to_string(info_.startIndex_);
1288 }
1289
OnRestoreInfo(const std::string & restoreInfo)1290 void GridPattern::OnRestoreInfo(const std::string& restoreInfo)
1291 {
1292 info_.jumpIndex_ = StringUtils::StringToInt(restoreInfo);
1293 info_.scrollAlign_ = ScrollAlign::START;
1294 }
1295
GetItemRect(int32_t index) const1296 Rect GridPattern::GetItemRect(int32_t index) const
1297 {
1298 if (index < 0 || index < info_.startIndex_ || index > info_.endIndex_) {
1299 return Rect();
1300 }
1301 auto host = GetHost();
1302 CHECK_NULL_RETURN(host, Rect());
1303 auto item = host->GetChildByIndex(index);
1304 CHECK_NULL_RETURN(item, Rect());
1305 auto itemGeometry = item->GetGeometryNode();
1306 CHECK_NULL_RETURN(itemGeometry, Rect());
1307 return Rect(itemGeometry->GetFrameRect().GetX(), itemGeometry->GetFrameRect().GetY(),
1308 itemGeometry->GetFrameRect().Width(), itemGeometry->GetFrameRect().Height());
1309 }
1310
GetItemIndex(double x,double y) const1311 int32_t GridPattern::GetItemIndex(double x, double y) const
1312 {
1313 for (int32_t index = info_.startIndex_; index <= info_.endIndex_; ++index) {
1314 Rect rect = GetItemRect(index);
1315 if (rect.IsInRegion({ x, y })) {
1316 return index;
1317 }
1318 }
1319 return -1;
1320 }
1321
ScrollToIndex(int32_t index,bool smooth,ScrollAlign align,std::optional<float> extraOffset)1322 void GridPattern::ScrollToIndex(int32_t index, bool smooth, ScrollAlign align, std::optional<float> extraOffset)
1323 {
1324 SetScrollSource(SCROLL_FROM_JUMP);
1325 StopAnimate();
1326 auto host = GetHost();
1327 CHECK_NULL_VOID(host);
1328 int32_t totalChildCount = host->TotalChildCount();
1329 if (((index >= 0) && (index < totalChildCount)) || (index == LAST_ITEM)) {
1330 if (extraOffset.has_value()) {
1331 info_.extraOffset_ = -extraOffset.value();
1332 }
1333 if (smooth) {
1334 SetExtraOffset(extraOffset);
1335 targetIndex_ = index;
1336 scrollAlign_ = align;
1337 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1338 } else {
1339 UpdateStartIndex(index, align);
1340 }
1341 }
1342 FireAndCleanScrollingListener();
1343 }
1344
ScrollToEdge(ScrollEdgeType scrollEdgeType,bool smooth)1345 void GridPattern::ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth)
1346 {
1347 if (UseIrregularLayout() && scrollEdgeType == ScrollEdgeType::SCROLL_BOTTOM) {
1348 ScrollToIndex(LAST_ITEM, smooth);
1349 // for irregular layout, last item might not be at bottom
1350 info_.jumpIndex_ = JUMP_TO_BOTTOM_EDGE;
1351 auto host = GetHost();
1352 CHECK_NULL_VOID(host);
1353 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1354 return;
1355 }
1356 ScrollablePattern::ScrollToEdge(scrollEdgeType, smooth);
1357 }
1358
1359 // Turn on the scrolling animation
AnimateToTarget(ScrollAlign align,const RefPtr<LayoutAlgorithmWrapper> & algo)1360 void GridPattern::AnimateToTarget(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo)
1361 {
1362 if (targetIndex_.has_value()) {
1363 AnimateToTargetImpl(align, algo);
1364 targetIndex_.reset();
1365 }
1366 }
1367
1368 // scroll to the item where the index is located
AnimateToTargetImpl(ScrollAlign align,const RefPtr<LayoutAlgorithmWrapper> & algo)1369 bool GridPattern::AnimateToTargetImpl(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo)
1370 {
1371 const float mainGap = GetMainGap();
1372 float targetPos = 0.0f;
1373 auto host = GetHost();
1374 CHECK_NULL_RETURN(host, false);
1375 auto&& extraOffset = GetExtraOffset();
1376 bool success = true;
1377 if (UseIrregularLayout()) {
1378 auto host = GetHost();
1379 CHECK_NULL_RETURN(host, false);
1380 auto size = GridLayoutUtils::GetItemSize(&info_, RawPtr(host), *targetIndex_);
1381 targetPos = info_.GetAnimatePosIrregular(*targetIndex_, size.rows, align, mainGap);
1382 if (Negative(targetPos)) {
1383 success = false;
1384 }
1385 } else {
1386 auto gridScrollLayoutAlgorithm = DynamicCast<GridScrollLayoutAlgorithm>(algo->GetLayoutAlgorithm());
1387 infoCopy_ = gridScrollLayoutAlgorithm->MoveInfoCopy();
1388 // Based on the index, align gets the position to scroll to
1389 success = infoCopy_ && infoCopy_->GetGridItemAnimatePos(info_, *targetIndex_, align, mainGap, targetPos);
1390 }
1391 if (!success) {
1392 if (NearZero(extraOffset.value_or(0.0f))) {
1393 return false;
1394 }
1395 targetPos = GetTotalOffset();
1396 }
1397
1398 isSmoothScrolling_ = true;
1399 if (extraOffset.has_value()) {
1400 ACE_SCOPED_TRACE(
1401 "AnimateToTargetImpl, success:%u, targetPos:%f, extraOffset:%f", success, targetPos, *extraOffset);
1402 targetPos += *extraOffset;
1403 ResetExtraOffset();
1404 } else {
1405 ACE_SCOPED_TRACE("AnimateToTargetImpl, targetPos:%f", targetPos);
1406 }
1407 if (NearEqual(targetPos, GetTotalOffset())) {
1408 isSmoothScrolling_ = false;
1409 return false;
1410 }
1411 AnimateTo(targetPos, -1, nullptr, true);
1412 return true;
1413 }
1414
GetVisibleSelectedItems()1415 std::vector<RefPtr<FrameNode>> GridPattern::GetVisibleSelectedItems()
1416 {
1417 std::vector<RefPtr<FrameNode>> children;
1418 auto host = GetHost();
1419 CHECK_NULL_RETURN(host, children);
1420 for (int32_t index = info_.startIndex_; index <= info_.endIndex_; ++index) {
1421 auto item = host->GetChildByIndex(index);
1422 if (!AceType::InstanceOf<FrameNode>(item)) {
1423 continue;
1424 }
1425 auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
1426 auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
1427 if (!itemPattern) {
1428 continue;
1429 }
1430 if (!itemPattern->IsSelected()) {
1431 continue;
1432 }
1433 children.emplace_back(itemFrameNode);
1434 }
1435 return children;
1436 }
1437
StopAnimate()1438 void GridPattern::StopAnimate()
1439 {
1440 ScrollablePattern::StopAnimate();
1441 isSmoothScrolling_ = false;
1442 }
1443
IsPredictOutOfRange(int32_t index) const1444 bool GridPattern::IsPredictOutOfRange(int32_t index) const
1445 {
1446 CHECK_NULL_RETURN(info_.reachEnd_, false);
1447 auto host = GetHost();
1448 CHECK_NULL_RETURN(host, true);
1449 auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1450 CHECK_NULL_RETURN(gridLayoutProperty, true);
1451 auto cacheCount = gridLayoutProperty->GetCachedCountValue(info_.defCachedCount_) * info_.crossCount_;
1452 return index < info_.startIndex_ - cacheCount || index > info_.endIndex_ + cacheCount;
1453 }
1454
IsPredictInRange(int32_t index) const1455 bool GridPattern::IsPredictInRange(int32_t index) const
1456 {
1457 return index >= info_.startIndex_ && index <= info_.endIndex_;
1458 }
1459
UseIrregularLayout() const1460 inline bool GridPattern::UseIrregularLayout() const
1461 {
1462 return irregular_ || (SystemProperties::GetGridIrregularLayoutEnabled() &&
1463 GetLayoutProperty<GridLayoutProperty>()->HasLayoutOptions());
1464 }
1465
IsReverse() const1466 bool GridPattern::IsReverse() const
1467 {
1468 auto host = GetHost();
1469 CHECK_NULL_RETURN(host, false);
1470 auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1471 CHECK_NULL_RETURN(gridLayoutProperty, false);
1472 return gridLayoutProperty->IsReverse();
1473 }
1474
BuildScrollAlignInfo(std::unique_ptr<JsonValue> & json)1475 void GridPattern::BuildScrollAlignInfo(std::unique_ptr<JsonValue>& json)
1476 {
1477 switch (info_.scrollAlign_) {
1478 case ScrollAlign::NONE: {
1479 json->Put("ScrollAlign", "NONE");
1480 break;
1481 }
1482 case ScrollAlign::CENTER: {
1483 json->Put("ScrollAlign", "CENTER");
1484 break;
1485 }
1486 case ScrollAlign::END: {
1487 json->Put("ScrollAlign", "END");
1488 break;
1489 }
1490 case ScrollAlign::START: {
1491 json->Put("ScrollAlign", "START");
1492 break;
1493 }
1494 case ScrollAlign::AUTO: {
1495 json->Put("ScrollAlign", "AUTO");
1496 break;
1497 }
1498 default: {
1499 break;
1500 }
1501 }
1502 }
1503
BuildGridLayoutInfo(std::unique_ptr<JsonValue> & json)1504 void GridPattern::BuildGridLayoutInfo(std::unique_ptr<JsonValue>& json)
1505 {
1506 if (!info_.gridMatrix_.empty()) {
1507 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1508 std::string res = std::string("");
1509 for (auto item : info_.gridMatrix_) {
1510 for (auto index : item.second) {
1511 res.append("[")
1512 .append(std::to_string(index.first))
1513 .append(",")
1514 .append(std::to_string(index.second))
1515 .append("] ");
1516 }
1517 children->Put(std::to_string(item.first).c_str(), res.c_str());
1518 res.clear();
1519 }
1520 children->Put("gridMatrix", children);
1521 }
1522 if (!info_.lineHeightMap_.empty()) {
1523 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1524 for (auto item : info_.lineHeightMap_) {
1525 children->Put(std::to_string(item.first).c_str(), std::to_string(item.second).c_str());
1526 }
1527 children->Put("lineHeightMap", children);
1528 }
1529 if (!info_.irregularItemsPosition_.empty()) {
1530 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1531 for (auto item : info_.irregularItemsPosition_) {
1532 children->Put(std::to_string(item.first).c_str(), std::to_string(item.second).c_str());
1533 }
1534 children->Put("irregularItemsPosition_", children);
1535 }
1536 }
1537
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)1538 void GridPattern::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
1539 {
1540 auto property = GetLayoutProperty<GridLayoutProperty>();
1541 CHECK_NULL_VOID(property);
1542 ScrollablePattern::DumpAdvanceInfo(json);
1543 json->Put("GridLayoutOptions", property->HasLayoutOptions() ? GetIrregularIndexesString().c_str() : "null");
1544 json->Put("supportAnimation", supportAnimation_);
1545 json->Put("isConfigScrollable", isConfigScrollable_);
1546 json->Put("lastCrossCount",
1547 info_.lastCrossCount_.has_value() ? std::to_string(info_.lastCrossCount_.value()).c_str() : "null");
1548 json->Put("reachEnd", info_.reachEnd_);
1549 json->Put("reachStart", info_.reachStart_);
1550 json->Put("offsetEnd", info_.offsetEnd_);
1551 json->Put("hasBigItem", info_.hasBigItem_);
1552 json->Put("synced", info_.synced_);
1553 json->Put("scrollStop", std::to_string(scrollStop_).c_str());
1554 json->Put("prevHeight", info_.prevHeight_);
1555 json->Put("currentHeight", info_.currentHeight_);
1556 json->Put("endHeight", endHeight_);
1557 json->Put("currentOffset", std::to_string(info_.currentOffset_).c_str());
1558 json->Put("prevOffset", std::to_string(info_.prevOffset_).c_str());
1559 json->Put("lastMainSize", std::to_string(info_.lastMainSize_).c_str());
1560 json->Put("totalHeightOfItemsInView", std::to_string(info_.totalHeightOfItemsInView_).c_str());
1561 json->Put("startIndex", info_.startIndex_);
1562 json->Put("endIndex", info_.endIndex_);
1563 json->Put("jumpIndex", info_.jumpIndex_);
1564 json->Put("crossCount", info_.crossCount_);
1565 json->Put("childrenCount", info_.childrenCount_);
1566 json->Put("RowsTemplate", property->GetRowsTemplate()->c_str());
1567 json->Put("ColumnsTemplate", property->GetColumnsTemplate()->c_str());
1568 json->Put("CachedCount",
1569 property->GetCachedCount().has_value() ? std::to_string(property->GetCachedCount().value()).c_str() : "null");
1570 json->Put("ShowCache", std::to_string(property->GetShowCachedItemsValue(false)).c_str());
1571 json->Put("MaxCount",
1572 property->GetMaxCount().has_value() ? std::to_string(property->GetMaxCount().value()).c_str() : "null");
1573 json->Put("MinCount",
1574 property->GetMinCount().has_value() ? std::to_string(property->GetMinCount().value()).c_str() : "null");
1575 json->Put("CellLength",
1576 property->GetCellLength().has_value() ? std::to_string(property->GetCellLength().value()).c_str() : "null");
1577 json->Put("Editable",
1578 property->GetEditable().has_value() ? std::to_string(property->GetEditable().value()).c_str() : "null");
1579 json->Put("ScrollEnabled", property->GetScrollEnabled().has_value()
1580 ? std::to_string(property->GetScrollEnabled().value()).c_str()
1581 : "null");
1582
1583 json->Put("AlignItems", property->GetAlignItems() ? "GridItemAlignment.STRETCH" : "GridItemAlignment.DEFAULT");
1584 BuildScrollAlignInfo(json);
1585 BuildGridLayoutInfo(json);
1586 }
1587
GetChildrenExpandedSize()1588 SizeF GridPattern::GetChildrenExpandedSize()
1589 {
1590 auto host = GetHost();
1591 CHECK_NULL_RETURN(host, SizeF());
1592 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1593 CHECK_NULL_RETURN(layoutProperty, SizeF());
1594 auto padding = layoutProperty->CreatePaddingAndBorder();
1595 auto geometryNode = host->GetGeometryNode();
1596 CHECK_NULL_RETURN(geometryNode, SizeF());
1597 auto viewSize = geometryNode->GetFrameSize();
1598 MinusPaddingToSize(padding, viewSize);
1599
1600 auto axis = GetAxis();
1601 float estimatedHeight = 0.f;
1602 const auto& info = info_;
1603 auto viewScopeSize = geometryNode->GetPaddingSize();
1604 auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
1605 if (UseIrregularLayout()) {
1606 estimatedHeight = info.GetIrregularHeight(mainGap);
1607 } else if (!layoutProperty->GetLayoutOptions().has_value()) {
1608 estimatedHeight = info.GetContentHeight(mainGap);
1609 } else {
1610 estimatedHeight =
1611 info.GetContentHeight(layoutProperty->GetLayoutOptions().value(), info.childrenCount_, mainGap);
1612 }
1613
1614 if (axis == Axis::VERTICAL) {
1615 return SizeF(viewSize.Width(), estimatedHeight);
1616 } else if (axis == Axis::HORIZONTAL) {
1617 return SizeF(estimatedHeight, viewSize.Height());
1618 }
1619 return SizeF();
1620 }
1621
GetScopeFocusAlgorithm()1622 ScopeFocusAlgorithm GridPattern::GetScopeFocusAlgorithm()
1623 {
1624 auto property = GetLayoutProperty<GridLayoutProperty>();
1625 if (!property) {
1626 return ScopeFocusAlgorithm();
1627 }
1628 return ScopeFocusAlgorithm(property->IsVertical(), true, ScopeType::OTHERS,
1629 [wp = WeakClaim(this)](
1630 FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) -> bool {
1631 auto grid = wp.Upgrade();
1632 CHECK_NULL_RETURN(grid, false);
1633 if (grid->UseIrregularLayout() && (step == FocusStep::TAB || step == FocusStep::SHIFT_TAB)) {
1634 nextFocusNode = grid->focusHandler_.GetNextFocusSimplified(step, currFocusNode.Upgrade());
1635 } else {
1636 nextFocusNode = grid->focusHandler_.GetNextFocusNode(step, currFocusNode);
1637 }
1638 return nextFocusNode.Upgrade() != currFocusNode.Upgrade();
1639 });
1640 }
1641
HandleOnItemFocus(int32_t index)1642 void GridPattern::HandleOnItemFocus(int32_t index)
1643 {
1644 focusHandler_.SetFocusIndex(index);
1645 }
1646 } // namespace OHOS::Ace::NG
1647