1 /*
2 * Copyright (c) 2022 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_ = AceType::MakeRefPtr<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,int32_t source)805 void RenderWaterFlow::ScrollToIndex(int32_t index, int32_t source)
806 {
807 if (source != SCROLL_FROM_JUMP) {
808 LOGW("Not from scroll jump.");
809 return;
810 }
811
812 if (useScrollable_ == SCROLLABLE::NO_SCROLL || index < 0) {
813 LOGW("Not supported.");
814 return;
815 }
816
817 auto context = context_.Upgrade();
818 if (!context) {
819 LOGE("context is null");
820 return;
821 }
822
823 auto iter = flowMatrix_.find(index);
824 if (iter == flowMatrix_.end()) {
825 targetIndex_ = index;
826 size_t itemIndex = GetNextSupplyedIndex();
827 SupplyItems(itemIndex, GetTargetPos());
828 iter = flowMatrix_.find(index);
829 if (iter == flowMatrix_.end()) {
830 LOGE("scrollToIndex[item:%{public}d] failed.", index);
831 return;
832 }
833 }
834
835 double scrollToPos = 0.0;
836 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
837 scrollToPos = iter->second.mainPos;
838 } else {
839 scrollToPos = (mainSize_ - (iter->second.mainPos + iter->second.mainSize)) + iter->second.mainSize - mainSize_;
840 }
841 AnimateToPos(scrollToPos, ANIMATE_DURATION, CURVE_SCROLL_TO_TOP);
842 }
843
DoJump(double position,int32_t source)844 void RenderWaterFlow::DoJump(double position, int32_t source)
845 {
846 UpdateScrollPosition(viewportStartPos_ - position, source);
847 }
848
OnPredictLayout(int64_t deadline)849 void RenderWaterFlow::OnPredictLayout(int64_t deadline)
850 {
851 if (!NeedPredictLayout()) {
852 return;
853 }
854 auto context = context_.Upgrade();
855 if (!context) {
856 return;
857 }
858 if (!context->IsTransitionStop()) {
859 MarkNeedPredictLayout();
860 return;
861 }
862
863 auto startTime = GetSysTimestamp(); // unit: ns
864 DealCache();
865 if (GetSysTimestamp() - startTime + TIME_THRESHOLD > deadline * MICROSEC_TO_NANOSEC) {
866 MarkNeedPredictLayout();
867 return;
868 }
869
870 // just need supply forward the main side, backwards already supply and keep in flowMatrix.
871 size_t itemIndex = GetNextSupplyedIndex();
872 SupplyItems(itemIndex, GetCacheTargetPos());
873 UpdateCacheItems();
874 LayoutItems(cacheItems_);
875 dVPStartPosBackup_ = viewportStartPos_;
876 totalCountBack_ = getTotalCount_();
877 MarkNeedPredictLayout();
878 }
879
IsAxisScrollable(AxisDirection direction)880 bool RenderWaterFlow::IsAxisScrollable(AxisDirection direction)
881 {
882 bool ret = true;
883 switch (direction_) {
884 case FlexDirection::COLUMN:
885 if ((direction == AxisDirection::UP && reachHead_) ||
886 (direction == AxisDirection::DOWN && reachTail_)) {
887 ret = false;
888 }
889 break;
890 case FlexDirection::ROW:
891 if ((direction == AxisDirection::LEFT && reachHead_) ||
892 (direction == AxisDirection::RIGHT && reachTail_)) {
893 ret = false;
894 }
895 break;
896 case FlexDirection::COLUMN_REVERSE:
897 if ((direction == AxisDirection::DOWN && reachHead_) ||
898 (direction == AxisDirection::UP && reachTail_)) {
899 ret = false;
900 }
901 break;
902 case FlexDirection::ROW_REVERSE:
903 if ((direction == AxisDirection::RIGHT && reachHead_) ||
904 (direction == AxisDirection::LEFT && reachTail_)) {
905 ret = false;
906 }
907 break;
908 default:
909 ret = false;
910 break;
911 }
912 if (direction == AxisDirection::NONE) {
913 ret = false;
914 }
915 return ret;
916 }
917
HandleAxisEvent(const AxisEvent & event)918 void RenderWaterFlow::HandleAxisEvent(const AxisEvent& event)
919 {
920 double degree = 0.0;
921 if (!NearZero(event.horizontalAxis)) {
922 degree = event.horizontalAxis;
923 } else if (!NearZero(event.verticalAxis)) {
924 degree = event.verticalAxis;
925 }
926 double offset = SystemProperties::Vp2Px(DP_PER_LINE_DESKTOP * LINE_NUMBER_DESKTOP * degree / MOUSE_WHEEL_DEGREES);
927 UpdateScrollPosition(-offset, SCROLL_FROM_ROTATE);
928 }
929
CheckAxisNode()930 WeakPtr<RenderNode> RenderWaterFlow::CheckAxisNode()
931 {
932 return AceType::WeakClaim<RenderNode>(this);
933 }
934
OnChildAdded(const RefPtr<RenderNode> & renderNode)935 void RenderWaterFlow::OnChildAdded(const RefPtr<RenderNode>& renderNode)
936 {
937 Offset offset;
938 switch (direction_) {
939 case FlexDirection::COLUMN:
940 offset.SetX(crossSize_ / CENTER_POINT);
941 offset.SetY(mainSize_ + cacheSize_);
942 break;
943 case FlexDirection::ROW:
944 offset.SetX(mainSize_ + cacheSize_);
945 offset.SetY(crossSize_ / CENTER_POINT);
946 break;
947 case FlexDirection::COLUMN_REVERSE:
948 offset.SetX(crossSize_ / CENTER_POINT);
949 offset.SetY(0.0 - cacheSize_);
950 break;
951 case FlexDirection::ROW_REVERSE:
952 offset.SetX(0.0 - cacheSize_);
953 offset.SetY(crossSize_ / CENTER_POINT);
954 break;
955 default:
956 break;
957 }
958 // set default position for animateTo(covering animation)
959 renderNode->SetPosition(offset);
960 RenderNode::OnChildAdded(renderNode);
961 }
962
IsUseOnly()963 bool RenderWaterFlow::IsUseOnly()
964 {
965 return true;
966 }
967
GetFlowItemByChild(const RefPtr<RenderNode> & child)968 RefPtr<RenderWaterFlowItem> RenderWaterFlow::GetFlowItemByChild(const RefPtr<RenderNode>& child)
969 {
970 int32_t depth = DEFAULT_DEPTH;
971 auto item = child;
972 auto flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
973 while (!flowItem && depth > 0) {
974 if (!item || item->GetChildren().empty()) {
975 return nullptr;
976 }
977 item = item->GetChildren().front();
978 flowItem = AceType::DynamicCast<RenderWaterFlowItem>(item);
979 --depth;
980 }
981 return flowItem;
982 }
983
OutputMatrix()984 void RenderWaterFlow::OutputMatrix()
985 {
986 for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
987 LOGD("%{public}s: [%{public}zu] Pos[%{public}f, %{public}f] Size[%{public}f, %{public}f]", __PRETTY_FUNCTION__,
988 it->first, it->second.crossPos, it->second.mainPos, it->second.crossSize, it->second.mainSize);
989 it++;
990 }
991 }
992
RequestWaterFlowFooter()993 void RenderWaterFlow::RequestWaterFlowFooter()
994 {
995 auto generator = itemGenerator_.Upgrade();
996 footer_ = generator ? generator->RequestWaterFlowFooter() : RefPtr<RenderNode>();
997 if (footer_) {
998 AddChild(footer_);
999 footer_->Layout(GetLayoutParam());
1000 footer_->SetVisible(false);
1001 auto mainSize = GetMainSize(footer_);
1002 auto crossSize = GetCrossSize(footer_);
1003 if (NonPositive(mainSize) || NonPositive(crossSize)) {
1004 RemoveChild(footer_);
1005 footer_ = nullptr;
1006 } else {
1007 GetFooterSize(mainSize, crossSize);
1008 }
1009 }
1010 }
1011
GetLastSupplyedIndex()1012 size_t RenderWaterFlow::GetLastSupplyedIndex()
1013 {
1014 return flowMatrix_.empty() ? 0 : (--flowMatrix_.end())->first;
1015 }
1016
GetNextSupplyedIndex()1017 size_t RenderWaterFlow::GetNextSupplyedIndex()
1018 {
1019 size_t index = 0;
1020 if (!flowMatrix_.empty()) {
1021 index = (--flowMatrix_.end())->first;
1022 index++;
1023 }
1024 return index;
1025 }
1026
GetLastSupplyedMainSize()1027 double RenderWaterFlow::GetLastSupplyedMainSize()
1028 {
1029 double result = 0.0;
1030 if (flowMatrix_.empty()) {
1031 return result;
1032 }
1033 size_t index = GetLastSupplyedIndex();
1034 auto iter = flowMatrix_.find(index);
1035 if (iter != flowMatrix_.end()) {
1036 result = iter->second.mainSize + iter->second.mainPos;
1037 }
1038 return result;
1039 }
1040
GetLastMainBlankPos()1041 Offset RenderWaterFlow::GetLastMainBlankPos()
1042 {
1043 Offset pos;
1044 size_t crossIndex = 0;
1045 if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1046 return pos;
1047 }
1048 pos.SetY(mainSideEndPos_.at(0));
1049 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1050 if (LessNotEqual(mainSideEndPos_.at(i), pos.GetY())) {
1051 pos.SetY(mainSideEndPos_.at(i));
1052 crossIndex = i;
1053 }
1054 }
1055 pos.SetX(GetCrossEndPos(crossIndex));
1056 return pos;
1057 }
1058
GetLastMainBlankCross()1059 size_t RenderWaterFlow::GetLastMainBlankCross()
1060 {
1061 double pos = 0.0;
1062 size_t crossIndex = 0;
1063 if (mainSideEndPos_.empty()) {
1064 return crossIndex;
1065 }
1066 pos = mainSideEndPos_.at(0);
1067 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1068 if (LessNotEqual(mainSideEndPos_.at(i), pos)) {
1069 pos = mainSideEndPos_.at(i);
1070 crossIndex = i;
1071 }
1072 }
1073 return crossIndex;
1074 }
1075
GetLastMainPos()1076 Offset RenderWaterFlow::GetLastMainPos()
1077 {
1078 Offset pos(0.0, 0.0);
1079 size_t crossIndex = 0;
1080 if (mainSideEndPos_.empty() || mainSideEndPos_.size() != crossSideSize_.size()) {
1081 return pos;
1082 }
1083 double tempMainSidePos = mainSideEndPos_.at(0);
1084 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1085 if (GreatNotEqual(mainSideEndPos_.at(i), tempMainSidePos)) {
1086 tempMainSidePos = mainSideEndPos_.at(i);
1087 crossIndex = i;
1088 }
1089 }
1090 pos.SetY(mainSideEndPos_.at(crossIndex) - mainGap_);
1091 pos.SetX(GetCrossEndPos(crossIndex));
1092 return pos;
1093 }
1094
GetCrossEndPos(size_t crossIndex)1095 double RenderWaterFlow::GetCrossEndPos(size_t crossIndex)
1096 {
1097 double pos = 0.0;
1098 if (crossIndex >= crossSideSize_.size()) {
1099 return pos;
1100 }
1101 for (size_t i = 0; i < crossIndex; i++) {
1102 pos += crossSideSize_[i];
1103 }
1104 if (crossIndex > 0) {
1105 pos += crossIndex * crossGap_;
1106 }
1107
1108 return pos;
1109 }
1110
GetMainSize(const RefPtr<RenderNode> & item) const1111 double RenderWaterFlow::GetMainSize(const RefPtr<RenderNode>& item) const
1112 {
1113 double size = 0.0;
1114 if (!item) {
1115 return size;
1116 }
1117 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1118 size = item->GetLayoutSize().Height();
1119 } else {
1120 size = item->GetLayoutSize().Width();
1121 }
1122
1123 return size;
1124 }
1125
GetCrossSize(const RefPtr<RenderNode> & item) const1126 double RenderWaterFlow::GetCrossSize(const RefPtr<RenderNode>& item) const
1127 {
1128 double size = 0.0;
1129 if (!item) {
1130 return size;
1131 }
1132
1133 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE) {
1134 size = item->GetLayoutSize().Width();
1135 } else {
1136 size = item->GetLayoutSize().Height();
1137 }
1138
1139 return size;
1140 }
1141
ConstraintItemSize(FlowStyle item,size_t crossIndex)1142 FlowStyle RenderWaterFlow::ConstraintItemSize(FlowStyle item, size_t crossIndex)
1143 {
1144 FlowStyle result = item;
1145 if (GreatNotEqual(result.mainSize, itemConstraintSize_.maxMainSize)) {
1146 result.mainSize = itemConstraintSize_.maxMainSize;
1147 }
1148 if (LessNotEqual(result.mainSize, itemConstraintSize_.minMainSize)) {
1149 result.mainSize = itemConstraintSize_.minMainSize;
1150 }
1151 if (crossIndex < crossSideSize_.size()) {
1152 result.crossSize = crossSideSize_[crossIndex];
1153 }
1154 return result;
1155 }
1156
CheckReachHead()1157 bool RenderWaterFlow::CheckReachHead()
1158 {
1159 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1160 return LessOrEqual(viewportStartPos_, 0.0);
1161 }
1162 return LessOrEqual(0.0, viewportStartPos_);
1163 }
1164
CheckReachTail()1165 bool RenderWaterFlow::CheckReachTail()
1166 {
1167 double tailPos = GetTailPos();
1168 double footerOffset = 0.0;
1169 if (footer_) {
1170 switch (direction_) {
1171 case FlexDirection::COLUMN:
1172 case FlexDirection::COLUMN_REVERSE:
1173 footerOffset = footerMaxSize_.Height();
1174 break;
1175 case FlexDirection::ROW:
1176 case FlexDirection::ROW_REVERSE:
1177 footerOffset = footerMaxSize_.Width();
1178 break;
1179 default:
1180 break;
1181 }
1182 }
1183 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1184 return (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset));
1185 }
1186 return (GreatOrEqual(tailPos - footerOffset, viewportStartPos_));
1187 }
1188
AdjustViewPort()1189 void RenderWaterFlow::AdjustViewPort()
1190 {
1191 double tailPos = GetTailPos();
1192 double footerOffset = 0.0;
1193 if (footer_) {
1194 switch (direction_) {
1195 case FlexDirection::COLUMN:
1196 case FlexDirection::COLUMN_REVERSE:
1197 footerOffset = footerMaxSize_.Height();
1198 break;
1199 case FlexDirection::ROW:
1200 case FlexDirection::ROW_REVERSE:
1201 footerOffset = footerMaxSize_.Width();
1202 break;
1203 default:
1204 break;
1205 }
1206 }
1207
1208 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1209 // Correct the position of view port to avoid oversize offset from scroller
1210 viewportStartPos_ = std::max(viewportStartPos_, 0.0);
1211 if (GreatOrEqual((viewportStartPos_) + mainSize_, tailPos + footerOffset)) {
1212 viewportStartPos_ = std::max((tailPos + footerOffset - mainSize_), 0.0);
1213 }
1214 } else {
1215 // Correct the position of view port to avoid oversize offset from scroller
1216 viewportStartPos_ = std::min(viewportStartPos_, 0.0);
1217 if (GreatOrEqual(tailPos - footerOffset, viewportStartPos_)) {
1218 viewportStartPos_ = std::min(tailPos - footerOffset, 0.0);
1219 }
1220 }
1221 }
1222
GetTailPos()1223 double RenderWaterFlow::GetTailPos()
1224 {
1225 double result = 0.0;
1226 if (!getTotalCount_) {
1227 return result;
1228 }
1229
1230 if (flowMatrix_.empty()) {
1231 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1232 return result;
1233 }
1234 return mainSize_;
1235 }
1236
1237 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1238 result = DBL_MAX;
1239 } else {
1240 result = -DBL_MAX;
1241 }
1242
1243 totalCount_ = getTotalCount_();
1244 auto iter = flowMatrix_.find(totalCount_ - 1);
1245 if (iter != flowMatrix_.end()) {
1246 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1247 result = GetLastMainPos().GetY();
1248 } else {
1249 result = mainSize_ - GetLastMainPos().GetY();
1250 }
1251 }
1252 return result;
1253 }
1254
GetTargetPos()1255 double RenderWaterFlow::GetTargetPos()
1256 {
1257 double result = 0.0;
1258 // valid targetIndex_
1259 if (targetIndex_ >= 0) {
1260 auto iter = flowMatrix_.find(targetIndex_);
1261 if (iter != flowMatrix_.end()) {
1262 result = iter->second.mainPos;
1263 } else {
1264 result = DBL_MAX;
1265 }
1266 } else {
1267 if (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::ROW) {
1268 result = viewportStartPos_ + mainSize_;
1269 } else {
1270 result = -viewportStartPos_ + mainSize_;
1271 }
1272 }
1273 return result;
1274 }
1275
GetCacheTargetPos() const1276 double RenderWaterFlow::GetCacheTargetPos() const
1277 {
1278 return viewportStartPos_ + mainSize_ + cacheSize_;
1279 }
1280
AnimateToPos(const double & position,int32_t duration,const RefPtr<Curve> & curve)1281 void RenderWaterFlow::AnimateToPos(const double& position, int32_t duration, const RefPtr<Curve>& curve)
1282 {
1283 if (!animator_->IsStopped()) {
1284 animator_->Stop();
1285 }
1286 animator_->ClearInterpolators();
1287 auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(viewportStartPos_, position, curve);
1288 animation->AddListener([weakScroll = AceType::WeakClaim(this)](double value) {
1289 auto scroll = weakScroll.Upgrade();
1290 if (scroll) {
1291 scroll->DoJump(value, SCROLL_FROM_ANIMATION);
1292 }
1293 });
1294 animator_->AddInterpolator(animation);
1295 animator_->SetDuration(duration);
1296 animator_->ClearStopListeners();
1297 animator_->Play();
1298 }
1299
ClearFlowMatrix(size_t index,bool clearAll)1300 void RenderWaterFlow::ClearFlowMatrix(size_t index, bool clearAll)
1301 {
1302 if (!clearAll) {
1303 for (auto it = flowMatrix_.begin(); it != flowMatrix_.end();) {
1304 if (it->first >= index) {
1305 flowMatrix_.erase(it++);
1306 } else {
1307 it++;
1308 }
1309 }
1310 } else {
1311 flowMatrix_.clear();
1312 }
1313 }
1314
ClearItemsByCrossIndex(size_t index,bool clearAll)1315 void RenderWaterFlow::ClearItemsByCrossIndex(size_t index, bool clearAll)
1316 {
1317 if (!clearAll) {
1318 for (auto& cross : itemsByCrossIndex_) {
1319 for (auto item = cross.begin(); item != cross.end();) {
1320 if (*item >= index) {
1321 item = cross.erase(item);
1322 } else {
1323 item++;
1324 }
1325 }
1326 }
1327 } else {
1328 itemsByCrossIndex_.clear();
1329 std::vector<size_t> item;
1330 for (size_t i = 0; i < crossCount_; i++) {
1331 itemsByCrossIndex_.emplace_back(item);
1332 }
1333 }
1334 }
1335
UpdateMainSideEndPos()1336 void RenderWaterFlow::UpdateMainSideEndPos()
1337 {
1338 if (mainSideEndPos_.size() != itemsByCrossIndex_.size()) {
1339 return;
1340 }
1341
1342 for (size_t i = 0; i < mainSideEndPos_.size(); i++) {
1343 int32_t maxIndex = -1;
1344 for (size_t j : itemsByCrossIndex_[i]) {
1345 maxIndex = std::max(maxIndex, static_cast<int32_t>(j));
1346 }
1347 auto iter = flowMatrix_.find(maxIndex);
1348 if (iter != flowMatrix_.end()) {
1349 mainSideEndPos_.at(i) = iter->second.mainPos + iter->second.mainSize + mainGap_;
1350 } else {
1351 mainSideEndPos_.at(i) = 0.0;
1352 }
1353 }
1354 }
1355
InitMainSideEndPos()1356 void RenderWaterFlow::InitMainSideEndPos()
1357 {
1358 mainSideEndPos_.clear();
1359 for (size_t i = 0; i < crossCount_; i++) {
1360 mainSideEndPos_.emplace_back(0.0);
1361 }
1362 }
1363
RemoveAllChild()1364 void RenderWaterFlow::RemoveAllChild()
1365 {
1366 items_.clear();
1367 ClearChildren();
1368 }
1369
NeedPredictLayout()1370 bool RenderWaterFlow::NeedPredictLayout()
1371 {
1372 return !(updateFlag_ || (NearEqual(dVPStartPosBackup_, viewportStartPos_) &&
1373 (totalCountBack_ == getTotalCount_())));
1374 }
1375
PreParseArgs(const std::string & args)1376 std::string RenderWaterFlow::PreParseArgs(const std::string& args)
1377 {
1378 if (args.empty() || args.find(UNIT_AUTO) == std::string::npos) {
1379 return args;
1380 }
1381 std::string rowsArgs;
1382 std::vector<std::string> strs;
1383 StringUtils::StringSplitter(args, ' ', strs);
1384 std::string current;
1385 size_t rowArgSize = strs.size();
1386 for (size_t i = 0; i < rowArgSize; ++i) {
1387 current = strs[i];
1388 // "auto" means 1fr in waterflow
1389 if (strs[i] == std::string(UNIT_AUTO)) {
1390 current = "1fr";
1391 }
1392 rowsArgs += ' ' + current;
1393 }
1394 return rowsArgs;
1395 }
1396
HandleScrollEvent()1397 void RenderWaterFlow::HandleScrollEvent()
1398 {
1399 for (auto& event : waterflowEventFlags_) {
1400 switch (event.first) {
1401 case WaterFlowEvents::REACH_START:
1402 if (event.second) {
1403 ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachStart);
1404 LOGD("waterflow event REACH_START triggered.");
1405 event.second = false;
1406 }
1407 break;
1408 case WaterFlowEvents::REACH_END:
1409 if (event.second) {
1410 ResumeEventCallback(component_, &WaterFlowComponent::GetOnReachEnd);
1411 LOGD("waterflow event REACH_END triggered.");
1412 event.second = false;
1413 }
1414 break;
1415 default:
1416 LOGW("This event does not handle in here, please check. event number: %{public}d", event.first);
1417 break;
1418 }
1419 }
1420 }
1421 } // namespace OHOS::Ace::V2
1422