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_v2/water_flow/render_water_flow.h"
17
18 #include <cinttypes>
19 #include <cstdint>
20
21 #include "base/log/event_report.h"
22 #include "base/utils/time_util.h"
23 #include "base/utils/utils.h"
24 #include "core/animation/curve_animation.h"
25 #include "core/components/common/layout/templates_parser.h"
26 #include "core/components_v2/water_flow/water_flow_scroll_controller.h"
27 #include "core/event/ace_event_helper.h"
28 #include "core/pipeline/base/position_layout_utils.h"
29
30 namespace OHOS::Ace::V2 {
31 namespace {
32 constexpr int64_t MICROSEC_TO_NANOSEC = 1000;
33 constexpr int64_t MILLISEC_TO_NANOSEC = 1000000;
34 constexpr int64_t TIME_THRESHOLD = 3 * MILLISEC_TO_NANOSEC; // milliseconds
35 constexpr int32_t ANIMATE_DURATION = 800; // ms
36 const RefPtr<CubicCurve> CURVE_SCROLL_TO_TOP = AceType::MakeRefPtr<CubicCurve>(0.0f, 0.3f, 0.2f, 1.0f);
37 constexpr int32_t DEFAULT_DEPTH = 10;
38 constexpr double MAX_CONSTRAINT_SCALE = 3.0;
39 constexpr double CENTER_POINT = 2.0;
40 constexpr int32_t CACHE_SIZE_SCALE = 3;
41 const std::string UNIT_AUTO = "auto";
42 } // namespace
43
~RenderWaterFlow()44 RenderWaterFlow::~RenderWaterFlow()
45 {
46 if (scrollBarProxy_) {
47 scrollBarProxy_->UnRegisterScrollableNode(AceType::WeakClaim(this));
48 }
49 }
50
Update(const RefPtr<Component> & component)51 void RenderWaterFlow::Update(const RefPtr<Component>& component)
52 {
53 component_ = AceType::DynamicCast<V2::WaterFlowComponent>(component);
54 if (!component_) {
55 LOGE("RenderWaterFlow update failed.");
56 EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
57 return;
58 }
59
60 auto controller = component_->GetController();
61 if (controller) {
62 controller->SetScrollNode(WeakClaim(this));
63 }
64 if (!animator_) {
65 animator_ = CREATE_ANIMATOR(GetContext());
66 }
67
68 updateFlag_ = true;
69 direction_ = component_->GetDirection();
70 userColGap_ = component_->GetColumnsGap();
71 userRowGap_ = component_->GetRowsGap();
72 colsArgs_ = component_->GetColumnsArgs();
73 rowsArgs_ = component_->GetRowsArgs();
74 scrollBarProxy_ = component_->GetScrollBarProxy();
75 InitScrollBar();
76 InitScrollBarProxy();
77 CreateScrollable();
78 MarkNeedLayout();
79 }
80
PerformLayout()81 void RenderWaterFlow::PerformLayout()
82 {
83 if (RenderNode::GetChildren().empty() && !buildChildByIndex_) {
84 return;
85 }
86 InitialFlowProp();
87 // Adjust the view port out of items, caused by scrolling that may occur.
88 AdjustViewPort();
89 size_t itemIndex = GetNextSupplyedIndex();
90 double targetPos = GetTargetPos();
91 SupplyItems(itemIndex, targetPos);
92 // Adjust the view port out of items, caused by supply items that may occur.
93 // (view port at the tail and delete tail item continuously)
94 AdjustViewPort();
95 UpdateCacheItems();
96 LayoutItems(cacheItems_);
97 LayoutFooter();
98 // Check if reach the tail of waterFlow
99 reachTail_ = CheckReachTail();
100 // Check if reach the head of waterFlow
101 reachHead_ = CheckReachHead();
102 if (reachHead_) {
103 viewportStartPos_ = 0.0;
104 }
105
106 if (!scrollBar_) {
107 return;
108 }
109 scrollBar_->SetScrollable(false);
110 if (scrollBar_ && (GetEstimatedHeight() > mainSize_)) {
111 scrollBar_->SetScrollable(true);
112 }
113
114 if (!lastReachHead_ && reachHead_) {
115 waterflowEventFlags_[WaterFlowEvents::REACH_START] = true;
116 }
117 if (!lastReachTail_ && reachTail_) {
118 waterflowEventFlags_[WaterFlowEvents::REACH_END] = true;
119 }
120
121 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
122 SetLayoutSize(GetLayoutParam().Constrain(Size(crossSize_, mainSize_)));
123 } else {
124 SetLayoutSize(GetLayoutParam().Constrain(Size(mainSize_, crossSize_)));
125 }
126 HandleScrollEvent();
127 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
128 lastOffset_ = viewportStartPos_;
129 } else {
130 lastOffset_ = estimateHeight_ + viewportStartPos_ - mainSize_;
131 }
132 lastReachHead_ = reachHead_;
133 lastReachTail_ = reachTail_;
134 MarkNeedPredictLayout();
135 }
136
AddChildByIndex(size_t index,const RefPtr<RenderNode> & renderNode)137 void RenderWaterFlow::AddChildByIndex(size_t index, const RefPtr<RenderNode>& renderNode)
138 {
139 auto iter = items_.find(index);
140 if (iter != items_.end() && iter->second == nullptr) {
141 items_.erase(index);
142 }
143
144 auto itor = items_.try_emplace(index, renderNode);
145 if (itor.second) {
146 AddChild(renderNode);
147 }
148 }
149
CreateScrollable()150 void RenderWaterFlow::CreateScrollable()
151 {
152 scrollable_ = nullptr;
153 if (useScrollable_ == SCROLLABLE::NO_SCROLL) {
154 return;
155 }
156
157 auto callback = [weak = AceType::WeakClaim(this)](double offset, int32_t source) {
158 auto flow = weak.Upgrade();
159 if (!flow) {
160 return false;
161 }
162 // Stop animator of scroll bar.
163 auto scrollBarProxy = flow->scrollBarProxy_;
164 if (scrollBarProxy) {
165 scrollBarProxy->StopScrollBarAnimator();
166 }
167 return flow->UpdateScrollPosition(offset, source);
168 };
169 scrollable_ = AceType::MakeRefPtr<Scrollable>(
170 callback, useScrollable_ == SCROLLABLE::HORIZONTAL ? Axis::HORIZONTAL : Axis::VERTICAL);
171 scrollable_->SetScrollEndCallback([weak = AceType::WeakClaim(this)]() {
172 auto flow = weak.Upgrade();
173 if (flow) {
174 auto proxy = flow->scrollBarProxy_;
175 if (proxy) {
176 proxy->StartScrollBarAnimator();
177 }
178 auto scrollBar = flow->scrollBar_;
179 if (scrollBar) {
180 scrollBar->HandleScrollBarEnd();
181 }
182 }
183 });
184 scrollable_->Initialize(context_);
185 }
186
UpdateScrollPosition(double offset,int32_t source)187 bool RenderWaterFlow::UpdateScrollPosition(double offset, int32_t source)
188 {
189 if (source == SCROLL_FROM_START) {
190 return true;
191 }
192
193 if (NearZero(offset)) {
194 return true;
195 }
196 if (scrollBar_ && scrollBar_->NeedScrollBar()) {
197 scrollBar_->SetActive(SCROLL_FROM_CHILD != source);
198 }
199
200 if (reachHead_ && reachTail_) {
201 return false;
202 }
203
204 if (offset > 0.0) {
205 // view port move up
206 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
207 if (reachHead_) {
208 return false;
209 }
210 } else {
211 if (reachTail_) {
212 return false;
213 }
214 }
215 } else {
216 // view port move down
217 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
218 if (reachTail_) {
219 return false;
220 }
221 } else {
222 if (reachHead_) {
223 return false;
224 }
225 }
226 }
227 viewportStartPos_ -= offset;
228 MarkNeedLayout(true);
229
230 return true;
231 }
232
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)233 void RenderWaterFlow::OnTouchTestHit(
234 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
235 {
236 if (!GetVisible()) {
237 return;
238 }
239 if (!scrollable_ || !scrollable_->Available()) {
240 return;
241 }
242 if (scrollBar_ && scrollBar_->InBarRegion(globalPoint_ - coordinateOffset)) {
243 scrollBar_->AddScrollBarController(coordinateOffset, result);
244 } else {
245 scrollable_->SetCoordinateOffset(coordinateOffset);
246 scrollable_->SetDragTouchRestrict(touchRestrict);
247 result.emplace_back(scrollable_);
248 }
249 result.emplace_back(scrollable_);
250 }
251
IsChildrenTouchEnable()252 bool RenderWaterFlow::IsChildrenTouchEnable()
253 {
254 bool ret = scrollable_->IsMotionStop();
255 return ret;
256 }
257
SetChildPosition(const RefPtr<RenderNode> & child,size_t itemIndex)258 void RenderWaterFlow::SetChildPosition(const RefPtr<RenderNode>& child, size_t itemIndex)
259 {
260 Offset offset;
261 double mainPos = 0.0;
262 double crossPos = 0.0;
263 double mainSize = 0.0;
264 auto iter = flowMatrix_.find(itemIndex);
265 if (iter != flowMatrix_.end()) {
266 mainPos = iter->second.mainPos;
267 crossPos = iter->second.crossPos;
268 mainSize = iter->second.mainSize;
269 }
270 // need to support set position with Flex::Direction
271 switch (direction_) {
272 case FlexDirection::COLUMN:
273 // offset.y : item mainPos - viewPort offset
274 offset = Offset(crossPos, mainPos - viewportStartPos_);
275 break;
276 case FlexDirection::COLUMN_REVERSE:
277 // offset.y : [viewPort mainSize - (item mainSize + item mainPos)] - viewPort offse
278 offset = Offset(crossPos, (mainSize_ - (mainPos + mainSize)) - viewportStartPos_);
279 break;
280 case FlexDirection::ROW:
281 // offset.x : item mainPos - viewPort offset
282 offset = Offset(mainPos - viewportStartPos_, crossPos);
283 break;
284 case FlexDirection::ROW_REVERSE:
285 // offset.x : [viewPort mainSize - (item mainSize + item mainPos)] - viewPort offse
286 offset = Offset((mainSize_ - (mainPos + mainSize)) - viewportStartPos_, crossPos);
287 break;
288 default:
289 return;
290 }
291 child->SetPosition(offset);
292 child->SetVisible(true);
293 }
294
GetFlowSize()295 void RenderWaterFlow::GetFlowSize()
296 {
297 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
298 mainSize_ = GetLayoutParam().GetMaxSize().Height();
299 crossSize_ = GetLayoutParam().GetMaxSize().Width();
300 if (NearEqual(mainSize_, Size::INFINITE_SIZE)) {
301 mainSize_ = viewPort_.Height();
302 }
303 if (NearEqual(crossSize_, Size::INFINITE_SIZE)) {
304 crossSize_ = viewPort_.Width();
305 }
306 } else {
307 crossSize_ = GetLayoutParam().GetMaxSize().Height();
308 mainSize_ = GetLayoutParam().GetMaxSize().Width();
309 if (NearEqual(crossSize_, Size::INFINITE_SIZE)) {
310 crossSize_ = viewPort_.Height();
311 }
312 if (NearEqual(mainSize_, Size::INFINITE_SIZE)) {
313 mainSize_ = viewPort_.Width();
314 }
315 }
316 cacheSize_ = mainSize_ * CACHE_SIZE_SCALE;
317 }
318
CallGap()319 void RenderWaterFlow::CallGap()
320 {
321 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
322 mainGap_ = NormalizePercentToPx(userRowGap_, true);
323 crossGap_ = NormalizePercentToPx(userColGap_, false);
324 } else {
325 crossGap_ = NormalizePercentToPx(userRowGap_, true);
326 mainGap_ = NormalizePercentToPx(userColGap_, false);
327 }
328 if (GreatOrEqual(crossGap_, crossSize_)) {
329 crossGap_ = 0.0;
330 }
331 }
332
CallItemConstraintSize()333 void RenderWaterFlow::CallItemConstraintSize()
334 {
335 ItemConstraintSize size;
336 auto pipelineContext = GetContext().Upgrade();
337 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
338 size.maxCrossSize = std::max(NormalizePercentToPx(component_->GetMaxWidth(), false),
339 NormalizePercentToPx(component_->GetMinWidth(), false));
340 size.minCrossSize = std::min(NormalizePercentToPx(component_->GetMaxWidth(), false),
341 NormalizePercentToPx(component_->GetMinWidth(), false));
342 size.maxMainSize = std::max(NormalizePercentToPx(component_->GetMaxHeight(), true),
343 NormalizePercentToPx(component_->GetMinHeight(), true));
344 size.minMainSize = std::min(NormalizePercentToPx(component_->GetMaxHeight(), true),
345 NormalizePercentToPx(component_->GetMinHeight(), true));
346 mainMaxConstraintSize_ = MAX_CONSTRAINT_SCALE * pipelineContext->GetRootHeight();
347 } else {
348 size.maxCrossSize = std::max(NormalizePercentToPx(component_->GetMaxHeight(), true),
349 NormalizePercentToPx(component_->GetMinHeight(), true));
350 size.minCrossSize = std::min(NormalizePercentToPx(component_->GetMaxHeight(), true),
351 NormalizePercentToPx(component_->GetMinHeight(), true));
352 size.maxMainSize = std::max(NormalizePercentToPx(component_->GetMaxWidth(), false),
353 NormalizePercentToPx(component_->GetMinWidth(), false));
354 size.minMainSize = std::min(NormalizePercentToPx(component_->GetMaxWidth(), false),
355 NormalizePercentToPx(component_->GetMinWidth(), false));
356 mainMaxConstraintSize_ = MAX_CONSTRAINT_SCALE * pipelineContext->GetRootWidth();
357 }
358
359 // exchange and make sure the max is larger then the min.
360 itemConstraintSize_.maxCrossSize = std::max(size.maxCrossSize, size.minCrossSize);
361 itemConstraintSize_.minCrossSize = std::min(size.maxCrossSize, size.minCrossSize);
362 itemConstraintSize_.maxMainSize = std::max(size.maxMainSize, size.minMainSize);
363 itemConstraintSize_.minMainSize = std::min(size.maxMainSize, size.minMainSize);
364
365 // constraint with 3times of root.
366 if (GreatOrEqual(itemConstraintSize_.maxMainSize, mainMaxConstraintSize_)) {
367 itemConstraintSize_.maxMainSize = mainMaxConstraintSize_;
368 }
369 if (GreatOrEqual(itemConstraintSize_.minMainSize, mainMaxConstraintSize_)) {
370 itemConstraintSize_.minMainSize = 0.0;
371 }
372 // constraint with 0, and set with default.
373 if (LessOrEqual(itemConstraintSize_.maxMainSize, 0.0)) {
374 itemConstraintSize_.maxMainSize = mainMaxConstraintSize_;
375 }
376 if (LessOrEqual(itemConstraintSize_.minMainSize, 0.0)) {
377 itemConstraintSize_.minMainSize = 0.0;
378 }
379 }
380
InitialFlowProp()381 void RenderWaterFlow::InitialFlowProp()
382 {
383 // Not first time layout after update, no need to initialize.
384 if (!updateFlag_) {
385 return;
386 }
387
388 // Not valid layout size, no need to initialize.
389 auto maxLayoutSize = GetLayoutParam().GetMaxSize();
390 if (!maxLayoutSize.IsValid() || maxLayoutSize.IsEmpty()) {
391 return;
392 }
393
394 GetFlowSize();
395 CallGap();
396 CallItemConstraintSize();
397 crossSideSize_.clear();
398 TemplatesParser parser;
399 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
400 crossSideSize_ = parser.ParseArgs(WeakClaim(this), PreParseArgs(colsArgs_), crossSize_, crossGap_);
401 } else {
402 crossSideSize_ = parser.ParseArgs(WeakClaim(this), PreParseArgs(rowsArgs_), crossSize_, crossGap_);
403 }
404 if (crossSideSize_.empty()) {
405 crossSideSize_.push_back(crossSize_);
406 }
407 // Initialize the crossCount, default is 1
408 crossCount_ = crossSideSize_.size();
409 InitMainSideEndPos();
410 viewportStartPos_ = 0.0;
411 RemoveAllChild();
412 ClearLayout(0, true);
413 if (footer_) {
414 RemoveChild(footer_);
415 footer_ = nullptr;
416 }
417 RequestWaterFlowFooter();
418 updateFlag_ = false;
419 }
420
MakeInnerLayoutParam(size_t itemIndex)421 LayoutParam RenderWaterFlow::MakeInnerLayoutParam(size_t itemIndex)
422 {
423 LayoutParam innerLayout;
424 double crossSize = 0.0;
425 size_t crossIndex = 0;
426 auto iter = flowMatrix_.find(itemIndex);
427 if (iter != flowMatrix_.end()) {
428 crossSize = iter->second.crossSize;
429 } else {
430 crossIndex = GetLastMainBlankCross();
431 if (crossIndex < crossSideSize_.size()) {
432 crossSize = crossSideSize_[crossIndex];
433 }
434 }
435 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
436 innerLayout.SetMinSize(Size(crossSize, 0));
437 innerLayout.SetMaxSize(Size(crossSize, Size::INFINITE_SIZE));
438 } else {
439 innerLayout.SetMinSize(Size(0, crossSize));
440 innerLayout.SetMaxSize(Size(Size::INFINITE_SIZE, crossSize));
441 }
442 return innerLayout;
443 }
444
SupplyItems(size_t startIndex,double targetPos)445 void RenderWaterFlow::SupplyItems(size_t startIndex, double targetPos)
446 {
447 size_t itemCrossIndex = 0;
448 FlowStyle itemFlowStyle;
449 while (LessNotEqual(GetLastMainBlankPos().GetY(), targetPos)) {
450 if (items_.find(startIndex) == items_.end()) {
451 if (!buildChildByIndex_(startIndex)) {
452 break;
453 }
454 }
455
456 auto flowItem = GetFlowItemByChild(items_[startIndex]);
457 if (flowItem == nullptr) {
458 startIndex++;
459 continue;
460 }
461 flowItem->SetNeedRender(false);
462 flowItem->Layout(MakeInnerLayoutParam(startIndex));
463 flowItem->SetVisible(false);
464 itemCrossIndex = GetLastMainBlankCross();
465 itemFlowStyle.mainPos = GetLastMainBlankPos().GetY();
466 itemFlowStyle.crossPos = GetLastMainBlankPos().GetX();
467 itemFlowStyle.mainSize = GetMainSize(flowItem);
468 itemFlowStyle = ConstraintItemSize(itemFlowStyle, itemCrossIndex);
469 flowMatrix_.emplace(std::make_pair(startIndex, itemFlowStyle));
470 if (itemsByCrossIndex_.size() > itemCrossIndex) {
471 itemsByCrossIndex_.at(itemCrossIndex).emplace_back(startIndex);
472 }
473 if (itemCrossIndex < mainSideEndPos_.size()) {
474 mainSideEndPos_[itemCrossIndex] +=
475 Positive(itemFlowStyle.mainSize) ? (itemFlowStyle.mainSize + mainGap_) : itemFlowStyle.mainSize;
476 }
477
478 // reach the valid target index
479 if (targetIndex_ >= 0 && static_cast<size_t>(targetIndex_) == startIndex) {
480 targetPos = itemFlowStyle.mainPos + mainSize_;
481 }
482 startIndex++;
483 }
484 targetIndex_ = -1;
485 }
486
LayoutItems(std::set<size_t> & items)487 void RenderWaterFlow::LayoutItems(std::set<size_t>& items)
488 {
489 LayoutParam innerLayoutParam;
490 for (const auto& itemIndex : items) {
491 if (items_.find(itemIndex) == items_.end()) {
492 if (!buildChildByIndex_(itemIndex)) {
493 continue;
494 }
495 }
496 innerLayoutParam = MakeInnerLayoutParam(itemIndex);
497 auto flowItem = GetFlowItemByChild(items_[itemIndex]);
498 if (flowItem == nullptr) {
499 continue;
500 }
501 flowItem->Layout(innerLayoutParam);
502 SetChildPosition(flowItem, itemIndex);
503 }
504 }
505
GetFooterSize(double mainSize,double crossSize)506 void RenderWaterFlow::GetFooterSize(double mainSize, double crossSize)
507 {
508 if (!footer_ || NonPositive(mainSize) || NonPositive(crossSize)) {
509 LOGE("footer is null");
510 return;
511 }
512 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
513 footerMaxSize_.SetWidth(std::min(crossSize, crossSize_));
514 footerMaxSize_.SetHeight(std::min(mainSize, mainSize_));
515 } else {
516 footerMaxSize_.SetWidth(std::min(mainSize, mainSize_));
517 footerMaxSize_.SetHeight(std::min(crossSize, crossSize_));
518 }
519 }
520
LayoutFooter()521 void RenderWaterFlow::LayoutFooter()
522 {
523 if (!footer_) {
524 LOGE("footer is null");
525 return;
526 }
527 footer_->SetVisible(false);
528 LayoutParam innerLayoutParam;
529 innerLayoutParam.SetMaxSize(footerMaxSize_);
530 footer_->Layout(innerLayoutParam);
531 SetFooterPosition();
532 }
533
SetFooterPosition()534 void RenderWaterFlow::SetFooterPosition()
535 {
536 if (!footer_) {
537 return;
538 }
539 Offset offset;
540 auto width = footerMaxSize_.Width();
541 auto height = footerMaxSize_.Height();
542 auto footerCurrentPos = GetTailPos();
543 switch (direction_) {
544 case FlexDirection::COLUMN:
545 offset = Offset((crossSize_ - width) / CENTER_POINT, footerCurrentPos - viewportStartPos_);
546 if (GreatOrEqual(offset.GetY(), mainSize_)) {
547 return;
548 }
549 break;
550 case FlexDirection::COLUMN_REVERSE:
551 offset = Offset((crossSize_ - width) / CENTER_POINT, footerCurrentPos - viewportStartPos_ - height);
552 if (LessOrEqual(offset.GetY(), -height)) {
553 return;
554 }
555 break;
556 case FlexDirection::ROW:
557 offset = Offset(footerCurrentPos - viewportStartPos_, (crossSize_ - height) / CENTER_POINT);
558 if (GreatOrEqual(offset.GetX(), mainSize_)) {
559 return;
560 }
561 break;
562 case FlexDirection::ROW_REVERSE:
563 offset = Offset(footerCurrentPos - viewportStartPos_ - width, (crossSize_ - height) / CENTER_POINT);
564 if (LessOrEqual(offset.GetX(), -width)) {
565 return;
566 }
567 break;
568 default:
569 return;
570 }
571 footer_->SetPosition(offset);
572 footer_->SetVisible(true);
573 }
574
UpdateCacheItems()575 void RenderWaterFlow::UpdateCacheItems()
576 {
577 cacheItems_.clear();
578 double itemMainMinPos = 0.0;
579 double itemMainMaxPos = 0.0;
580 double viewportEndPos = viewportStartPos_ + mainSize_ + cacheSize_;
581 for (const auto& item : flowMatrix_) {
582 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
583 itemMainMinPos = item.second.mainPos;
584 itemMainMaxPos = item.second.mainPos + item.second.mainSize;
585 } else {
586 itemMainMinPos = (mainSize_ - (item.second.mainPos + item.second.mainSize));
587 itemMainMaxPos = (mainSize_ - (item.second.mainPos + item.second.mainSize)) + item.second.mainSize;
588 }
589 if (!(GreatNotEqual(itemMainMinPos, viewportEndPos) ||
590 LessNotEqual(itemMainMaxPos, viewportStartPos_ - cacheSize_))) {
591 cacheItems_.emplace(item.first);
592 }
593 }
594 }
595
GetShowItems()596 std::set<size_t> RenderWaterFlow::GetShowItems()
597 {
598 std::set<size_t> showItems;
599 showItems.clear();
600 double itemMainMinPos = 0.0;
601 double itemMainMaxPos = 0.0;
602 double viewportEndPos = viewportStartPos_ + mainSize_;
603 for (const auto& item : cacheItems_) {
604 auto iter = flowMatrix_.find(item);
605 if (iter != flowMatrix_.end()) {
606 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
607 itemMainMinPos = iter->second.mainPos;
608 itemMainMaxPos = iter->second.mainPos + iter->second.mainSize;
609 } else {
610 itemMainMinPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize));
611 itemMainMaxPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize;
612 }
613 if (!(GreatNotEqual(itemMainMinPos, viewportEndPos) || LessNotEqual(itemMainMaxPos, viewportStartPos_))) {
614 showItems.emplace(item);
615 }
616 }
617 }
618 return showItems;
619 }
620
DealCache()621 void RenderWaterFlow::DealCache()
622 {
623 std::set<size_t> deleteItem;
624 double itemMainMinPos = 0.0;
625 double itemMainMaxPos = 0.0;
626 double cacheStartPos = viewportStartPos_ - cacheSize_;
627 double cacheEndPos = viewportStartPos_ + mainSize_ + cacheSize_;
628 for (const auto& item : items_) {
629 auto iter = flowMatrix_.find(item.first);
630 if (iter != flowMatrix_.end()) {
631 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
632 itemMainMinPos = iter->second.mainPos;
633 itemMainMaxPos = iter->second.mainPos + iter->second.mainSize;
634 } else {
635 itemMainMinPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize));
636 itemMainMaxPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize;
637 }
638 if (GreatNotEqual(itemMainMinPos, cacheEndPos) || LessNotEqual(itemMainMaxPos, cacheStartPos)) {
639 deleteItem.emplace(item.first);
640 }
641 }
642 }
643
644 for (const auto& item : deleteItem) {
645 DeleteItems(item);
646 }
647 }
648
DeleteItems(size_t index)649 void RenderWaterFlow::DeleteItems(size_t index)
650 {
651 if (!deleteChildByIndex_) {
652 return;
653 }
654
655 auto iter = items_.find(index);
656 if (iter == items_.end()) {
657 return;
658 }
659 deleteChildByIndex_(index);
660 RemoveChildByIndex(index);
661 }
662
ClearLayout(size_t index,bool clearAll)663 void RenderWaterFlow::ClearLayout(size_t index, bool clearAll)
664 {
665 cacheItems_.clear();
666 reachHead_ = false;
667 reachTail_ = false;
668 lastOffset_ = 0.0;
669 ClearFlowMatrix(index, clearAll);
670 ClearItemsByCrossIndex(index, clearAll);
671 UpdateMainSideEndPos();
672 }
673
ClearItems(size_t index)674 void RenderWaterFlow::ClearItems(size_t index)
675 {
676 for (auto item = items_.begin(); item != items_.end();) {
677 if (index <= item->first) {
678 item->second->SetVisible(false);
679 item = items_.erase(item);
680 } else {
681 item++;
682 }
683 }
684 }
685
OnDataSourceUpdated(size_t index)686 void RenderWaterFlow::OnDataSourceUpdated(size_t index)
687 {
688 if (items_.empty() && updateFlag_) {
689 return;
690 }
691
692 if (!getTotalCount_) {
693 return;
694 }
695
696 totalCount_ = getTotalCount_();
697 ClearItems(index);
698 ClearLayout(index);
699 MarkNeedLayout();
700 }
701
GetEstimatedHeight()702 double RenderWaterFlow::GetEstimatedHeight()
703 {
704 estimateHeight_ =
705 std::min(std::max(estimateHeight_, (std::abs(viewportStartPos_) + mainSize_)), GetLastMainPos().GetY());
706 return estimateHeight_;
707 }
708
InitScrollBar()709 void RenderWaterFlow::InitScrollBar()
710 {
711 if (!component_) {
712 LOGE("RenderWaterFlow update failed.");
713 EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
714 return;
715 }
716
717 if (scrollBar_) {
718 scrollBar_->SetDisplayMode(component_->GetScrollBarDisplayMode());
719 scrollBar_->Reset();
720 return;
721 }
722
723 const RefPtr<ScrollBarTheme> theme = GetTheme<ScrollBarTheme>();
724 if (!theme) {
725 return;
726 }
727
728 RefPtr<WaterFlowScrollController> controller = AceType::MakeRefPtr<WaterFlowScrollController>();
729 scrollBar_ = AceType::MakeRefPtr<ScrollBar>(component_->GetScrollBarDisplayMode(), theme->GetShapeMode());
730 scrollBar_->SetScrollBarController(controller);
731
732 // set the scroll bar style
733 scrollBar_->SetMinHeight(theme->GetMinHeight());
734 scrollBar_->SetMinDynamicHeight(theme->GetMinDynamicHeight());
735 scrollBar_->SetForegroundColor(theme->GetForegroundColor());
736 scrollBar_->SetBackgroundColor(theme->GetBackgroundColor());
737 scrollBar_->SetPadding(theme->GetPadding());
738 scrollBar_->SetInactiveWidth(theme->GetNormalWidth());
739 scrollBar_->SetNormalWidth(theme->GetNormalWidth());
740 scrollBar_->SetActiveWidth(theme->GetActiveWidth());
741 scrollBar_->SetTouchWidth(theme->GetTouchWidth());
742 switch (direction_) {
743 case FlexDirection::COLUMN:
744 case FlexDirection::COLUMN_REVERSE:
745 useScrollable_ = SCROLLABLE::VERTICAL;
746 scrollBar_->SetPositionMode(PositionMode::RIGHT);
747 break;
748 case FlexDirection::ROW:
749 case FlexDirection::ROW_REVERSE:
750 useScrollable_ = SCROLLABLE::HORIZONTAL;
751 scrollBar_->SetPositionMode(PositionMode::BOTTOM);
752 break;
753 default:
754 break;
755 }
756 scrollBar_->InitScrollBar(AceType::WeakClaim(this), GetContext());
757 SetScrollBarCallback();
758 }
759
InitScrollBarProxy()760 void RenderWaterFlow::InitScrollBarProxy()
761 {
762 if (!scrollBarProxy_) {
763 return;
764 }
765 auto&& scrollCallback = [weakScroll = AceType::WeakClaim(this)](double value, int32_t source) {
766 auto flow = weakScroll.Upgrade();
767 if (!flow) {
768 return false;
769 }
770 return flow->UpdateScrollPosition(value, source);
771 };
772 scrollBarProxy_->UnRegisterScrollableNode(AceType::WeakClaim(this));
773 scrollBarProxy_->RegisterScrollableNode({ AceType::WeakClaim(this), scrollCallback });
774 }
775
SetScrollBarCallback()776 void RenderWaterFlow::SetScrollBarCallback()
777 {
778 if (!scrollBar_ || !scrollBar_->NeedScrollBar()) {
779 return;
780 }
781 auto&& barEndCallback = [weakFlow = AceType::WeakClaim(this)](int32_t value) {
782 auto flow = weakFlow.Upgrade();
783 if (!flow) {
784 return;
785 }
786 flow->scrollBarOpacity_ = value;
787 flow->MarkNeedLayout(true);
788 };
789 auto&& scrollEndCallback = [weakFlow = AceType::WeakClaim(this)]() {
790 auto flow = weakFlow.Upgrade();
791 if (!flow) {
792 return;
793 }
794 };
795 auto&& scrollCallback = [weakScroll = AceType::WeakClaim(this)](double value, int32_t source) {
796 auto flow = weakScroll.Upgrade();
797 if (!flow) {
798 return false;
799 }
800 return flow->UpdateScrollPosition(value, source);
801 };
802 scrollBar_->SetCallBack(scrollCallback, barEndCallback, scrollEndCallback);
803 }
804
ScrollToIndex(int32_t index)805 void RenderWaterFlow::ScrollToIndex(int32_t index)
806 {
807 if (useScrollable_ == SCROLLABLE::NO_SCROLL || index < 0) {
808 LOGW("Not supported.");
809 return;
810 }
811
812 auto context = context_.Upgrade();
813 if (!context) {
814 LOGE("context is null");
815 return;
816 }
817
818 auto iter = flowMatrix_.find(index);
819 if (iter == flowMatrix_.end()) {
820 targetIndex_ = index;
821 size_t itemIndex = GetNextSupplyedIndex();
822 SupplyItems(itemIndex, GetTargetPos());
823 iter = flowMatrix_.find(index);
824 if (iter == flowMatrix_.end()) {
825 LOGE("scrollToIndex[item:%{public}d] failed.", index);
826 return;
827 }
828 }
829
830 double scrollToPos = 0.0;
831 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
832 scrollToPos = iter->second.mainPos;
833 } else {
834 scrollToPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize - mainSize_;
835 }
836 AnimateToPos(scrollToPos, ANIMATE_DURATION, CURVE_SCROLL_TO_TOP);
837 }
838
DoJump(double position,int32_t source)839 void RenderWaterFlow::DoJump(double position, int32_t source)
840 {
841 UpdateScrollPosition(viewportStartPos_ - position, source);
842 }
843
OnPredictLayout(int64_t deadline)844 void RenderWaterFlow::OnPredictLayout(int64_t deadline)
845 {
846 if (!NeedPredictLayout()) {
847 return;
848 }
849 auto context = context_.Upgrade();
850 if (!context) {
851 return;
852 }
853 if (!context->IsTransitionStop()) {
854 MarkNeedPredictLayout();
855 return;
856 }
857
858 auto startTime = GetSysTimestamp(); // unit: ns
859 DealCache();
860 if (GetSysTimestamp() - startTime + TIME_THRESHOLD > deadline * MICROSEC_TO_NANOSEC) {
861 MarkNeedPredictLayout();
862 return;
863 }
864
865 // just need supply forward the main side, backwards already supply and keep in flowMatrix.
866 size_t itemIndex = GetNextSupplyedIndex();
867 SupplyItems(itemIndex, GetCacheTargetPos());
868 UpdateCacheItems();
869 LayoutItems(cacheItems_);
870 dVPStartPosBackup_ = viewportStartPos_;
871 totalCountBack_ = getTotalCount_();
872 MarkNeedPredictLayout();
873 }
874
IsAxisScrollable(AxisDirection direction)875 bool RenderWaterFlow::IsAxisScrollable(AxisDirection direction)
876 {
877 bool ret = true;
878 switch (direction_) {
879 case FlexDirection::COLUMN:
880 if ((direction == AxisDirection::UP && reachHead_) ||
881 (direction == AxisDirection::DOWN && reachTail_)) {
882 ret = false;
883 }
884 break;
885 case FlexDirection::ROW:
886 if ((direction == AxisDirection::LEFT && reachHead_) ||
887 (direction == AxisDirection::RIGHT && reachTail_)) {
888 ret = false;
889 }
890 break;
891 case FlexDirection::COLUMN_REVERSE:
892 if ((direction == AxisDirection::DOWN && reachHead_) ||
893 (direction == AxisDirection::UP && reachTail_)) {
894 ret = false;
895 }
896 break;
897 case FlexDirection::ROW_REVERSE:
898 if ((direction == AxisDirection::RIGHT && reachHead_) ||
899 (direction == AxisDirection::LEFT && reachTail_)) {
900 ret = false;
901 }
902 break;
903 default:
904 ret = false;
905 break;
906 }
907 if (direction == AxisDirection::NONE) {
908 ret = false;
909 }
910 return ret;
911 }
912
HandleAxisEvent(const AxisEvent & event)913 void RenderWaterFlow::HandleAxisEvent(const AxisEvent& event)
914 {
915 double degree = 0.0;
916 if (!NearZero(event.horizontalAxis)) {
917 degree = event.horizontalAxis;
918 } else if (!NearZero(event.verticalAxis)) {
919 degree = event.verticalAxis;
920 }
921 double offset =
922 PipelineBase::Vp2PxWithCurrentDensity(DP_PER_LINE_DESKTOP * LINE_NUMBER_DESKTOP * degree / MOUSE_WHEEL_DEGREES);
923 UpdateScrollPosition(-offset, SCROLL_FROM_ROTATE);
924 }
925
CheckAxisNode()926 WeakPtr<RenderNode> RenderWaterFlow::CheckAxisNode()
927 {
928 return AceType::WeakClaim<RenderNode>(this);
929 }
930
OnChildAdded(const RefPtr<RenderNode> & renderNode)931 void RenderWaterFlow::OnChildAdded(const RefPtr<RenderNode>& renderNode)
932 {
933 Offset offset;
934 switch (direction_) {
935 case FlexDirection::COLUMN:
936 offset.SetX(crossSize_ / CENTER_POINT);
937 offset.SetY(mainSize_ + cacheSize_);
938 break;
939 case FlexDirection::ROW:
940 offset.SetX(mainSize_ + cacheSize_);
941 offset.SetY(crossSize_ / CENTER_POINT);
942 break;
943 case FlexDirection::COLUMN_REVERSE:
944 offset.SetX(crossSize_ / CENTER_POINT);
945 offset.SetY(0.0 - cacheSize_);
946 break;
947 case FlexDirection::ROW_REVERSE:
948 offset.SetX(0.0 - cacheSize_);
949 offset.SetY(crossSize_ / CENTER_POINT);
950 break;
951 default:
952 break;
953 }
954 // set default position for animateTo(covering animation)
955 renderNode->SetPosition(offset);
956 RenderNode::OnChildAdded(renderNode);
957 }
958
IsUseOnly()959 bool RenderWaterFlow::IsUseOnly()
960 {
961 return true;
962 }
963
GetFlowItemByChild(const RefPtr<RenderNode> & child)964 RefPtr<RenderWaterFlowItem> RenderWaterFlow::GetFlowItemByChild(const RefPtr<RenderNode>& child)
965 {
966 int32_t depth = DEFAULT_DEPTH;
967 auto item = child;
968 auto flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
969 while (!flowItem && depth > 0) {
970 if (!item || item->GetChildren().empty()) {
971 return nullptr;
972 }
973 item = item->GetChildren().front();
974 flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
975 --depth;
976 }
977 return flowItem;
978 }
979
OutputMatrix()980 void RenderWaterFlow::OutputMatrix() {}
981
RequestWaterFlowFooter()982 void RenderWaterFlow::RequestWaterFlowFooter()
983 {
984 auto generator = itemGenerator_.Upgrade();
985 footer_ = generator ? generator->RequestWaterFlowFooter() : RefPtr<RenderNode>();
986 if (footer_) {
987 AddChild(footer_);
988 footer_->Layout(GetLayoutParam());
989 footer_->SetVisible(false);
990 auto mainSize = GetMainSize(footer_);
991 auto crossSize = GetCrossSize(footer_);
992 if (NonPositive(mainSize) || NonPositive(crossSize)) {
993 RemoveChild(footer_);
994 footer_ = nullptr;
995 } else {
996 GetFooterSize(mainSize, crossSize);
997 }
998 }
999 }
1000
GetLastSupplyedIndex()1001 size_t RenderWaterFlow::GetLastSupplyedIndex()
1002 {
1003 return flowMatrix_.empty() ? 0 : (--flowMatrix_.end())->first;
1004 }
1005
GetNextSupplyedIndex()1006 size_t RenderWaterFlow::GetNextSupplyedIndex()
1007 {
1008 size_t index = 0;
1009 if (!flowMatrix_.empty()) {
1010 index = (--flowMatrix_.end())->first;
1011 index++;
1012 }
1013 return index;
1014 }
1015
GetLastSupplyedMainSize()1016 double RenderWaterFlow::GetLastSupplyedMainSize()
1017 {
1018 double result = 0.0;
1019 if (flowMatrix_.empty()) {
1020 return result;
1021 }
1022 size_t index = GetLastSupplyedIndex();
1023 auto iter = flowMatrix_.find(index);
1024 if (iter != flowMatrix_.end()) {
1025 result = iter->second.mainSize + iter->second.mainPos;
1026 }
1027 return result;
1028 }
1029
GetLastMainBlankPos()1030 Offset RenderWaterFlow::GetLastMainBlankPos()
1031 {
1032 Offset pos;
1033 size_t crossIndex = 0;
1034 if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1035 return pos;
1036 }
1037 pos.SetY(mainSideEndPos_.at(0));
1038 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1039 if (LessNotEqual(mainSideEndPos_.at(i), pos.GetY())) {
1040 pos.SetY(mainSideEndPos_.at(i));
1041 crossIndex = i;
1042 }
1043 }
1044 pos.SetX(GetCrossEndPos(crossIndex));
1045 return pos;
1046 }
1047
GetLastMainBlankCross()1048 size_t RenderWaterFlow::GetLastMainBlankCross()
1049 {
1050 double pos = 0.0;
1051 size_t crossIndex = 0;
1052 if (mainSideEndPos_.empty()) {
1053 return crossIndex;
1054 }
1055 pos = mainSideEndPos_.at(0);
1056 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1057 if (LessNotEqual(mainSideEndPos_.at(i), pos)) {
1058 pos = mainSideEndPos_.at(i);
1059 crossIndex = i;
1060 }
1061 }
1062 return crossIndex;
1063 }
1064
GetLastMainPos()1065 Offset RenderWaterFlow::GetLastMainPos()
1066 {
1067 Offset pos(0.0, 0.0);
1068 size_t crossIndex = 0;
1069 if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1070 return pos;
1071 }
1072 double tempMainSidePos = mainSideEndPos_.at(0);
1073 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1074 if (GreatNotEqual(mainSideEndPos_.at(i), tempMainSidePos)) {
1075 tempMainSidePos = mainSideEndPos_.at(i);
1076 crossIndex = i;
1077 }
1078 }
1079 pos.SetY(mainSideEndPos_.at(crossIndex) - mainGap_);
1080 pos.SetX(GetCrossEndPos(crossIndex));
1081 return pos;
1082 }
1083
GetCrossEndPos(size_t crossIndex)1084 double RenderWaterFlow::GetCrossEndPos(size_t crossIndex)
1085 {
1086 double pos = 0.0;
1087 if (crossIndex >= crossSideSize_.size()) {
1088 return pos;
1089 }
1090 for (size_t i = 0; i < crossIndex; i++) {
1091 pos += crossSideSize_[i];
1092 }
1093 if (crossIndex > 0) {
1094 pos += crossIndex * crossGap_;
1095 }
1096
1097 return pos;
1098 }
1099
GetMainSize(const RefPtr<RenderNode> & item) const1100 double RenderWaterFlow::GetMainSize(const RefPtr<RenderNode>& item) const
1101 {
1102 double size = 0.0;
1103 if (!item) {
1104 return size;
1105 }
1106 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1107 size = item->GetLayoutSize().Height();
1108 } else {
1109 size = item->GetLayoutSize().Width();
1110 }
1111
1112 return size;
1113 }
1114
GetCrossSize(const RefPtr<RenderNode> & item) const1115 double RenderWaterFlow::GetCrossSize(const RefPtr<RenderNode>& item) const
1116 {
1117 double size = 0.0;
1118 if (!item) {
1119 return size;
1120 }
1121
1122 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1123 size = item->GetLayoutSize().Width();
1124 } else {
1125 size = item->GetLayoutSize().Height();
1126 }
1127
1128 return size;
1129 }
1130
ConstraintItemSize(FlowStyle item,size_t crossIndex)1131 FlowStyle RenderWaterFlow::ConstraintItemSize(FlowStyle item, size_t crossIndex)
1132 {
1133 FlowStyle result = item;
1134 if (GreatNotEqual(result.mainSize, itemConstraintSize_.maxMainSize)) {
1135 result.mainSize = itemConstraintSize_.maxMainSize;
1136 }
1137 if (LessNotEqual(result.mainSize, itemConstraintSize_.minMainSize)) {
1138 result.mainSize = itemConstraintSize_.minMainSize;
1139 }
1140 if (crossIndex < crossSideSize_.size()) {
1141 result.crossSize = crossSideSize_[crossIndex];
1142 }
1143 return result;
1144 }
1145
CheckReachHead()1146 bool RenderWaterFlow::CheckReachHead()
1147 {
1148 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1149 return LessOrEqual(viewportStartPos_, 0.0);
1150 }
1151 return LessOrEqual(0.0, viewportStartPos_);
1152 }
1153
CheckReachTail()1154 bool RenderWaterFlow::CheckReachTail()
1155 {
1156 double tailPos = GetTailPos();
1157 double footerOffset = 0.0;
1158 if (footer_) {
1159 switch (direction_) {
1160 case FlexDirection::COLUMN:
1161 case FlexDirection::COLUMN_REVERSE:
1162 footerOffset = footerMaxSize_.Height();
1163 break;
1164 case FlexDirection::ROW:
1165 case FlexDirection::ROW_REVERSE:
1166 footerOffset = footerMaxSize_.Width();
1167 break;
1168 default:
1169 break;
1170 }
1171 }
1172 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1173 return (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset));
1174 }
1175 return (GreatOrEqual(tailPos - footerOffset, viewportStartPos_));
1176 }
1177
AdjustViewPort()1178 void RenderWaterFlow::AdjustViewPort()
1179 {
1180 double tailPos = GetTailPos();
1181 double footerOffset = 0.0;
1182 if (footer_) {
1183 switch (direction_) {
1184 case FlexDirection::COLUMN:
1185 case FlexDirection::COLUMN_REVERSE:
1186 footerOffset = footerMaxSize_.Height();
1187 break;
1188 case FlexDirection::ROW:
1189 case FlexDirection::ROW_REVERSE:
1190 footerOffset = footerMaxSize_.Width();
1191 break;
1192 default:
1193 break;
1194 }
1195 }
1196
1197 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1198 // Correct the position of view port to avoid oversize offset from scroller
1199 viewportStartPos_ = std::max(viewportStartPos_, 0.0);
1200 if (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset)) {
1201 viewportStartPos_ = std::max((tailPos + footerOffset - mainSize_), 0.0);
1202 }
1203 } else {
1204 // Correct the position of view port to avoid oversize offset from scroller
1205 viewportStartPos_ = std::min(viewportStartPos_, 0.0);
1206 if (GreatOrEqual(tailPos - footerOffset, viewportStartPos_)) {
1207 viewportStartPos_ = std::min(tailPos - footerOffset, 0.0);
1208 }
1209 }
1210 }
1211
GetTailPos()1212 double RenderWaterFlow::GetTailPos()
1213 {
1214 double result = 0.0;
1215 if (!getTotalCount_) {
1216 return result;
1217 }
1218
1219 if (flowMatrix_.empty()) {
1220 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1221 return result;
1222 }
1223 return mainSize_;
1224 }
1225
1226 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1227 result = DBL_MAX;
1228 } else {
1229 result = -DBL_MAX;
1230 }
1231
1232 totalCount_ = getTotalCount_();
1233 auto iter = flowMatrix_.find(totalCount_ - 1);
1234 if (iter != flowMatrix_.end()) {
1235 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1236 result = GetLastMainPos().GetY();
1237 } else {
1238 result = mainSize_ - GetLastMainPos().GetY();
1239 }
1240 }
1241 return result;
1242 }
1243
GetTargetPos()1244 double RenderWaterFlow::GetTargetPos()
1245 {
1246 double result = 0.0;
1247 // valid targetIndex_
1248 if (targetIndex_ >= 0) {
1249 auto iter = flowMatrix_.find(targetIndex_);
1250 if (iter != flowMatrix_.end()) {
1251 result = iter->second.mainPos;
1252 } else {
1253 result = DBL_MAX;
1254 }
1255 } else {
1256 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1257 result = viewportStartPos_ + mainSize_;
1258 } else {
1259 result = -viewportStartPos_ + mainSize_;
1260 }
1261 }
1262 return result;
1263 }
1264
GetCacheTargetPos() const1265 double RenderWaterFlow::GetCacheTargetPos() const
1266 {
1267 return viewportStartPos_ + mainSize_ + cacheSize_;
1268 }
1269
AnimateToPos(const double & position,int32_t duration,const RefPtr<Curve> & curve)1270 void RenderWaterFlow::AnimateToPos(const double& position, int32_t duration, const RefPtr<Curve>& curve)
1271 {
1272 if (!animator_->IsStopped()) {
1273 animator_->Stop();
1274 }
1275 animator_->ClearInterpolators();
1276 auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(viewportStartPos_, position, curve);
1277 animation->AddListener([weakScroll = AceType::WeakClaim(this)](double value) {
1278 auto scroll = weakScroll.Upgrade();
1279 if (scroll) {
1280 scroll->DoJump(value, SCROLL_FROM_ANIMATION);
1281 }
1282 });
1283 animator_->AddInterpolator(animation);
1284 animator_->SetDuration(duration);
1285 animator_->ClearStopListeners();
1286 animator_->Play();
1287 }
1288
ClearFlowMatrix(size_t index,bool clearAll)1289 void RenderWaterFlow::ClearFlowMatrix(size_t index, bool clearAll)
1290 {
1291 if (!clearAll) {
1292 for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
1293 if (it->first >= index) {
1294 it = flowMatrix_.erase(it);
1295 } else {
1296 it++;
1297 }
1298 }
1299 } else {
1300 flowMatrix_.clear();
1301 }
1302 }
1303
ClearItemsByCrossIndex(size_t index,bool clearAll)1304 void RenderWaterFlow::ClearItemsByCrossIndex(size_t index, bool clearAll)
1305 {
1306 if (!clearAll) {
1307 for (auto& cross : itemsByCrossIndex_) {
1308 for (auto item = cross.begin(); item != cross.end();) {
1309 if (*item >= index) {
1310 item = cross.erase(item);
1311 } else {
1312 item++;
1313 }
1314 }
1315 }
1316 } else {
1317 itemsByCrossIndex_.clear();
1318 std::vector<size_t> item;
1319 for (size_t i = 0; i < crossCount_; i++) {
1320 itemsByCrossIndex_.emplace_back(item);
1321 }
1322 }
1323 }
1324
UpdateMainSideEndPos()1325 void RenderWaterFlow::UpdateMainSideEndPos()
1326 {
1327 if (mainSideEndPos_.size() != itemsByCrossIndex_.size()) {
1328 return;
1329 }
1330
1331 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1332 int32_t maxIndex = -1;
1333 for (size_t j : itemsByCrossIndex_[i]) {
1334 maxIndex = std::max(maxIndex, static_cast<int32_t>(j));
1335 }
1336 auto iter = flowMatrix_.find(maxIndex);
1337 if (iter != flowMatrix_.end()) {
1338 mainSideEndPos_.at(i) = iter->second.mainPos + iter->second.mainSize + mainGap_;
1339 } else {
1340 mainSideEndPos_.at(i) = 0.0;
1341 }
1342 }
1343 }
1344
InitMainSideEndPos()1345 void RenderWaterFlow::InitMainSideEndPos()
1346 {
1347 mainSideEndPos_.clear();
1348 for (size_t i = 0; i < crossCount_; i++) {
1349 mainSideEndPos_.emplace_back(0.0);
1350 }
1351 }
1352
RemoveAllChild()1353 void RenderWaterFlow::RemoveAllChild()
1354 {
1355 items_.clear();
1356 ClearChildren();
1357 }
1358
NeedPredictLayout()1359 bool RenderWaterFlow::NeedPredictLayout()
1360 {
1361 return !(updateFlag_ || (NearEqual(dVPStartPosBackup_, viewportStartPos_) &&
1362 (totalCountBack_ == getTotalCount_())));
1363 }
1364
PreParseArgs(const std::string & args)1365 std::string RenderWaterFlow::PreParseArgs(const std::string& args)
1366 {
1367 if (args.empty() || args.find(UNIT_AUTO) == std::string::npos) {
1368 return args;
1369 }
1370 std::string rowsArgs;
1371 std::vector<std::string> strs;
1372 StringUtils::StringSplitter(args, ' ', strs);
1373 std::string current;
1374 size_t rowArgSize = strs.size();
1375 for (size_t i = 0; i < rowArgSize; ++i) {
1376 current = strs[i];
1377 // "auto" means 1fr in waterflow
1378 if (strs[i] == std::string(UNIT_AUTO)) {
1379 current = "1fr";
1380 }
1381 rowsArgs += ' ' + current;
1382 }
1383 return rowsArgs;
1384 }
1385
HandleScrollEvent()1386 void RenderWaterFlow::HandleScrollEvent()
1387 {
1388 for (auto& event : waterflowEventFlags_) {
1389 switch (event.first) {
1390 case WaterFlowEvents::REACH_START:
1391 if (event.second) {
1392 ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachStart);
1393 event.second = false;
1394 }
1395 break;
1396 case WaterFlowEvents::REACH_END:
1397 if (event.second) {
1398 ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachEnd);
1399 event.second = false;
1400 }
1401 break;
1402 default:
1403 LOGW("This event does not handle in here, please check. event number: %{public}d", event.first);
1404 break;
1405 }
1406 }
1407 }
1408 } // namespace OHOS::Ace::V2
1409