1 /*
2 * Copyright (c) 2022-2023 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 "frameworks/core/components_ng/pattern/refresh/refresh_layout_algorithm.h"
17
18 #include "frameworks/base/utils/utils.h"
19 #include "frameworks/core/common/container.h"
20 #include "frameworks/core/components_ng/base/frame_node.h"
21 #include "frameworks/core/components_ng/pattern/refresh/refresh_layout_property.h"
22 #include "frameworks/core/components_ng/pattern/refresh/refresh_pattern.h"
23 #include "frameworks/core/components_ng/property/measure_property.h"
24 #include "frameworks/core/components_ng/property/measure_utils.h"
25 #include "frameworks/core/components_ng/property/property.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr Dimension TRIGGER_REFRESH_DISTANCE = 64.0_vp;
30 } // namespace
31
32 RefreshLayoutAlgorithm::RefreshLayoutAlgorithm() = default;
33
Measure(LayoutWrapper * layoutWrapper)34 void RefreshLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
35 {
36 CHECK_NULL_VOID(layoutWrapper);
37 auto layoutProperty = AceType::DynamicCast<NG::RefreshLayoutProperty>(layoutWrapper->GetLayoutProperty());
38 CHECK_NULL_VOID(layoutProperty);
39 auto layoutConstraint = layoutProperty->CreateChildConstraint();
40 int32_t index = 0;
41 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
42 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
43 child->Measure(layoutConstraint);
44 ++index;
45 continue;
46 }
47 if (HasCustomBuilderIndex() && index == customBuilderIndex_.value_or(0)) {
48 auto builderLayoutConstraint = layoutConstraint;
49 bool isCustomBuilderExist = layoutProperty->GetIsCustomBuilderExistValue(true);
50 if (isCustomBuilderExist) {
51 builderLayoutConstraint.UpdateIllegalSelfIdealSizeWithCheck(
52 CalculateBuilderSize(child, builderLayoutConstraint, builderBaseHeight_));
53 } else {
54 builderLayoutConstraint.minSize.SetHeight(builderBaseHeight_);
55 builderLayoutConstraint.maxSize.SetHeight(builderBaseHeight_);
56 builderLayoutConstraint.percentReference.SetHeight(builderBaseHeight_);
57 }
58 child->Measure(builderLayoutConstraint);
59 ++index;
60 continue;
61 }
62 child->Measure(layoutConstraint);
63 ++index;
64 }
65 PerformMeasureSelf(layoutWrapper);
66 }
67
CalculateBuilderSize(RefPtr<LayoutWrapper> childLayoutWrapper,LayoutConstraintF & constraint,float customBaseHeight)68 OptionalSizeF RefreshLayoutAlgorithm::CalculateBuilderSize(
69 RefPtr<LayoutWrapper> childLayoutWrapper, LayoutConstraintF& constraint, float customBaseHeight)
70 {
71 OptionalSizeF defaultSize;
72 CHECK_NULL_RETURN(childLayoutWrapper, defaultSize);
73 auto layoutProperty = childLayoutWrapper->GetLayoutProperty();
74 CHECK_NULL_RETURN(layoutProperty, defaultSize);
75 std::optional<CalcLength> width = std::nullopt;
76 auto&& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
77 if (!calcLayoutConstraint) {
78 return defaultSize;
79 }
80 std::optional<float> reSetHeight = customBaseHeight;
81 if (calcLayoutConstraint->selfIdealSize.has_value() &&
82 calcLayoutConstraint->selfIdealSize.value().Height().has_value()) {
83 reSetHeight = ConvertToPx(
84 calcLayoutConstraint->selfIdealSize.value().Height().value(), constraint.scaleProperty, customBaseHeight)
85 .value_or(-1.0f);
86 }
87 if (calcLayoutConstraint->selfIdealSize.has_value()) {
88 width = calcLayoutConstraint->selfIdealSize->Width();
89 }
90 auto reSetWidth = ConvertToPx(width, constraint.scaleProperty, constraint.percentReference.Width());
91 return { reSetWidth, reSetHeight };
92 }
93
Layout(LayoutWrapper * layoutWrapper)94 void RefreshLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
95 {
96 PerformLayout(layoutWrapper);
97 auto layoutProperty = AceType::DynamicCast<NG::RefreshLayoutProperty>(layoutWrapper->GetLayoutProperty());
98 CHECK_NULL_VOID(layoutProperty);
99
100 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
101 if (!child) {
102 continue;
103 }
104 child->Layout();
105 }
106 }
107 // Called to perform layout render node and child.
PerformLayout(LayoutWrapper * layoutWrapper)108 void RefreshLayoutAlgorithm::PerformLayout(LayoutWrapper* layoutWrapper)
109 {
110 CHECK_NULL_VOID(layoutWrapper);
111 auto layoutProperty = AceType::DynamicCast<NG::RefreshLayoutProperty>(layoutWrapper->GetLayoutProperty());
112 CHECK_NULL_VOID(layoutProperty);
113 // update child position.
114 auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
115 const auto& padding = layoutProperty->CreatePaddingAndBorder();
116 MinusPaddingToSize(padding, size);
117 auto left = padding.left.value_or(0);
118 auto top = padding.top.value_or(0);
119 auto paddingOffset = OffsetF(left, top);
120 auto align = Alignment::TOP_CENTER;
121 auto host = layoutWrapper->GetHostNode();
122 CHECK_NULL_VOID(host);
123 auto pattern = host->GetPattern<RefreshPattern>();
124 CHECK_NULL_VOID(pattern);
125 // Update child position.
126 // if customBuilder exist, customBuilder is first child
127 int32_t index = 0;
128 float customBuilderHeight = 0.0f;
129 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
130 if (!child) {
131 index++;
132 continue;
133 }
134 auto paddingOffsetChild = paddingOffset;
135 auto alignChild = align;
136 if (!HasCustomBuilderIndex()) {
137 if (index == layoutWrapper->GetTotalChildCount() - 1) {
138 alignChild = Alignment::TOP_CENTER;
139 }
140 } else {
141 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
142 auto builderChild = layoutWrapper->GetOrCreateChildByIndex(customBuilderIndex_.value_or(0));
143 CHECK_NULL_VOID(builderChild);
144 auto geometryNode = builderChild->GetGeometryNode();
145 CHECK_NULL_VOID(geometryNode);
146 auto builderHeight = geometryNode->GetMarginFrameSize().Height();
147 alignChild = Alignment::TOP_CENTER;
148 if (index == customBuilderIndex_.value_or(0)) {
149 auto builderOffset =
150 NearEqual(builderHeight, builderBaseHeight_) ? 0.0f : (builderBaseHeight_ - builderHeight);
151 paddingOffsetChild += OffsetF(0.0f, builderOffset);
152 } else {
153 auto scrollOffset =
154 NearEqual(builderHeight, builderBaseHeight_) ? builderHeight : builderBaseHeight_;
155 paddingOffsetChild += OffsetF(0.0f, scrollOffset);
156 }
157 auto translate =
158 Alignment::GetAlignPosition(size, child->GetGeometryNode()->GetMarginFrameSize(), alignChild) +
159 paddingOffsetChild;
160 child->GetGeometryNode()->SetMarginFrameOffset(translate);
161 index++;
162 continue;
163 }
164 if (index == customBuilderIndex_.value_or(0)) {
165 alignChild = Alignment::TOP_CENTER;
166 paddingOffsetChild += OffsetF(0.0f, customBuilderOffset_);
167 auto geometryNode = child->GetGeometryNode();
168 CHECK_NULL_VOID(geometryNode);
169 customBuilderHeight = geometryNode->GetMarginFrameSize().Height();
170 } else {
171 auto refreshingProp = layoutProperty->GetIsRefreshing().value_or(false);
172 if (refreshingProp) {
173 auto distance = static_cast<float>(TRIGGER_REFRESH_DISTANCE.ConvertToPx());
174 auto refreshingPosition = Positive(customBuilderHeight) ? distance + customBuilderHeight : 0.0f;
175 paddingOffsetChild += OffsetF(0.0f, refreshingPosition);
176 } else {
177 paddingOffsetChild += OffsetF(0.0f, scrollOffset_);
178 }
179 }
180 }
181 auto translate = Alignment::GetAlignPosition(size, child->GetGeometryNode()->GetMarginFrameSize(), alignChild) +
182 paddingOffsetChild;
183 child->GetGeometryNode()->SetMarginFrameOffset(translate);
184 index++;
185 }
186 }
187
188 } // namespace OHOS::Ace::NG
189