• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-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 "components/ui_list.h"
17 
18 #include "components/ui_abstract_scroll_bar.h"
19 #include "gfx_utils/graphic_log.h"
20 
21 namespace OHOS {
~Recycle()22 UIList::Recycle::~Recycle()
23 {
24     ListNode<UIView*>* node = scrapView_.Begin();
25     while (node != scrapView_.End()) {
26         if (node->data_) {
27             UIView* deleteView = node->data_;
28             if (deleteView != nullptr) {
29                 delete deleteView;
30                 deleteView = nullptr;
31                 node->data_ = nullptr;
32             }
33         }
34         node = node->next_;
35     }
36     scrapView_.Clear();
37 }
38 
MeasureAdapterRelativeRect()39 void UIList::Recycle::MeasureAdapterRelativeRect()
40 {
41     uint16_t i = 0;
42     if (listView_ == nullptr) {
43         return;
44     }
45     UIView* childHead = listView_->childrenHead_;
46     if (childHead == nullptr) {
47         return;
48     }
49     uint16_t idx = childHead->GetViewIndex();
50     if (listView_->direction_ == VERTICAL) {
51         int32_t height = 0;
52         for (; i < idx; i++) {
53             height += adapter_->GetItemHeightWithMargin(i);
54         }
55         int16_t y = childHead->GetRelativeRect().GetTop() - height - childHead->GetStyle(STYLE_MARGIN_TOP);
56         for (; i < adapter_->GetCount(); i++) {
57             height += adapter_->GetItemHeightWithMargin(i);
58         }
59         adapterRelativeRect_.SetRect(0, y, listView_->GetWidth() - 1, y + height - 1);
60     } else {
61         int32_t width = 0;
62         for (; i < idx; i++) {
63             width += adapter_->GetItemWidthWithMargin(i);
64         }
65         int16_t x = childHead->GetRelativeRect().GetLeft() - width - childHead->GetStyle(STYLE_MARGIN_LEFT);
66         for (; i < adapter_->GetCount(); i++) {
67             width += adapter_->GetItemWidthWithMargin(i);
68         }
69         adapterRelativeRect_.SetRect(x, 0, x + width - 1, listView_->GetHeight() - 1);
70     }
71 }
72 
InitRecycle()73 void UIList::Recycle::InitRecycle()
74 {
75     if ((adapter_ == nullptr) || (listView_ == nullptr)) {
76         return;
77     }
78     FillActiveView();
79     listView_->Invalidate();
80     hasInitialiszed_ = true;
81     if (listView_->xScrollBarVisible_ || listView_->yScrollBarVisible_) {
82         MeasureAdapterRelativeRect();
83     }
84 }
85 
GetView(int16_t index)86 UIView* UIList::Recycle::GetView(int16_t index)
87 {
88     if (adapter_ == nullptr) {
89         return nullptr;
90     }
91     UIView* inView = nullptr;
92     UIView* retView = nullptr;
93 
94     if (scrapView_.Size() != 0) {
95         inView = scrapView_.Back();
96     }
97 
98     retView = adapter_->GetView(inView, index);
99     if (retView != nullptr) {
100         retView->SetViewIndex(index);
101         scrapView_.PopBack();
102     }
103     return retView;
104 }
105 
FillActiveView()106 void UIList::Recycle::FillActiveView()
107 {
108     uint16_t index = listView_->GetStartIndex();
109     if (listView_->GetDirection() == UIList::VERTICAL) {
110         int16_t childBottom = 0;
111         while ((index < adapter_->GetCount()) && (childBottom < listView_->GetHeight())) {
112             UIView* view = GetView(index);
113             if (view == nullptr) {
114                 break;
115             }
116             listView_->PushBack(view);
117             if (listView_->childrenTail_) {
118                 childBottom =
119                     listView_->childrenTail_->GetY() + listView_->childrenTail_->GetRelativeRect().GetHeight();
120             } else {
121                 break;
122             }
123             index++;
124         }
125     } else {
126         int16_t childRight = 0;
127         while ((index < adapter_->GetCount()) && (childRight < listView_->GetWidth())) {
128             UIView* view = GetView(index);
129             listView_->PushBack(view);
130             if (listView_->childrenTail_) {
131                 childRight = listView_->childrenTail_->GetX() + listView_->childrenTail_->GetRelativeRect().GetWidth();
132             } else {
133                 break;
134             }
135             index++;
136         }
137     }
138 }
139 
GetAdapterItemsReletiveRect()140 Rect32 UIList::Recycle::GetAdapterItemsReletiveRect()
141 {
142     return adapterRelativeRect_;
143 }
144 
MoveAdapterItemsRelativeRect(int16_t x,int16_t y)145 void UIList::Recycle::MoveAdapterItemsRelativeRect(int16_t x, int16_t y)
146 {
147     auto& rect = adapterRelativeRect_;
148     rect.SetPosition(rect.GetX() + x, rect.GetY() + y);
149 }
150 
UIList()151 UIList::UIList() : UIList(VERTICAL) {}
152 
UIList(uint8_t direction)153 UIList::UIList(uint8_t direction)
154     : onSelectedView_(nullptr),
155       isLoopList_(false),
156       isReCalculateDragEnd_(true),
157       autoAlign_(false),
158       alignTime_(DEFAULT_ALIGN_TIMES),
159       startIndex_(0),
160       topIndex_(0),
161       bottomIndex_(0),
162       selectPosition_(0),
163       onSelectedIndex_(0),
164       recycle_(this),
165       scrollListener_(nullptr)
166 {
167 #if ENABLE_ROTATE_INPUT
168     rotateFactor_ = DEFAULT_LIST_ROTATE_FACTOR;
169     rotateThrowthreshold_ = LIST_ROTATE_THROW_THRESHOLD;
170     rotateAccCoefficient_ = LIST_ROTATE_DISTANCE_COEFF;
171 #endif
172 #if ENABLE_FOCUS_MANAGER
173     focusable_ = true;
174 #endif
175     direction_ = direction;
176     touchable_ = true;
177     draggable_ = true;
178     dragParentInstead_ = false;
179 }
180 
~UIList()181 UIList::~UIList()
182 {
183     UIView* view = GetChildrenHead();
184     while (view != nullptr) {
185         UIView* tmp = view->GetNextSibling();
186         UIViewGroup::Remove(view);
187         delete view;
188         view = tmp;
189     }
190 }
191 
OnDragEvent(const DragEvent & event)192 bool UIList::OnDragEvent(const DragEvent& event)
193 {
194     if (scrollAnimator_.GetState() != Animator::STOP) {
195         UIAbstractScroll::StopAnimator();
196     }
197     isReCalculateDragEnd_ = true;
198     int16_t xDistance = event.GetDeltaX();
199     int16_t yDistance = event.GetDeltaY();
200     if (direction_ == VERTICAL) {
201         RefreshDelta(yDistance);
202         DragYInner(yDistance);
203     } else {
204         RefreshDelta(xDistance);
205         DragXInner(xDistance);
206     }
207     return UIView::OnDragEvent(event);
208 }
209 
OnDragEndEvent(const DragEvent & event)210 bool UIList::OnDragEndEvent(const DragEvent& event)
211 {
212     Point last = event.GetPreLastPoint();
213     Point current = event.GetLastPoint();
214     if ((last.x == current.x) && (last.y == current.y)) {
215         last = current;
216         current = event.GetCurrentPos();
217     }
218     isReCalculateDragEnd_ = false;
219     if (!DragThrowAnimator(current, last, event.GetDragDirection(), dragBack_)) {
220         if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
221             scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
222             scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
223         }
224     }
225     return UIView::OnDragEndEvent(event);
226 }
227 
OnPressEvent(const PressEvent & event)228 bool UIList::OnPressEvent(const PressEvent& event)
229 {
230     StopAnimator();
231     return UIView::OnPressEvent(event);
232 }
233 
234 #if ENABLE_ROTATE_INPUT
OnRotateStartEvent(const RotateEvent & event)235 bool UIList::OnRotateStartEvent(const RotateEvent& event)
236 {
237     isReCalculateDragEnd_ = true;
238     return UIAbstractScroll::OnRotateStartEvent(event);
239 }
240 
OnRotateEndEvent(const RotateEvent & event)241 bool UIList::OnRotateEndEvent(const RotateEvent& event)
242 {
243     isReCalculateDragEnd_ = false;
244     return UIAbstractScroll::OnRotateEndEvent(event);
245 }
246 #endif
247 
ScrollBy(int16_t distance)248 void UIList::ScrollBy(int16_t distance)
249 {
250     if (direction_ == VERTICAL) {
251         DragYInner(distance);
252     } else {
253         DragXInner(distance);
254     }
255     if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
256         scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
257         scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
258     }
259 }
260 
DragXInner(int16_t distance)261 bool UIList::DragXInner(int16_t distance)
262 {
263     if (IsNeedReCalculateDragEnd()) {
264         return false;
265     }
266     int16_t listWidth = GetWidth();
267     if (distance == 0) {
268         return true;
269     }
270     int16_t reboundSize = reboundSize_;
271     if (isLoopList_ || (scrollAnimator_.GetState() != Animator::STOP)) {
272         reboundSize = 0;
273     }
274     bool ret = 0;
275     do {
276         ret = MoveChildStep(distance);
277     } while (ret);
278 
279     if (isLoopList_) {
280         return MoveOffset(distance, 0);
281     }
282     if (distance > 0) {
283         if (childrenHead_ && ((childrenHead_->GetX() + distance) > (scrollBlankSize_ + reboundSize))) {
284             distance = scrollBlankSize_ + reboundSize - childrenHead_->GetX();
285         }
286     } else {
287         if (childrenTail_) {
288             if (childrenTail_->GetRelativeRect().GetRight() + childrenTail_->GetStyle(STYLE_MARGIN_RIGHT) <
289                 listWidth - scrollBlankSize_ - reboundSize) {
290                 distance = 0;
291             } else if ((childrenTail_->GetRelativeRect().GetRight() + childrenTail_->GetStyle(STYLE_MARGIN_RIGHT) +
292                         distance) <= (listWidth - scrollBlankSize_ - reboundSize)) {
293                 distance = listWidth - scrollBlankSize_ - reboundSize - childrenTail_->GetRelativeRect().GetRight() -
294                            childrenTail_->GetStyle(STYLE_MARGIN_RIGHT) - 1;
295             }
296         }
297     }
298     return MoveOffset(distance, 0);
299 }
300 
DragYInner(int16_t distance)301 bool UIList::DragYInner(int16_t distance)
302 {
303     if (IsNeedReCalculateDragEnd()) {
304         return false;
305     }
306     int16_t listHeight = GetHeight();
307     if (distance == 0) {
308         return true;
309     }
310     int16_t reboundSize = reboundSize_;
311     if (isLoopList_ || (scrollAnimator_.GetState() != Animator::STOP)) {
312         reboundSize = 0;
313     }
314     bool ret = 0;
315     do {
316         ret = MoveChildStep(distance);
317     } while (ret);
318 
319     if (isLoopList_) {
320         return MoveOffset(0, distance);
321     }
322     if (distance > 0) {
323         if (childrenHead_ && ((childrenHead_->GetY() + distance) > (scrollBlankSize_ + reboundSize))) {
324             distance = scrollBlankSize_ + reboundSize - childrenHead_->GetY();
325         }
326     } else {
327         if (childrenTail_) {
328             if (childrenTail_->GetRelativeRect().GetBottom() + childrenTail_->GetStyle(STYLE_MARGIN_BOTTOM) <
329                 listHeight - scrollBlankSize_ - reboundSize) {
330                 distance = 0;
331             } else if ((childrenTail_->GetRelativeRect().GetBottom() + childrenTail_->GetStyle(STYLE_MARGIN_BOTTOM) +
332                         distance) <= (listHeight - scrollBlankSize_ - reboundSize)) {
333                 distance = listHeight - scrollBlankSize_ - reboundSize - childrenTail_->GetRelativeRect().GetBottom() -
334                            childrenTail_->GetStyle(STYLE_MARGIN_BOTTOM) - 1;
335             }
336         }
337     }
338     return MoveOffset(0, distance);
339 }
340 
MoveOffset(int16_t x,int16_t y)341 bool UIList::MoveOffset(int16_t x, int16_t y)
342 {
343     if ((x == 0) && (y == 0)) {
344         return false;
345     }
346     MoveChildByOffset(x, y);
347     if (xScrollBarVisible_ || yScrollBarVisible_) {
348         recycle_.MoveAdapterItemsRelativeRect(x, y);
349         UpdateScrollBar();
350     }
351     Invalidate();
352     if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_STOP)) {
353         scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_MOVE);
354         scrollListener_->OnScrollStart(onSelectedIndex_, onSelectedView_);
355     }
356 
357     if (!isLoopList_ && scrollListener_) {
358         if (direction_ == VERTICAL) {
359             if (childrenHead_ && (childrenHead_->GetViewIndex() == 0) &&
360                 childrenHead_->GetRelativeRect().GetTop() >= 0 && childrenHead_->GetRelativeRect().GetTop() - y < 0) {
361                 scrollListener_->OnScrollTop(childrenHead_->GetViewIndex(), childrenHead_);
362             }
363             if (childrenTail_ && (childrenTail_->GetViewIndex() == recycle_.GetAdapterItemCount() - 1) &&
364                 (childrenTail_->GetRelativeRect().GetBottom() <= GetContentRect().GetHeight() - 1) &&
365                 (childrenTail_->GetRelativeRect().GetBottom() - y > GetContentRect().GetHeight() - 1)) {
366                 scrollListener_->OnScrollBottom(childrenTail_->GetViewIndex(), childrenTail_);
367             }
368         } else {
369             if (childrenHead_ && (childrenHead_->GetViewIndex() == 0) &&
370                 childrenHead_->GetRelativeRect().GetLeft() >= 0 && childrenHead_->GetRelativeRect().GetLeft() - x < 0) {
371                 scrollListener_->OnScrollTop(childrenHead_->GetViewIndex(), childrenHead_);
372             }
373             if (childrenTail_ && (childrenTail_->GetViewIndex() == recycle_.GetAdapterItemCount() - 1) &&
374                 (childrenTail_->GetRelativeRect().GetRight() <= GetContentRect().GetWidth() - 1) &&
375                 (childrenTail_->GetRelativeRect().GetRight() - x > GetContentRect().GetWidth() - 1)) {
376                 scrollListener_->OnScrollBottom(childrenTail_->GetViewIndex(), childrenTail_);
377             }
378         }
379     }
380     return true;
381 }
382 
UpdateScrollBar()383 void UIList::UpdateScrollBar()
384 {
385     auto allItemsRect = recycle_.GetAdapterItemsReletiveRect();
386     int16_t totalHeight = allItemsRect.GetHeight() + 2 * scrollBlankSize_; // 2: two blank spaces on both sides
387     int16_t height = GetHeight();
388     yScrollBar_->SetForegroundProportion(static_cast<float>(height) / totalHeight);
389     yScrollBar_->SetScrollProgress(static_cast<float>(scrollBlankSize_ - allItemsRect.GetTop()) /
390                                    (totalHeight - height));
391     RefreshAnimator();
392 }
393 
IsNeedReCalculateDragEnd()394 bool UIList::IsNeedReCalculateDragEnd()
395 {
396     if (!autoAlign_ || isReCalculateDragEnd_ || (onSelectedView_ == nullptr)) {
397         return false;
398     }
399     int16_t animationLess = 0;
400     if (direction_ == VERTICAL) {
401         animationLess = animatorCallback_.endValueY_ - animatorCallback_.previousValueY_;
402     } else {
403         animationLess = animatorCallback_.endValueX_ - animatorCallback_.previousValueX_;
404     }
405     if (!isDragging_ || (MATH_ABS(animationLess) > RECALCULATE_DRAG_DISTANCE)) {
406         return false;
407     }
408     return true;
409 }
ReCalculateDragEnd()410 bool UIList::ReCalculateDragEnd()
411 {
412     if ((onSelectedView_ == nullptr) || isReCalculateDragEnd_ || !autoAlign_) {
413         return false;
414     }
415 
416     int16_t offsetX = 0;
417     int16_t offsetY = 0;
418     if (direction_ == VERTICAL) {
419         // 2: half
420         offsetY = selectPosition_ - (onSelectedView_->GetY() + (onSelectedView_->GetRelativeRect().GetHeight() / 2));
421     } else {
422         // 2: half
423         offsetX = selectPosition_ - (onSelectedView_->GetX() + (onSelectedView_->GetRelativeRect().GetWidth() / 2));
424     }
425     animatorCallback_.ResetCallback();
426     animatorCallback_.SetDragStartValue(0, 0);
427     animatorCallback_.SetDragEndValue(offsetX, offsetY);
428     animatorCallback_.SetDragTimes(GetAutoAlignTime() / DEFAULT_TASK_PERIOD);
429     scrollAnimator_.Start();
430     isReCalculateDragEnd_ = true;
431     return true;
432 }
433 
MoveChildStepVertical(int16_t distance)434 bool UIList::MoveChildStepVertical(int16_t distance)
435 {
436     bool popRet = false;
437     bool pushRet = false;
438     if (distance > 0) {
439         if ((childrenHead_ == nullptr) || (childrenHead_->GetRelativeRect().GetTop() + distance > 0)) {
440             uint16_t index = GetIndexDec(topIndex_);
441             if (index == topIndex_) {
442                 return false;
443             }
444             UIView* newView = recycle_.GetView(index);
445             if (newView == nullptr) {
446                 return false;
447             }
448             PushFront(newView);
449             pushRet = true;
450         }
451         if (childrenTail_ != nullptr && (childrenTail_->GetRelativeRect().GetTop() + distance > GetHeight())) {
452             PopItem(childrenTail_);
453             popRet = true;
454         }
455     } else {
456         if (childrenTail_ == nullptr || (childrenTail_->GetRelativeRect().GetBottom() + distance < GetHeight())) {
457             UIView* newView = recycle_.GetView(GetIndexInc(bottomIndex_));
458             if (newView == nullptr) {
459                 return false;
460             }
461             PushBack(newView);
462             pushRet = true;
463         }
464         if (childrenHead_ && (childrenHead_->GetRelativeRect().GetBottom() + distance < 0)) {
465             PopItem(childrenHead_);
466             popRet = true;
467         }
468     }
469     return (popRet || pushRet);
470 }
471 
MoveChildStepHorizontal(int16_t distance)472 bool UIList::MoveChildStepHorizontal(int16_t distance)
473 {
474     bool popRet = false;
475     bool pushRet = false;
476     if (distance > 0) {
477         if ((childrenHead_ == nullptr) || (childrenHead_->GetRelativeRect().GetLeft() + distance > 0)) {
478             uint16_t index = GetIndexDec(topIndex_);
479             if (index == topIndex_) {
480                 return false;
481             }
482             UIView* newView = recycle_.GetView(index);
483             if (newView == nullptr) {
484                 return false;
485             }
486             PushFront(newView);
487             pushRet = true;
488         }
489         if (childrenTail_ != nullptr && (childrenTail_->GetRelativeRect().GetLeft() + distance > GetWidth())) {
490             PopItem(childrenTail_);
491             popRet = true;
492         }
493     } else {
494         if (childrenTail_ == nullptr || (childrenTail_->GetRelativeRect().GetRight() + distance < GetWidth())) {
495             UIView* newView = recycle_.GetView(GetIndexInc(bottomIndex_));
496             if (newView == nullptr) {
497                 return false;
498             }
499             PushBack(newView);
500             pushRet = true;
501         }
502         if (childrenHead_ && (childrenHead_->GetRelativeRect().GetRight() + distance < 0)) {
503             PopItem(childrenHead_);
504             popRet = true;
505         }
506     }
507     return (popRet || pushRet);
508 }
509 
MoveChildStep(int16_t distance)510 bool UIList::MoveChildStep(int16_t distance)
511 {
512     if (direction_ == VERTICAL) {
513         return MoveChildStepVertical(distance);
514     } else {
515         return MoveChildStepHorizontal(distance);
516     }
517 }
518 
SetAdapter(AbstractAdapter * adapter)519 void UIList::SetAdapter(AbstractAdapter* adapter)
520 {
521     recycle_.SetAdapter(adapter);
522     recycle_.InitRecycle();
523 }
524 
GetSelectView()525 UIView* UIList::GetSelectView()
526 {
527     if (onSelectedView_ != nullptr) {
528         return onSelectedView_;
529     }
530     if ((childrenHead_ == nullptr) || (selectPosition_ == 0)) {
531         return nullptr;
532     }
533     UIView* child = childrenHead_;
534     while (child != nullptr) {
535         if (direction_ == VERTICAL) {
536             if ((child->GetY() <= selectPosition_) &&
537                 (child->GetY() + child->GetRelativeRect().GetHeight() >= selectPosition_)) {
538                 if (scrollListener_ != nullptr) {
539                     scrollListener_->OnItemSelected(child->GetViewIndex(), child);
540                 }
541                 return child;
542             }
543         } else {
544             if ((child->GetX() <= selectPosition_) &&
545                 (child->GetX() + child->GetRelativeRect().GetWidth() >= selectPosition_)) {
546                 if (scrollListener_ != nullptr) {
547                     scrollListener_->OnItemSelected(child->GetViewIndex(), child);
548                 }
549                 return child;
550             }
551         }
552         child = child->GetNextSibling();
553     }
554     return nullptr;
555 }
556 
PushBack(UIView * view)557 void UIList::PushBack(UIView* view)
558 {
559     if (view == nullptr) {
560         return;
561     }
562     if (childrenTail_ == nullptr) {
563         SetHead(view);
564     } else {
565         if (direction_ == VERTICAL) {
566             view->SetPosition(0, childrenTail_->GetY() + childrenTail_->GetHeightWithMargin());
567         } else {
568             view->SetPosition(childrenTail_->GetX() + childrenTail_->GetWidthWithMargin(), 0);
569         }
570         bottomIndex_ = GetIndexInc(bottomIndex_);
571     }
572 
573     view->SetDragParentInstead(true);
574     UIViewGroup::Add(view);
575 }
576 
PushFront(UIView * view)577 void UIList::PushFront(UIView* view)
578 {
579     if (view == nullptr) {
580         return;
581     }
582     if (GetChildrenHead() == nullptr) {
583         SetHead(view);
584     } else {
585         if (direction_ == VERTICAL) {
586             view->SetPosition(0, GetChildrenHead()->GetY() - view->GetHeightWithMargin());
587         } else {
588             view->SetPosition(GetChildrenHead()->GetX() - view->GetWidthWithMargin(), 0);
589         }
590         topIndex_ = GetIndexDec(topIndex_);
591     }
592     view->SetDragParentInstead(true);
593     UIViewGroup::Insert(nullptr, view);
594 }
595 
PopItem(UIView * view)596 void UIList::PopItem(UIView* view)
597 {
598     if (view == nullptr) {
599         return;
600     }
601     recycle_.AddScrapView(view);
602     if (view == GetChildrenHead()) {
603         topIndex_ = GetIndexInc(topIndex_);
604     }
605 
606     if (view == childrenTail_) {
607         bottomIndex_ = GetIndexDec(bottomIndex_);
608     }
609     UIViewGroup::Remove(view);
610 }
611 
SetHead(UIView * view)612 void UIList::SetHead(UIView* view)
613 {
614     if (view != nullptr) {
615         view->SetPosition(0, 0);
616         topIndex_ = startIndex_;
617         bottomIndex_ = startIndex_;
618     }
619 }
620 
MoveChildByOffset(int16_t xOffset,int16_t yOffset)621 void UIList::MoveChildByOffset(int16_t xOffset, int16_t yOffset)
622 {
623     UIView* view = GetChildrenHead();
624     if (view == nullptr) {
625         return;
626     }
627     int16_t x;
628     int16_t y;
629     int16_t height;
630     int16_t width;
631 
632     if ((onSelectedIndex_ != NULL_SELECT_INDEX) && (selectPosition_ != 0)) {
633         if (yOffset != 0) {
634             height = view->GetRelativeRect().GetHeight();
635             if ((view->GetY() + yOffset > selectPosition_) ||
636                 (childrenTail_->GetY() + height + childrenTail_->GetStyle(STYLE_MARGIN_BOTTOM) + yOffset <
637                  selectPosition_)) {
638                 onSelectedIndex_ = NULL_SELECT_INDEX;
639                 onSelectedView_ = nullptr;
640                 if (scrollListener_ != nullptr) {
641                     scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
642                 }
643             }
644         }
645         if (xOffset != 0) {
646             width = view->GetRelativeRect().GetWidth();
647             if ((view->GetX() + xOffset > selectPosition_) ||
648                 (childrenTail_->GetX() + width + childrenTail_->GetStyle(STYLE_MARGIN_RIGHT) < selectPosition_)) {
649                 onSelectedIndex_ = NULL_SELECT_INDEX;
650                 onSelectedView_ = nullptr;
651                 if (scrollListener_ != nullptr) {
652                     scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
653                 }
654             }
655         }
656     }
657     bool isSelectViewFind = false;
658     do {
659         x = view->GetX() + xOffset;
660         y = view->GetY() + yOffset;
661         view->SetPosition(x, y);
662         if ((selectPosition_ != 0) && !isSelectViewFind) {
663             if (direction_ == VERTICAL) {
664                 height = view->GetRelativeRect().GetHeight();
665                 /* Views may be the same but have different indexes because of view recycling. */
666                 if ((y - view->GetStyle(STYLE_PADDING_TOP) <= selectPosition_) &&
667                     (y + view->GetStyle(STYLE_MARGIN_BOTTOM) + height >= selectPosition_) &&
668                     ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
669                     onSelectedIndex_ = view->GetViewIndex();
670                     onSelectedView_ = view;
671                     if (scrollListener_ != nullptr) {
672                         scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
673                     }
674                     isSelectViewFind = true;
675                 }
676             } else {
677                 width = view->GetRelativeRect().GetWidth();
678                 if ((x - view->GetStyle(STYLE_MARGIN_LEFT) <= selectPosition_) &&
679                     (x + width + view->GetStyle(STYLE_MARGIN_RIGHT) >= selectPosition_) &&
680                     ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
681                     onSelectedIndex_ = view->GetViewIndex();
682                     onSelectedView_ = view;
683                     if (scrollListener_ != nullptr) {
684                         scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
685                     }
686                     isSelectViewFind = true;
687                 }
688             }
689 #if ENABLE_VIBRATOR
690             VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc();
691             if (isSelectViewFind && isRotating_ && vibratorFunc != nullptr) {
692                 if (!isLoopList_ && (onSelectedIndex_ == 0 || onSelectedIndex_ == recycle_.adapter_->GetCount() - 1)) {
693                     vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE);
694                     GRAPHIC_LOGI("UIList::MoveChildByOffset calls TYPE_THREE vibrator");
695                 } else {
696                     vibratorFunc(VibratorType::VIBRATOR_TYPE_TWO);
697                     GRAPHIC_LOGI("UIList::MoveChildByOffset calls TYPE_TWO vibrator");
698                 }
699             }
700 #endif
701         }
702         view = view->GetNextSibling();
703     } while (view != nullptr);
704 }
705 
StopAnimator()706 void UIList::StopAnimator()
707 {
708     UIAbstractScroll::StopAnimator();
709     if (!ReCalculateDragEnd()) {
710         if ((scrollListener_ != nullptr) &&
711             (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
712             scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
713             scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
714         }
715     }
716 }
717 
GetIndexInc(uint16_t index)718 uint16_t UIList::GetIndexInc(uint16_t index)
719 {
720     uint16_t ret = index + 1;
721     if (isLoopList_ && (recycle_.GetAdapterItemCount() != 0)) {
722         ret = ret % recycle_.GetAdapterItemCount();
723     }
724     return ret;
725 }
726 
GetIndexDec(uint16_t index)727 uint16_t UIList::GetIndexDec(uint16_t index)
728 {
729     if (index == 0) {
730         if (isLoopList_) {
731             return recycle_.GetAdapterItemCount() - 1;
732         } else {
733             return 0;
734         }
735     } else {
736         return index - 1;
737     }
738 }
739 
ScrollTo(uint16_t index)740 void UIList::ScrollTo(uint16_t index)
741 {
742     UIView* child = GetChildrenHead();
743     UIView* tmp = nullptr;
744     while (child != nullptr) {
745         tmp = child;
746         child = child->GetNextSibling();
747         PopItem(tmp);
748     }
749     onSelectedView_ = nullptr;
750     SetStartIndex(index);
751     recycle_.InitRecycle();
752 }
753 
RefreshList()754 void UIList::RefreshList()
755 {
756     int16_t topIndex = topIndex_;
757     UIView* child = GetChildrenHead();
758     UIView* tmp = nullptr;
759     int16_t offset = 0;
760     if (child != nullptr) {
761         if (direction_ == VERTICAL) {
762             offset = child->GetY();
763         } else {
764             offset = child->GetX();
765         }
766     }
767 
768     while (child != nullptr) {
769         tmp = child;
770         child = child->GetNextSibling();
771         PopItem(tmp);
772     }
773     onSelectedView_ = nullptr;
774 
775     uint16_t tmpStartIndex = startIndex_;
776     if (topIndex > recycle_.GetAdapterItemCount() - 1) {
777         startIndex_ = 0;
778         offset = 0;
779     } else {
780         startIndex_ = topIndex;
781     }
782     recycle_.InitRecycle();
783     startIndex_ = tmpStartIndex;
784 
785     if (direction_ == VERTICAL) {
786         DragYInner(offset);
787     } else {
788         DragXInner(offset);
789     }
790     Invalidate();
791 }
792 
RemoveAll()793 void UIList::RemoveAll()
794 {
795     UIViewGroup::RemoveAll();
796     recycle_.ClearScrapView();
797 }
798 
SetXScrollBarVisible(bool visible)799 void UIList::SetXScrollBarVisible(bool visible)
800 {
801     bool lastVisible = xScrollBarVisible_;
802     UIAbstractScroll::SetXScrollBarVisible(visible);
803     if (!lastVisible && xScrollBarVisible_) {
804         if (recycle_.HasInitialiszed()) {
805             recycle_.MeasureAdapterRelativeRect();
806         } else {
807             recycle_.InitRecycle();
808         }
809     }
810 }
811 
SetYScrollBarVisible(bool visible)812 void UIList::SetYScrollBarVisible(bool visible)
813 {
814     bool lastVisible = yScrollBarVisible_;
815     UIAbstractScroll::SetYScrollBarVisible(visible);
816     if (!lastVisible && yScrollBarVisible_) {
817         if (recycle_.HasInitialiszed()) {
818             recycle_.MeasureAdapterRelativeRect();
819         } else {
820             recycle_.InitRecycle();
821         }
822     }
823 }
824 
CalculateReboundDistance(int16_t & dragDistanceX,int16_t & dragDistanceY)825 void UIList::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY)
826 {
827     if (isLoopList_) {
828         return;
829     }
830     Rect rect = GetAllChildRelativeRect();
831     int16_t top = rect.GetTop();
832     int16_t bottom = rect.GetBottom();
833     int16_t scrollHeight = GetHeight();
834     int16_t left = rect.GetLeft();
835     int16_t right = rect.GetRight();
836     int16_t scrollWidth = GetWidth();
837     if ((direction_ == VERTICAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
838         if (top > scrollBlankSize_) {
839             if ((dragDistanceY + top) > (scrollBlankSize_ + reboundSize_)) {
840                 dragDistanceY = 0;
841             }
842             dragDistanceY += scrollBlankSize_ - (top + dragDistanceY);
843         }
844         if (bottom < (scrollHeight - scrollBlankSize_ - 1)) {
845             if ((dragDistanceY + bottom) < (scrollHeight - scrollBlankSize_ - reboundSize_ - 1)) {
846                 dragDistanceY = 0;
847             }
848             dragDistanceY += scrollHeight - scrollBlankSize_ - 1 - (bottom + dragDistanceY);
849         }
850     } else {
851         if (left > scrollBlankSize_) {
852             if ((dragDistanceX + left) > (scrollBlankSize_ + reboundSize_)) {
853                 dragDistanceX = 0;
854             }
855             dragDistanceX += scrollBlankSize_ - (left + dragDistanceX);
856         }
857         if (right < (scrollWidth - scrollBlankSize_ - 1)) {
858             if ((dragDistanceX + right) < (scrollWidth - scrollBlankSize_ - reboundSize_ - 1)) {
859                 dragDistanceX = 0;
860             }
861             dragDistanceX += scrollWidth - scrollBlankSize_ - 1 - (right + dragDistanceX);
862         }
863     }
864 }
865 
866 /* this is a temporary impementation just used for list and will be replaced later,
867    we assume size of all items in scroll are equal for now. */
FixDistance(int16_t & distanceX,int16_t & distanceY)868 void UIList::FixDistance(int16_t& distanceX, int16_t& distanceY)
869 {
870     if (childrenHead_ == nullptr) {
871         GRAPHIC_LOGW("cannot fix drag distance without children!");
872         return;
873     }
874 
875     if (direction_ == VERTICAL) {
876         FixVerDistance(distanceY);
877     } else {
878         FixHorDistance(distanceX);
879     }
880 }
881 
FixHorDistance(int16_t & distanceX)882 void UIList::FixHorDistance(int16_t& distanceX)
883 {
884     UIView* targetView = childrenHead_;
885     while (targetView != nullptr) {
886         int16_t pos = targetView->GetX();
887         int16_t width = targetView->GetRelativeRect().GetWidth();
888         if (width == 0) {
889             return;
890         }
891         if (pos <= selectPosition_ && pos + width >= selectPosition_) {
892             int16_t offset = selectPosition_ - (pos + width / 2); // 2 : half of width
893             if ((distanceX < 0) && (offset > 0)) {
894                 offset = offset - width;
895             } else if ((distanceX > 0) && (offset < 0)) {
896                 offset = offset + width;
897             }
898             distanceX = (distanceX / width) * width + offset;
899             return;
900         }
901         targetView = targetView->GetNextSibling();
902     }
903 }
904 
FixVerDistance(int16_t & distanceY)905 void UIList::FixVerDistance(int16_t& distanceY)
906 {
907     UIView* targetView = childrenHead_;
908     while (targetView != nullptr) {
909         int16_t pos = targetView->GetY();
910         int16_t height = targetView->GetRelativeRect().GetHeight();
911         if (height == 0) {
912             return;
913         }
914         if (pos <= selectPosition_ && pos + height >= selectPosition_) {
915             int16_t offset = selectPosition_ - (pos + height / 2); // 2 : half of height
916             if ((distanceY < 0) && (offset > 0)) {
917                 offset = offset - height;
918             } else if ((distanceY > 0) && (offset < 0)) {
919                 offset = offset + height;
920             }
921             distanceY = (distanceY / height) * height + offset;
922             return;
923         }
924         targetView = targetView->GetNextSibling();
925     }
926 }
927 } // namespace OHOS
928