diff --git a/frameworks/core/components_ng/pattern/BUILD.gn b/frameworks/core/components_ng/pattern/BUILD.gn index 6c3e11d22dda69267f6c2aab58863a547ee58eb8..3e9d78b387353adb254057e74e81687b6ade3e2a 100644 --- a/frameworks/core/components_ng/pattern/BUILD.gn +++ b/frameworks/core/components_ng/pattern/BUILD.gn @@ -541,6 +541,7 @@ build_component_ng("pattern_ng") { "waterflow/layout/top_down/water_flow_layout_algorithm.cpp", "waterflow/layout/top_down/water_flow_layout_info.cpp", "waterflow/layout/top_down/water_flow_segmented_layout.cpp", + "waterflow/layout/water_flow_layout_algorithm_base.cpp", "waterflow/layout/water_flow_layout_info_base.cpp", "waterflow/layout/water_flow_layout_utils.cpp", "waterflow/water_flow_accessibility_property.cpp", diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp index 18fb0414c8ead639d3d8690cec66310d02390f72..194dc24f87b00faea014c541e679691dc26579c0 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_sw.cpp @@ -104,7 +104,12 @@ void WaterFlowLayoutSW::Layout(LayoutWrapper* wrapper) } } - wrapper->SetActiveChildRange(nodeIdx(info_->startIndex_), nodeIdx(info_->endIndex_)); + auto cachedCount = props->GetCachedCountValue(1); + wrapper->SetActiveChildRange(nodeIdx(info_->startIndex_), nodeIdx(info_->endIndex_), cachedCount, cachedCount); + PreBuildItems(wrapper_, info_, + WaterFlowLayoutUtils::CreateChildConstraint({ itemCrossSize_[0], mainLen_, axis_ }, props, nullptr), + cachedCount); + if (info_->itemEnd_) { LayoutFooter(paddingOffset, reverse); } diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_algorithm.cpp index df9c432c2121c436b63f36fcee66dce624caa32c..042224d6cfc07b76a760aac827009b35fa8de0b6 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_algorithm.cpp @@ -252,6 +252,13 @@ void WaterFlowLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) } layoutInfo_->firstIndex_ = firstIndex; LayoutFooter(layoutWrapper, childFrameOffset, layoutProperty->IsReverse()); + + auto cachedCount = layoutProperty->GetCachedCountValue(1); + layoutWrapper->SetActiveChildRange(layoutInfo_->FirstIdx(), layoutInfo_->endIndex_, cachedCount, cachedCount); + PreBuildItems(layoutWrapper, layoutInfo_, + WaterFlowLayoutUtils::CreateChildConstraint( + { itemsCrossPosition_.find(0)->second, mainSize_, axis_ }, layoutProperty, nullptr), + cachedCount); } void WaterFlowLayoutAlgorithm::LayoutFooter(LayoutWrapper* layoutWrapper, const OffsetF& childFrameOffset, bool reverse) diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_segmented_layout.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_segmented_layout.cpp index 9247836c5cf78af1e7b09ae10dd796cf5aef749b..8e68ab83f6a146f53282a98f5dbc0d42119b1ddb 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_segmented_layout.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_segmented_layout.cpp @@ -109,10 +109,15 @@ void WaterFlowSegmentedLayout::Layout(LayoutWrapper* wrapper) for (int32_t i = info_->startIndex_; i <= info_->endIndex_; ++i) { LayoutItem(i, crossPos[info_->GetSegment(i)][info_->itemInfos_[i].crossIdx], initialOffset, isReverse); } - wrapper_->SetActiveChildRange(info_->startIndex_, info_->endIndex_); + auto cachedCount = props->GetCachedCountValue(1); + wrapper_->SetActiveChildRange(info_->startIndex_, info_->endIndex_, cachedCount, cachedCount); // for compatibility info_->firstIndex_ = info_->startIndex_; + PreBuildItems(wrapper_, info_, + WaterFlowLayoutUtils::CreateChildConstraint( + { itemsCrossSize_[info_->GetSegment(info_->endIndex_ + 1)][0], mainSize_, axis_ }, props, nullptr), + cachedCount); } namespace { diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.cpp b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bd40c7203770d1fc509779116e35057baba657f --- /dev/null +++ b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h" + +#include "core/components_ng/pattern/waterflow/water_flow_pattern.h" + +namespace OHOS::Ace::NG { +std::list WaterFlowLayoutBase::LayoutCachedItem( + LayoutWrapper* layoutWrapper, const RefPtr& info, int32_t cacheCount) +{ + std::list predictBuildList; + auto currIndex = info->NodeIdx(info->endIndex_ + 1); + auto totalCount = layoutWrapper->GetTotalChildCount(); + for (int32_t i = 0; i < cacheCount && currIndex + i < totalCount; ++i) { + int32_t index = currIndex + i; + auto wrapper = layoutWrapper->GetChildByIndex(index, true); + if (!wrapper) { + predictBuildList.emplace_back(index); + continue; + } + wrapper->SetActive(false); + } + + currIndex = info->NodeIdx(info->FirstIdx() - 1); + for (int32_t i = 0; i < cacheCount && currIndex - i >= info->NodeIdx(0); ++i) { + int32_t index = currIndex - i; + auto wrapper = layoutWrapper->GetChildByIndex(index, true); + if (!wrapper) { + predictBuildList.emplace_back(index); + continue; + } + wrapper->SetActive(false); + } + return predictBuildList; +} + +void WaterFlowLayoutBase::PreBuildItems(LayoutWrapper* layoutWrapper, const RefPtr& info, + const LayoutConstraintF& constraint, int32_t cachedCount) +{ + if (cachedCount > 0) { + auto items = LayoutCachedItem(layoutWrapper, info, cachedCount); + if (!items.empty()) { + PostIdleTask(layoutWrapper->GetHostNode(), { items, constraint }); + } else { + auto host = layoutWrapper->GetHostNode(); + CHECK_NULL_VOID(host); + auto pattern = host->GetPattern(); + CHECK_NULL_VOID(pattern); + pattern->SetPredictLayoutParam(std::nullopt); + } + } +} + +bool WaterFlowLayoutBase::PredictBuildItem(RefPtr wrapper, const LayoutConstraintF& constraint) +{ + CHECK_NULL_RETURN(wrapper, false); + wrapper->SetActive(false); + + auto frameNode = wrapper->GetHostNode(); + CHECK_NULL_RETURN(frameNode, false); + frameNode->GetGeometryNode()->SetParentLayoutConstraint(constraint); + FrameNode::ProcessOffscreenNode(frameNode); + return true; +} + +void WaterFlowLayoutBase::PostIdleTask(RefPtr frameNode, const PredictLayoutParam& param) +{ + CHECK_NULL_VOID(frameNode); + auto pattern = frameNode->GetPattern(); + CHECK_NULL_VOID(pattern); + if (pattern->GetPredictLayoutParam()) { + pattern->SetPredictLayoutParam(param); + return; + } + pattern->SetPredictLayoutParam(param); + auto* context = frameNode->GetContext(); + CHECK_NULL_VOID(context); + context->AddPredictTask([weak = WeakClaim(RawPtr(frameNode))](int64_t deadline, bool canUseLongPredictTask) { + ACE_SCOPED_TRACE("WaterFlow predict"); + auto frameNode = weak.Upgrade(); + CHECK_NULL_VOID(frameNode); + auto pattern = frameNode->GetPattern(); + CHECK_NULL_VOID(pattern); + if (!pattern->GetPredictLayoutParam().has_value()) { + return; + } + bool needMarkDirty = false; + auto param = pattern->GetPredictLayoutParam().value(); + for (auto it = param.items.begin(); it != param.items.end();) { + if (GetSysTimestamp() > deadline) { + break; + } + auto wrapper = frameNode->GetOrCreateChildByIndex(*it, false, true); + if (wrapper && wrapper->GetHostNode() && !wrapper->GetHostNode()->RenderCustomChild(deadline)) { + break; + } + needMarkDirty = PredictBuildItem(wrapper, param.layoutConstraint) || needMarkDirty; + param.items.erase(it++); + } + if (needMarkDirty) { + frameNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT); + } + pattern->SetPredictLayoutParam(std::nullopt); + if (!param.items.empty()) { + WaterFlowLayoutBase::PostIdleTask(frameNode, param); + pattern->SetPredictLayoutParam(param); + } + }); +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h index 4466c531fc41255c869ffb53bbd61d00cd2f4de2..ce82c561be47362f56ee30ecb74e69531044199a 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h +++ b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h @@ -15,7 +15,10 @@ #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_LAYOUT_BASE_H #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_LAYOUT_BASE_H +#include "core/components_ng/base/frame_node.h" #include "core/components_ng/layout/layout_algorithm.h" +#include "core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h" +#include "core/components_ng/property/layout_constraint.h" namespace OHOS::Ace::NG { class WaterFlowLayoutBase : public LayoutAlgorithm { @@ -23,6 +26,20 @@ class WaterFlowLayoutBase : public LayoutAlgorithm { public: virtual void SetCanOverScroll(bool canOverScroll) = 0; + struct PredictLayoutParam { + std::list items; + LayoutConstraintF layoutConstraint; + }; + +protected: + void PreBuildItems(LayoutWrapper* layoutWrapper, const RefPtr& info, + const LayoutConstraintF& constraint, int32_t cachedCount); + +private: + std::list LayoutCachedItem( + LayoutWrapper* wrapper, const RefPtr& info, int32_t cachedCount); + static bool PredictBuildItem(RefPtr wrapper, const LayoutConstraintF& constraint); + static void PostIdleTask(RefPtr frameNode, const PredictLayoutParam& param); }; enum class WaterFlowLayoutMode { TOP_DOWN = 0, SLIDING_WINDOW = 1 }; diff --git a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h index c294ed27c561f26b0d547cd22267e5ea6fefab77..ab6ae4cc797d756a25e0e8414dc545d57b2d23b6 100644 --- a/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h +++ b/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h @@ -141,6 +141,12 @@ public: */ int32_t GetSegment(int32_t itemIdx) const; + // convert FlowItem's index to children node index. + inline int32_t NodeIdx(int32_t idx) const + { + return idx + footerIndex_ + 1; + } + bool itemStart_ = false; /** diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h index d87b4a83c90afe6d4b6b22859ca0439863903e6c..6494397834f3127d56e86a11e5010b5033fc2269 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_pattern.h @@ -153,6 +153,15 @@ public: void DumpAdvanceInfo() override; + void SetPredictLayoutParam(std::optional param) + { + predictLayoutParam_ = param; + } + std::optional GetPredictLayoutParam() const + { + return predictLayoutParam_; + } + // ------------------------ Focus adapter -------------------------------- FocusPattern GetFocusPattern() const override { @@ -198,6 +207,8 @@ private: // clip padding of WaterFlow RefPtr contentModifier_; + + std::optional predictLayoutParam_; }; } // namespace OHOS::Ace::NG #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_PATTERN_H diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 8ad53a028dabfc087107451bc4069aff7dc0fad6..347181e959a1eefc09ec4b58fa41f3da9f3ef18e 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -1077,6 +1077,7 @@ ohos_source_set("ace_components_pattern") { "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_algorithm.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/top_down/water_flow_segmented_layout.cpp", + "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/layout/water_flow_layout_utils.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_accessibility_property.cpp", diff --git a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp index 40a5806edf71012b2ab71bfd858638b812660ca7..b5936d6d7076c740927d4a7e699fe80eba1c809b 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp @@ -22,11 +22,6 @@ #include "test/mock/base/mock_system_properties.h" #endif #include "test/mock/core/rosen/mock_canvas.h" - -#include "core/components/scroll/scroll_controller_base.h" -#include "core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h" -#include "core/components_ng/property/property.h" - #define protected public #define private public #include "test/mock/core/common/mock_theme_manager.h" @@ -35,10 +30,12 @@ #include "core/components/button/button_theme.h" #include "core/components/common/layout/constants.h" +#include "core/components/scroll/scroll_controller_base.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/pattern/button/button_model_ng.h" #include "core/components_ng/pattern/linear_layout/row_model_ng.h" #include "core/components_ng/pattern/scrollable/scrollable.h" +#include "core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h" #include "core/components_ng/pattern/waterflow/water_flow_accessibility_property.h" #include "core/components_ng/pattern/waterflow/water_flow_event_hub.h" #include "core/components_ng/pattern/waterflow/water_flow_item_model_ng.h" @@ -48,6 +45,7 @@ #include "core/components_ng/pattern/waterflow/water_flow_model_ng.h" #include "core/components_ng/pattern/waterflow/water_flow_pattern.h" #include "core/components_ng/property/measure_property.h" +#include "core/components_ng/property/property.h" #include "core/components_v2/inspector/inspector_constants.h" #undef private #undef protected