• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/list/list_watch_layout_manager.h"
17 
18 #include "core/components/list/render_list_item_group.h"
19 #include "core/components/scroll/render_multi_child_scroll.h"
20 
21 namespace OHOS::Ace {
22 
23 namespace {
24 
25 const double HALF_SIZE = 0.5;
26 
27 } // namespace
28 
ListWatchLayoutManager(RenderList & renderList)29 ListWatchLayoutManager::ListWatchLayoutManager(RenderList& renderList)
30     : ListLayoutManager(renderList) {}
31 
PerformLayout()32 void ListWatchLayoutManager::PerformLayout()
33 {
34     LOGD("PerformLayout head:%{public}lf tail:%{public}lf", head_, tail_);
35     renderList_.SetCenterIndex(INVALID_INDEX);
36     if (renderList_.GetAddDeleteEffect()) {
37         AnimationForItemUpdate();
38     } else {
39         RefreshLayout();
40     }
41 
42     int32_t itemIndex = GetIndexByPosition(head_);
43     renderList_.RecycleHead(itemIndex - 1); // Recycle head items.
44     double curMainSize = GetItemPosition(itemIndex);
45     LayoutParam innerLayout = MakeInnerLayoutParam(crossAxisAlign_);
46     auto itemChild = renderList_.GetChildByIndex(itemIndex);
47     int32_t firstIndex = itemIndex;
48     while (itemChild) {
49         UpdateItemGroupAttr(itemChild);
50         itemChild->Layout(AdjustLayoutParam(itemChild, innerLayout));
51         if (itemIndex == ZERO_INDEX) {
52             firstChildSize_ = renderList_.GetMainSize(itemChild->GetLayoutSize());
53         }
54         lastChildSize_ = renderList_.GetMainSize(itemChild->GetLayoutSize());
55         LOGD("Index:%{public}d mainSize:%{public}lf", itemIndex, curMainSize);
56 
57         SetChildPosition(itemChild, itemIndex, curMainSize);
58         itemPosition_[itemIndex] = curMainSize;
59         curMainSize += renderList_.GetMainSize(itemChild->GetLayoutSize());
60         if (curMainSize >= tail_) {
61             break;
62         }
63         CalculateItemState(itemChild);
64         itemChild = renderList_.GetChildByIndex(++itemIndex);
65     }
66     RequestMoreItemsIfNeeded(firstIndex, itemIndex);
67     renderList_.RecycleTail(itemIndex + 1); // Recycle tail items.
68 
69     if (renderList_.GetCenterIndex() == INVALID_INDEX) {
70         MarkAllItemBlur();
71     }
72     if (renderList_.IsCenterLayout() && firstChildSize_ < renderList_.GetMainSize(viewPort_)) {
73         if (NearZero(lastChildSize_)) {
74             lastChildSize_ = firstChildSize_;
75         }
76         curMainSize = AdjustLayoutSize(curMainSize);
77     }
78 
79     Size layoutSize = renderList_.MakeValue<Size>(curMainSize, renderList_.GetCrossSize(viewPort_));
80     renderList_.SetLayoutSize(layoutSize);
81     renderList_.CalculateStickyItem(position_);
82     ShowItemFocusAnimation();
83     HandleItemStateAndEffect();
84     firstLayout_ = false;
85 }
86 
SetChildPosition(const RefPtr<RenderNode> & child,int32_t index,double mainSize)87 void ListWatchLayoutManager::SetChildPosition(const RefPtr<RenderNode>& child, int32_t index, double mainSize)
88 {
89     double mainLen = renderList_.GetMainSize(viewPort_);
90     double crossLen = renderList_.GetCrossSize(viewPort_);
91     double mainAxis = mainSize;
92     double crossAxis = 0.0;
93     auto listItemChild = RenderListItem::GetRenderListItem(child);
94     FlexAlign selfAlign = listItemChild ? listItemChild->GetSelfAlign() : FlexAlign::AUTO;
95     FlexAlign align = selfAlign == FlexAlign::AUTO ? crossAxisAlign_ : selfAlign;
96     if (rightToLeft_) {
97         if (align == FlexAlign::FLEX_END) {
98             align = FlexAlign::FLEX_START;
99         } else if (align == FlexAlign::FLEX_START) {
100             align = FlexAlign::FLEX_END;
101         }
102     }
103     switch (align) {
104         case FlexAlign::FLEX_END:
105             crossAxis = crossLen - renderList_.GetCrossSize(child->GetLayoutSize());
106             break;
107         case FlexAlign::CENTER:
108             crossAxis = (crossLen - renderList_.GetCrossSize(child->GetLayoutSize())) / 2.0;
109             break;
110         case FlexAlign::STRETCH:
111         case FlexAlign::FLEX_START:
112         default:
113             break;
114     }
115     auto isPlatformFive = IsPlatformFive();
116 
117     if (isVertical_) {
118         if (direction_ == FlexDirection::COLUMN_REVERSE) {
119             mainAxis = mainLen - renderList_.GetMainSize(child->GetLayoutSize()) - mainAxis;
120         }
121 
122         if (isPlatformFive && renderList_.IsCenterLayout() && firstChildSize_ < renderList_.GetMainSize(viewPort_)) {
123             mainAxis += (renderList_.GetMainSize(viewPort_) - firstChildSize_) * HALF_SIZE;
124         }
125         child->SetPosition(Offset(crossAxis, mainAxis) + position_);
126     } else {
127         if (IsRowReverse()) {
128             mainAxis = mainLen - renderList_.GetMainSize(child->GetLayoutSize()) - mainAxis;
129         }
130         if (isPlatformFive && renderList_.IsCenterLayout() && firstChildSize_ < renderList_.GetMainSize(viewPort_)) {
131             mainAxis += (renderList_.GetMainSize(viewPort_) - firstChildSize_) * HALF_SIZE;
132         }
133         child->SetPosition(Offset(mainAxis, crossAxis) + position_);
134     }
135     LOGD("Child:%{public}lf %{public}lf %{public}s", mainAxis, crossAxis, position_.ToString().c_str());
136 }
137 
HandleItemStateAndEffect()138 void ListWatchLayoutManager::HandleItemStateAndEffect()
139 {
140     auto isFromRotate = false;
141     auto parentScroll = AceType::DynamicCast<RenderScroll>(renderList_.GetParent().Upgrade());
142     if (parentScroll) {
143         isFromRotate = parentScroll->IsFromRotate();
144     }
145     RefPtr<RenderListItem> listItem;
146     for (const auto& item : renderList_.GetItems()) {
147         if (!item.second || item.second->GetChildren().empty()) {
148             continue;
149         }
150 
151         listItem = AceType::DynamicCast<RenderListItem>(item.second->GetChildren().front());
152         if (!listItem) {
153             break;
154         }
155         auto index = listItem->GetIndex();
156         auto centerIndex = renderList_.GetCenterIndex();
157         if (index == centerIndex - 1 || index == centerIndex + 1 ||
158             (centerIndex == INVALID_INDEX && index == renderList_.GetCurrentMaxIndex())) {
159             listItem->SetCurrentState(ItemState::NEARBY);
160         }
161         listItem->HandleItemEffect(isFromRotate);
162     }
163 }
164 
CalculateItemState(RefPtr<RenderNode> & item)165 void ListWatchLayoutManager::CalculateItemState(RefPtr<RenderNode>& item)
166 {
167     auto centerItem = RenderListItem::GetRenderListItem(item);
168     auto isVertical = direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE;
169     if (centerItem) {
170         if (centerItem->IsItemCenter(isVertical, viewPort_)) {
171             centerItem->SetCurrentState(ItemState::FOCUS);
172             renderList_.SetCenterIndex(centerItem->GetIndex());
173         } else {
174             centerItem->SetCurrentState(ItemState::BLUR);
175         }
176         centerItem->CalculateScaleFactorOnWatch();
177     }
178 }
179 
MarkAllItemBlur()180 void ListWatchLayoutManager::MarkAllItemBlur()
181 {
182     RefPtr<RenderListItem> listItem;
183     for (const auto& item : renderList_.GetItems()) {
184         if (!item.second || item.second->GetChildren().empty()) {
185             continue;
186         }
187 
188         listItem = AceType::DynamicCast<RenderListItem>(item.second->GetChildren().front());
189         if (!listItem) {
190             break;
191         } else {
192             listItem->SetCurrentState(ItemState::BLUR);
193         }
194     }
195     renderList_.SetCenterIndex(INVALID_INDEX);
196 }
197 
GetFirstChildSize(RefPtr<RenderNode> & itemChild)198 double ListWatchLayoutManager::GetFirstChildSize(RefPtr<RenderNode>& itemChild)
199 {
200     auto renderListItem = RenderListItem::GetRenderListItem(itemChild);
201     if (!renderListItem) {
202         return renderList_.GetMainSize(itemChild->GetLayoutSize());
203     }
204     auto renderListItemGroup = AceType::DynamicCast<RenderListItemGroup>(renderListItem);
205     if (!renderListItemGroup) {
206         return renderList_.GetMainSize(itemChild->GetLayoutSize());
207     }
208     auto children = renderListItemGroup->GetChildren();
209     auto rIter = children.rbegin();
210     while (rIter != children.rend()) {
211         auto child = *rIter++;
212         auto listItemNode = RenderListItem::GetRenderListItem(child);
213         if (listItemNode && listItemNode->GetPrimary()) {
214             return renderList_.GetMainSize(child->GetLayoutSize());
215         }
216     }
217     return renderList_.GetMainSize(itemChild->GetLayoutSize());
218 }
219 
AdjustLayoutSize(double size)220 double ListWatchLayoutManager::AdjustLayoutSize(double size)
221 {
222     if (!renderList_.IsCenterLayout()) {
223         return size;
224     }
225     if (NearZero(lastChildSize_)) {
226         lastChildSize_ = firstChildSize_;
227     }
228     if (IsPlatformFive()) {
229         double changeSize = size + renderList_.GetMainSize(viewPort_);
230         changeSize = changeSize - (firstChildSize_ + lastChildSize_) * HALF_SIZE;
231         return changeSize;
232     } else {
233         return size + (renderList_.GetMainSize(viewPort_) - lastChildSize_) * HALF_SIZE;
234     }
235 }
236 
IsPlatformFive()237 bool ListWatchLayoutManager::IsPlatformFive()
238 {
239     auto context = renderList_.GetContext().Upgrade();
240     const static int32_t PLATFORM_VERSION_FIVE = 5;
241     return context && context->GetMinPlatformVersion() <= PLATFORM_VERSION_FIVE;
242 }
243 
244 } // namespace OHOS::Ace