diff --git a/frameworks/core/components_ng/base/frame_node.cpp b/frameworks/core/components_ng/base/frame_node.cpp index 99abac448b947d2fd544110076d23c3e728ab280..7cd90905cdd1e1583b3b944a2cd4b3d474b9c536 100644 --- a/frameworks/core/components_ng/base/frame_node.cpp +++ b/frameworks/core/components_ng/base/frame_node.cpp @@ -60,7 +60,7 @@ const char FORM_COMPONENT_TAG[] = "FormComponent"; } // namespace namespace OHOS::Ace::NG { -class FramePorxy { +class FrameProxy { public: struct FrameChildNode { RefPtr node; @@ -69,9 +69,9 @@ public: }; struct RecursionGuard { - FramePorxy* proxy_; + FrameProxy* proxy_; bool inUse_; - explicit RecursionGuard(FramePorxy* proxy) : proxy_(proxy), inUse_(proxy->inUse_) + explicit RecursionGuard(FrameProxy* proxy) : proxy_(proxy), inUse_(proxy->inUse_) { proxy_->inUse_ = true; } @@ -86,10 +86,10 @@ public: RecursionGuard GetGuard() { - return RecursionGuard{this}; + return RecursionGuard { this }; } - explicit FramePorxy(FrameNode* frameNode) : hostNode_(frameNode) {} + explicit FrameProxy(FrameNode* frameNode) : hostNode_(frameNode) {} void Build() { @@ -191,6 +191,22 @@ public: return itor->second; } + /** + * @brief Find child's index in parent's map. Only works on children that are already created and recorded. + * + * @param target child LayoutWrapper + * @return index of children + */ + int32_t GetChildIndex(const RefPtr& target) const + { + for (auto it : partFrameNodeChildren_) { + if (it.second == target) { + return it.first; + } + } + return -1; + } + void ResetChildren(bool needResetChild = false) { if (inUse_) { @@ -324,7 +340,7 @@ private: FrameNode::FrameNode( const std::string& tag, int32_t nodeId, const RefPtr& pattern, int32_t instanceId, bool isRoot) : UINode(tag, nodeId, instanceId, isRoot), LayoutWrapper(WeakClaim(this)), pattern_(pattern), - frameProxy_(std::make_unique(this)) + frameProxy_(std::make_unique(this)) { renderContext_->InitContext(IsRootNode(), pattern_->GetContextParam()); paintProperty_ = pattern->CreatePaintProperty(); @@ -1458,6 +1474,14 @@ void FrameNode::MarkNeedRender(bool isRenderBoundary) } } +bool FrameNode::RequestParentDirty() +{ + auto parent = GetAncestorNodeOfFrame(); + CHECK_NULL_RETURN(parent, false); + parent->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST); + return true; +} + void FrameNode::MarkDirtyNode(bool isMeasureBoundary, bool isRenderBoundary, PropertyChangeFlag extraFlag) { if (CheckNeedRender(extraFlag)) { @@ -1475,9 +1499,7 @@ void FrameNode::MarkDirtyNode(bool isMeasureBoundary, bool isRenderBoundary, Pro if (CheckNeedRequestMeasureAndLayout(layoutFlag)) { if (!isMeasureBoundary && IsNeedRequestParentMeasure()) { - auto parent = GetAncestorNodeOfFrame(); - if (parent) { - parent->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST); + if (RequestParentDirty()) { return; } } @@ -2907,7 +2929,6 @@ void FrameNode::SyncGeometryNode(bool needSkipSync) layoutAlgorithm_.Reset(); } - RefPtr FrameNode::GetOrCreateChildByIndex(uint32_t index, bool addToRenderTree) { auto child = frameProxy_->GetFrameNodeByIndex(index, true); @@ -2925,6 +2946,11 @@ RefPtr FrameNode::GetChildByIndex(uint32_t index) return frameProxy_->GetFrameNodeByIndex(index, false); } +int32_t FrameNode::GetChildTrueIndex(const RefPtr& child) const +{ + return frameProxy_->GetChildIndex(child); +} + const std::list>& FrameNode::GetAllChildrenWithBuild(bool addToRenderTree) { const auto& children = frameProxy_->GetAllFrameChildren(); diff --git a/frameworks/core/components_ng/base/frame_node.h b/frameworks/core/components_ng/base/frame_node.h index 77b6dbe7849544516fe0e04489ae2639e50111ed..52ca5de037659b9b38b5d24a7adbb539341b08df 100644 --- a/frameworks/core/components_ng/base/frame_node.h +++ b/frameworks/core/components_ng/base/frame_node.h @@ -55,14 +55,14 @@ namespace OHOS::Accessibility { class AccessibilityElementInfo; class AccessibilityEventInfo; -} +} // namespace OHOS::Accessibility namespace OHOS::Ace::NG { class PipelineContext; class Pattern; class StateModifyTask; class UITask; -class FramePorxy; +class FrameProxy; // FrameNode will display rendering region in the screen. class ACE_FORCE_EXPORT FrameNode : public UINode, public LayoutWrapper { @@ -422,7 +422,8 @@ public: customerSet_ = false; } - void SetCustomerDraggable(bool draggable) { + void SetCustomerDraggable(bool draggable) + { draggable_ = draggable; userSet_ = true; customerSet_ = true; @@ -498,9 +499,8 @@ public: RefPtr GetAnimatablePropertyFloat(const std::string& propertyName) const; static RefPtr FindChildByName(const RefPtr& parentNode, const std::string& nodeName); - void CreateAnimatablePropertyFloat( - const std::string& propertyName, float value, const std::function& onCallbackEvent, - const PropertyUnit& propertyType = PropertyUnit::UNKNOWN); + void CreateAnimatablePropertyFloat(const std::string& propertyName, float value, + const std::function& onCallbackEvent, const PropertyUnit& propertyType = PropertyUnit::UNKNOWN); void DeleteAnimatablePropertyFloat(const std::string& propertyName); void UpdateAnimatablePropertyFloat(const std::string& propertyName, float value); void CreateAnimatableArithmeticProperty(const std::string& propertyName, RefPtr& value, @@ -574,6 +574,14 @@ public: RefPtr GetOrCreateChildByIndex(uint32_t index, bool addToRenderTree = true) override; RefPtr GetChildByIndex(uint32_t index) override; + /** + * @brief Get the index of Child among all FrameNode children of [this]. + * Handles intermediate SyntaxNodes like LazyForEach. + * + * @param child pointer to the Child FrameNode. + * @return index of Child, or -1 if not found. + */ + int32_t GetChildTrueIndex(const RefPtr& child) const; const std::list>& GetAllChildrenWithBuild(bool addToRenderTree = true) override; void RemoveChildInRenderTree(uint32_t index) override; void RemoveAllChildInRenderTree() override; @@ -715,6 +723,12 @@ private: void UpdateLayoutPropertyFlag() override; void ForceUpdateLayoutPropertyFlag(PropertyChangeFlag propertyChangeFlag) override; void AdjustParentLayoutFlag(PropertyChangeFlag& flag) override; + /** + * @brief try to mark Parent dirty with flag PROPERTY_UPDATE_BY_CHILD_REQUEST. + * + * @return true if Parent is successfully marked dirty. + */ + virtual bool RequestParentDirty(); void UpdateChildrenLayoutWrapper(const RefPtr& self, bool forceMeasure, bool forceLayout); void AdjustLayoutWrapperTree(const RefPtr& parent, bool forceMeasure, bool forceLayout) override; @@ -802,7 +816,7 @@ private: RefPtr layoutAlgorithm_; RefPtr oldGeometryNode_; std::optional skipMeasureContent_; - std::unique_ptr frameProxy_; + std::unique_ptr frameProxy_; WeakPtr targetComponent_; bool needSyncRenderTree_ = false; @@ -858,7 +872,6 @@ private: friend class Pattern; ACE_DISALLOW_COPY_AND_MOVE(FrameNode); - }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/BUILD.gn b/frameworks/core/components_ng/pattern/BUILD.gn index 79af818a0da81f8fdbeb9020325655ea5222fdf8..9d6d25ecbda20923466f88be6b7bf0a60b51ee76 100644 --- a/frameworks/core/components_ng/pattern/BUILD.gn +++ b/frameworks/core/components_ng/pattern/BUILD.gn @@ -508,6 +508,7 @@ build_component_ng("pattern_ng") { "waterflow/water_flow_accessibility_property.cpp", "waterflow/water_flow_content_modifier.cpp", "waterflow/water_flow_item_model_ng.cpp", + "waterflow/water_flow_item_node.cpp", "waterflow/water_flow_layout_algorithm.cpp", "waterflow/water_flow_layout_info.cpp", "waterflow/water_flow_layout_property.cpp", diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_item_model_ng.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_model_ng.cpp index 84d6eec9fc93b70931d9a408971da1218e9284ff..a6763591784e74810f559ff834a00731330b2a80 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_item_model_ng.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_model_ng.cpp @@ -16,6 +16,7 @@ #include "core/components_ng/pattern/waterflow/water_flow_item_model_ng.h" #include "core/components_ng/base/view_stack_processor.h" +#include "core/components_ng/pattern/waterflow/water_flow_item_node.h" #include "core/components_ng/pattern/waterflow/water_flow_item_pattern.h" #include "core/components_v2/inspector/inspector_constants.h" @@ -25,7 +26,7 @@ void WaterFlowItemModelNG::Create() auto* stack = ViewStackProcessor::GetInstance(); auto nodeId = stack->ClaimNodeId(); ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::FLOW_ITEM_ETS_TAG, nodeId); - auto frameNode = FrameNode::GetOrCreateFrameNode( + auto frameNode = WaterFlowItemNode::GetOrCreateFlowItem( V2::FLOW_ITEM_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); stack->Push(frameNode); } diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2b1b00ce785cc1f31038117cddd62cc0b26294d --- /dev/null +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.cpp @@ -0,0 +1,46 @@ +/* + * 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/water_flow_item_node.h" + +#include "core/components_ng/pattern/pattern.h" + +namespace OHOS::Ace::NG { +RefPtr WaterFlowItemNode::GetOrCreateFlowItem( + const std::string& tag, int32_t nodeId, const std::function(void)>& patternCreator) +{ + auto node = GetFrameNode(tag, nodeId); + if (node) { + return node; + } + auto pattern = patternCreator ? patternCreator() : MakeRefPtr(); + node = MakeRefPtr(tag, nodeId, pattern); + node->InitializePatternAndContext(); + ElementRegister::GetInstance()->AddUINode(node); + return node; +} + +bool WaterFlowItemNode::RequestParentDirty() +{ + auto parent = GetAncestorNodeOfFrame(); + CHECK_NULL_RETURN(parent, false); + parent->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST); + auto idx = parent->GetChildTrueIndex(Claim(this)); + if (idx > -1) { + parent->ChildrenUpdatedFrom(idx); + } + return true; +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.h b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.h new file mode 100644 index 0000000000000000000000000000000000000000..5f89f04a136a54244698ad1435317841d58284bb --- /dev/null +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_ITEM_NODE_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_ITEM_NODE_H + +#include "core/components_ng/base/frame_node.h" + +namespace OHOS::Ace::NG { +class WaterFlowItemNode : public FrameNode { + DECLARE_ACE_TYPE(WaterFlowItemNode, FrameNode); + +public: + WaterFlowItemNode(const std::string& tag, int32_t nodeId, const RefPtr& pattern) + : FrameNode(tag, nodeId, pattern) + {} + + static RefPtr GetOrCreateFlowItem( + const std::string& tag, int32_t nodeId, const std::function(void)>& patternCreator); + +private: + /** + * @brief Mark Parent (WaterFlow) dirty with flag PROPERTY_UPDATE_BY_CHILD_REQUEST, + * and also notify Parent the index of this child. + * + * @return true if Parent is marked dirty successfully + */ + bool RequestParentDirty() override; +}; +} // namespace OHOS::Ace::NG +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_WATERFLOW_WATER_FLOW_ITEM_NODE_H diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_info.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_info.cpp index b3ef52b9ffa168684715d785c27435918748bd5c..2b777d5748660e61d16a3c48735dffa823754723 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_info.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_info.cpp @@ -275,13 +275,17 @@ void WaterFlowLayoutInfo::ClearCacheAfterIndex(int32_t currentIndex) if (static_cast(currentIndex + 1) < itemInfos_.size()) { itemInfos_.resize(currentIndex + 1); } - if (segment + 1 < segmentStartPos_.size()) { - segmentStartPos_.resize(segment + 1); - } auto it = std::upper_bound(endPosArray_.begin(), endPosArray_.end(), currentIndex, [](int32_t index, const std::pair& pos) { return index < pos.second; }); endPosArray_.erase(it, endPosArray_.end()); + + if (segment + 1 < segmentStartPos_.size()) { + segmentStartPos_.resize(segment + 1); + if (currentIndex == segmentTails_[segment]) { + SetNextSegmentStartPos(currentIndex); + } + } } bool WaterFlowLayoutInfo::ReachStart(float prevOffset, bool firstLayout) const diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.cpp b/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.cpp index 50465a38f14d239f6022142e949e6b2f1c329b86..041fb808b0d19923cc3baed8aeb5bcec0424e99b 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.cpp +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.cpp @@ -117,10 +117,9 @@ namespace { * @brief Prepares a jump to the current StartItem. * * @param info WaterFlowLayoutInfo - * @param reset whether LayoutInfo should be cleared before the jump. * @return current StartItem's offset relative to the viewport. */ -float PrepareJump(WaterFlowLayoutInfo& info, bool reset) +float PrepareJump(WaterFlowLayoutInfo& info) { if (info.endIndex_ == -1) { // implies that LayoutInfo has already been reset, no need to jump @@ -132,23 +131,10 @@ float PrepareJump(WaterFlowLayoutInfo& info, bool reset) ? 0.0f : info.currentOffset_ + info.itemInfos_[info.startIndex_].mainOffset; - if (!reset) { - return itemOffset; - } - info.startIndex_ = 0; info.endIndex_ = -1; info.currentOffset_ = 0.0f; - for (auto& section : info.items_) { - for (auto& column : section) { - column.second.clear(); - } - } - info.ResetSegmentStartPos(); - info.itemInfos_.clear(); - info.endPosArray_.clear(); - return itemOffset; } } // namespace @@ -157,24 +143,32 @@ void WaterFlowSegmentedLayout::Init(const SizeF& frameSize) { info_.childrenCount_ = wrapper_->GetTotalChildCount(); auto secObj = wrapper_->GetHostNode()->GetPattern()->GetSections(); - CheckReset(secObj); - if (secObj) { - SegmentInit(secObj->GetSectionInfo(), frameSize); + const auto& sections = secObj->GetSectionInfo(); + if (info_.margins_.empty()) { + // empty margins_ implies a segment change + auto constraint = wrapper_->GetLayoutProperty()->GetLayoutConstraint(); + postJumpOffset_ = PrepareJump(info_); + info_.InitMargins(sections, constraint->scaleProperty, constraint->percentReference.Width()); + } + SegmentInit(sections, frameSize); if (info_.segmentTails_.empty()) { - info_.InitSegments(secObj->GetSectionInfo(), 0); + info_.InitSegments(sections, 0); } } else { - size_t lastCrossCnt = info_.items_[0].size(); RegularInit(frameSize); if (info_.footerIndex_ >= 0) { InitFooter(frameSize.CrossSize(axis_)); } + } - // crossCount changed - if (lastCrossCnt > 0 && lastCrossCnt != info_.items_[0].size()) { - postJumpOffset_ = PrepareJump(info_, true); + int32_t updateIdx = wrapper_->GetHostNode()->GetChildrenUpdated(); + if (updateIdx != -1) { + if (updateIdx <= info_.endIndex_) { + postJumpOffset_ = PrepareJump(info_); } + info_.ClearCacheAfterIndex(updateIdx - 1); + wrapper_->GetHostNode()->ChildrenUpdatedFrom(-1); } } @@ -257,6 +251,16 @@ void WaterFlowSegmentedLayout::RegularInit(const SizeF& frameSize) void WaterFlowSegmentedLayout::InitFooter(float crossSize) { + mainGaps_.emplace_back(0.0f); + itemsCrossSize_.emplace_back(std::vector { crossSize }); + + if (info_.items_.size() == 1) { + info_.items_.emplace_back(); + info_.items_.back().try_emplace(0); + } + info_.margins_.emplace_back(); + info_.segmentTails_.emplace_back(info_.childrenCount_ - 1); + if (info_.footerIndex_ != info_.childrenCount_ - 1) { info_.footerIndex_ = std::min(info_.footerIndex_, info_.childrenCount_ - 1); info_.ClearCacheAfterIndex(info_.footerIndex_ - 1); @@ -269,48 +273,6 @@ void WaterFlowSegmentedLayout::InitFooter(float crossSize) info_.segmentCache_.erase(info_.footerIndex_); info_.footerIndex_ = info_.childrenCount_ - 1; } - - mainGaps_.push_back(0.0f); - itemsCrossSize_.push_back({ crossSize }); - - size_t sectionCnt = mainGaps_.size(); - if (info_.items_.size() == sectionCnt - 1) { - info_.items_.emplace_back(); - info_.items_.back().try_emplace(0); - } - if (info_.segmentTails_.size() == sectionCnt - 1) { - info_.segmentTails_.push_back(info_.childrenCount_ - 1); - } - if (info_.margins_.size() == sectionCnt - 1) { - info_.margins_.emplace_back(); - } -} - -void WaterFlowSegmentedLayout::CheckReset(const RefPtr& secObj) -{ - if (secObj && info_.margins_.empty()) { - // empty margins_ implies a segment change - const auto& sections = secObj->GetSectionInfo(); - auto constraint = wrapper_->GetLayoutProperty()->GetLayoutConstraint(); - postJumpOffset_ = PrepareJump(info_, false); - info_.InitMargins(sections, constraint->scaleProperty, constraint->percentReference.Width()); - return; - } - - if (wrapper_->GetLayoutProperty()->GetPropertyChangeFlag() & PROPERTY_UPDATE_BY_CHILD_REQUEST) { - postJumpOffset_ = PrepareJump(info_, true); - return; - } - - int32_t updateIdx = wrapper_->GetHostNode()->GetChildrenUpdated(); - if (updateIdx != -1) { - if (updateIdx <= info_.endIndex_) { - postJumpOffset_ = PrepareJump(info_, true); - } else { - info_.ClearCacheAfterIndex(updateIdx - 1); - } - wrapper_->GetHostNode()->ChildrenUpdatedFrom(-1); - } } namespace { diff --git a/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.h b/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.h index 081e9662e911c1c6378291862d6985b755427203..b5eac9dde1fd96f9a91ace9a4ed08560ee3971c1 100644 --- a/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.h +++ b/frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.h @@ -66,8 +66,6 @@ private: void RegularInit(const SizeF& frameSize); void InitFooter(float crossSize); - void CheckReset(const RefPtr& secObj); - /** * @brief Measure self before measuring children. * diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 543eb99bb9e9d48c481d5dd648c7fff2dc2da2fd..88fbe786120962c12936cee1b4749af5da011a4b 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -988,6 +988,7 @@ ohos_source_set("ace_components_pattern") { "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_accessibility_property.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_content_modifier.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_item_model_ng.cpp", + "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_item_node.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_algorithm.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_info.cpp", "$ace_root/frameworks/core/components_ng/pattern/waterflow/water_flow_layout_property.cpp", diff --git a/test/unittest/core/base/frame_node_test_ng.cpp b/test/unittest/core/base/frame_node_test_ng.cpp index 8872a77169e5474b662866dc8d5c69d345af1db6..2a7c1a0a29a4d84dcbe4af08d9cc0d4334e72be2 100644 --- a/test/unittest/core/base/frame_node_test_ng.cpp +++ b/test/unittest/core/base/frame_node_test_ng.cpp @@ -1409,7 +1409,7 @@ HWTEST_F(FrameNodeTestNg, FrameNodeUpdateAnimatableArithmeticProperty0038, TestS /** * @tc.name: FrameNodeTestNg0039 - * @tc.desc: Test of FramePorxy + * @tc.desc: Test of FrameProxy * @tc.type: FUNC */ HWTEST_F(FrameNodeTestNg, FrameNodeTestNg0039, TestSize.Level1) diff --git a/test/unittest/core/pattern/waterflow/water_flow_segment_layout_test.cpp b/test/unittest/core/pattern/waterflow/water_flow_segment_layout_test.cpp index 4d1e5a93e3b958867be2c955d5ed8e20f5184943..9e02bb78f6c84053ad8167c26f90958a1253d256 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_segment_layout_test.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_segment_layout_test.cpp @@ -23,7 +23,8 @@ #define private public #include "test/mock/core/pipeline/mock_pipeline_context.h" -#include "frameworks/core/components_ng/pattern/waterflow/water_flow_segmented_layout.h" +#include "core/components_ng/pattern/waterflow/water_flow_item_node.h" +#include "core/components_ng/pattern/waterflow/water_flow_segmented_layout.h" namespace OHOS::Ace::NG { class WaterFlowSegmentTest : public WaterFlowTestNg { @@ -222,7 +223,7 @@ HWTEST_F(WaterFlowSegmentTest, MeasureFooter001, TestSize.Level1) auto& info = pattern_->layoutInfo_; EXPECT_EQ(info.childrenCount_, 11); EXPECT_EQ(info.footerIndex_, 10); - auto footer = FrameNode::GetOrCreateFrameNode( + auto footer = WaterFlowItemNode::GetOrCreateFlowItem( V2::FLOW_ITEM_ETS_TAG, -1, []() { return AceType::MakeRefPtr(); }); footer->GetLayoutProperty()->UpdateUserDefinedIdealSize( CalcSize(CalcLength(100.0f), CalcLength(Dimension(200.0f)))); @@ -266,7 +267,9 @@ HWTEST_F(WaterFlowSegmentTest, MeasureFooter002, TestSize.Level1) auto& info = pattern_->layoutInfo_; EXPECT_EQ(info.childrenCount_, 11); EXPECT_EQ(info.footerIndex_, 10); - auto footer = FrameNode::GetOrCreateFrameNode( + EXPECT_EQ(info.itemInfos_[8].mainOffset, 202.0f); + + auto footer = WaterFlowItemNode::GetOrCreateFlowItem( V2::FLOW_ITEM_ETS_TAG, -1, []() { return AceType::MakeRefPtr(); }); footer->GetLayoutProperty()->UpdateUserDefinedIdealSize( CalcSize(CalcLength(100.0f), CalcLength(Dimension(200.0f)))); @@ -283,6 +286,7 @@ HWTEST_F(WaterFlowSegmentTest, MeasureFooter002, TestSize.Level1) UpdateCurrentOffset(-1000.0f); EXPECT_EQ(info.items_.size(), 2); EXPECT_EQ(info.items_[1][0].size(), 1); + EXPECT_EQ(info.segmentStartPos_[1], 401.0f); EXPECT_EQ(info.childrenCount_, 9); EXPECT_EQ(info.endIndex_, 8); EXPECT_EQ(info.segmentTails_[0], 7); @@ -608,12 +612,12 @@ HWTEST_F(WaterFlowSegmentTest, Reset001, TestSize.Level1) // change crossCount, should jump back to index 75 layoutProperty_->UpdateColumnsTemplate("1fr 1fr 1fr"); + info.Reset(); algo->Measure(AceType::RawPtr(frameNode_)); - EXPECT_EQ(info.startIndex_, 75); - EXPECT_EQ(info.endIndex_, 94); - EXPECT_EQ(info.currentOffset_, -3875.0f); + EXPECT_EQ(info.startIndex_, 45); + EXPECT_EQ(info.endIndex_, 64); + EXPECT_EQ(info.currentOffset_, -2370.0f); EXPECT_EQ(algo->itemsCrossSize_[0].size(), 3); - EXPECT_EQ(info.align_, ScrollAlign::START); } /** @@ -653,6 +657,7 @@ HWTEST_F(WaterFlowSegmentTest, Reset002, TestSize.Level1) // child requires fresh layout, should jump back to index 75 layoutProperty_->propertyChangeFlag_ = PROPERTY_UPDATE_BY_CHILD_REQUEST; + frameNode_->ChildrenUpdatedFrom(0); algo->Measure(AceType::RawPtr(frameNode_)); EXPECT_EQ(info.startIndex_, 25); EXPECT_EQ(info.endIndex_, 57); @@ -727,6 +732,45 @@ HWTEST_F(WaterFlowSegmentTest, Reset003, TestSize.Level1) EXPECT_EQ(info.itemInfos_.size(), 58); } +/** + * @tc.name: Reset004 + * @tc.desc: Test Changing crossCount and deleting items. + * @tc.type: FUNC + */ +HWTEST_F(WaterFlowSegmentTest, Reset004, TestSize.Level1) +{ + Create([](WaterFlowModelNG model) { + model.SetColumnsTemplate("1fr 1fr 1fr 1fr"); + model.SetColumnsGap(Dimension(5.0f)); + model.SetRowsGap(Dimension(1.0f)); + model.SetFooter(GetDefaultHeaderBuilder()); + CreateItem(200); + ViewStackProcessor::GetInstance()->Pop(); + }); + + UpdateCurrentOffset(-2000.0f); + auto& info = pattern_->layoutInfo_; + EXPECT_EQ(info.footerIndex_, 200); + EXPECT_EQ(info.endIndex_, 75); + EXPECT_EQ(info.startIndex_, 49); + EXPECT_EQ(info.itemInfos_[info.startIndex_].mainOffset + info.currentOffset_, -188.0f); + auto footer = WaterFlowItemNode::GetOrCreateFlowItem( + V2::FLOW_ITEM_ETS_TAG, -1, []() { return AceType::MakeRefPtr(); }); + footer->GetLayoutProperty()->UpdateUserDefinedIdealSize( + CalcSize(CalcLength(100.0f), CalcLength(Dimension(200.0f)))); + pattern_->AddFooter(footer); + for (int i = 0; i < 2; ++i) { + frameNode_->RemoveChildAtIndex(80); + } + frameNode_->ChildrenUpdatedFrom(80); + layoutProperty_->UpdateColumnsTemplate("1fr 1fr"); + + FlushLayoutTask(frameNode_); + EXPECT_EQ(GetChildFrameNode(frameNode_, info.footerIndex_), footer); + EXPECT_EQ(info.startIndex_, 25); + EXPECT_EQ(info.currentOffset_, -2000.0f); +} + /** * @tc.name: Segmented001 * @tc.desc: Layout WaterFlow with multiple sections 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 1390bf47c99ac522f53dc78178e4729bac041517..6ae032cbfcf61a19efaf2dd8d877341df3b471b5 100644 --- a/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp +++ b/test/unittest/core/pattern/waterflow/water_flow_test_ng.cpp @@ -49,6 +49,7 @@ #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" +#include "core/components_ng/pattern/waterflow/water_flow_item_node.h" #include "core/components_ng/pattern/waterflow/water_flow_item_pattern.h" #include "core/components_ng/pattern/waterflow/water_flow_layout_algorithm.h" #include "core/components_ng/pattern/waterflow/water_flow_layout_property.h" @@ -157,7 +158,7 @@ void WaterFlowTestNg::CreateItem(int32_t number) void WaterFlowTestNg::AddItems(int32_t number) { for (int i = 0; i < number; ++i) { - auto child = FrameNode::GetOrCreateFrameNode( + auto child = WaterFlowItemNode::GetOrCreateFlowItem( V2::FLOW_ITEM_ETS_TAG, -1, []() { return AceType::MakeRefPtr(); }); if (i & 1) { child->GetLayoutProperty()->UpdateUserDefinedIdealSize(