• 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     float totalHeight = allItemsRect.GetHeight() + 2.0f * scrollBlankSize_; // 2: two blank spaces on both sides
387     int16_t height = GetHeight();
388     if (totalHeight < height) {
389         return;
390     } else {
391         yScrollBar_->SetForegroundProportion(height / totalHeight);
392         yScrollBar_->SetScrollProgress((scrollBlankSize_ - allItemsRect.GetTop()) /
393                                    (totalHeight - height));
394     }
395     RefreshAnimator();
396 }
397 
IsNeedReCalculateDragEnd()398 bool UIList::IsNeedReCalculateDragEnd()
399 {
400     if (!autoAlign_ || isReCalculateDragEnd_ || (onSelectedView_ == nullptr)) {
401         return false;
402     }
403     int16_t animationLess = 0;
404     if (direction_ == VERTICAL) {
405         animationLess = animatorCallback_.endValueY_ - animatorCallback_.previousValueY_;
406     } else {
407         animationLess = animatorCallback_.endValueX_ - animatorCallback_.previousValueX_;
408     }
409     if (!isDragging_ || (MATH_ABS(animationLess) > RECALCULATE_DRAG_DISTANCE)) {
410         return false;
411     }
412     return true;
413 }
ReCalculateDragEnd()414 bool UIList::ReCalculateDragEnd()
415 {
416     if ((onSelectedView_ == nullptr) || isReCalculateDragEnd_ || !autoAlign_) {
417         return false;
418     }
419 
420     int16_t offsetX = 0;
421     int16_t offsetY = 0;
422     if (direction_ == VERTICAL) {
423         // 2: half
424         offsetY = selectPosition_ - (onSelectedView_->GetY() + (onSelectedView_->GetRelativeRect().GetHeight() / 2));
425     } else {
426         // 2: half
427         offsetX = selectPosition_ - (onSelectedView_->GetX() + (onSelectedView_->GetRelativeRect().GetWidth() / 2));
428     }
429     animatorCallback_.ResetCallback();
430     animatorCallback_.SetDragStartValue(0, 0);
431     animatorCallback_.SetDragEndValue(offsetX, offsetY);
432     animatorCallback_.SetDragTimes(GetAutoAlignTime() / DEFAULT_TASK_PERIOD);
433     scrollAnimator_.Start();
434     isReCalculateDragEnd_ = true;
435     return true;
436 }
437 
MoveChildStepVertical(int16_t distance)438 bool UIList::MoveChildStepVertical(int16_t distance)
439 {
440     bool popRet = false;
441     bool pushRet = false;
442     if (distance > 0) {
443         if ((childrenHead_ == nullptr) || (childrenHead_->GetRelativeRect().GetTop() + distance > 0)) {
444             uint16_t index = GetIndexDec(topIndex_);
445             if (index == topIndex_) {
446                 return false;
447             }
448             UIView* newView = recycle_.GetView(index);
449             if (newView == nullptr) {
450                 return false;
451             }
452             PushFront(newView);
453             pushRet = true;
454         }
455         if (childrenTail_ != nullptr && (childrenTail_->GetRelativeRect().GetTop() + distance > GetHeight())) {
456             PopItem(childrenTail_);
457             popRet = true;
458         }
459     } else {
460         if (childrenTail_ == nullptr || (childrenTail_->GetRelativeRect().GetBottom() + distance < GetHeight())) {
461             UIView* newView = recycle_.GetView(GetIndexInc(bottomIndex_));
462             if (newView == nullptr) {
463                 return false;
464             }
465             PushBack(newView);
466             pushRet = true;
467         }
468         if (childrenHead_ && (childrenHead_->GetRelativeRect().GetBottom() + distance < 0)) {
469             PopItem(childrenHead_);
470             popRet = true;
471         }
472     }
473     return (popRet || pushRet);
474 }
475 
MoveChildStepHorizontal(int16_t distance)476 bool UIList::MoveChildStepHorizontal(int16_t distance)
477 {
478     bool popRet = false;
479     bool pushRet = false;
480     if (distance > 0) {
481         if ((childrenHead_ == nullptr) || (childrenHead_->GetRelativeRect().GetLeft() + distance > 0)) {
482             uint16_t index = GetIndexDec(topIndex_);
483             if (index == topIndex_) {
484                 return false;
485             }
486             UIView* newView = recycle_.GetView(index);
487             if (newView == nullptr) {
488                 return false;
489             }
490             PushFront(newView);
491             pushRet = true;
492         }
493         if (childrenTail_ != nullptr && (childrenTail_->GetRelativeRect().GetLeft() + distance > GetWidth())) {
494             PopItem(childrenTail_);
495             popRet = true;
496         }
497     } else {
498         if (childrenTail_ == nullptr || (childrenTail_->GetRelativeRect().GetRight() + distance < GetWidth())) {
499             UIView* newView = recycle_.GetView(GetIndexInc(bottomIndex_));
500             if (newView == nullptr) {
501                 return false;
502             }
503             PushBack(newView);
504             pushRet = true;
505         }
506         if (childrenHead_ && (childrenHead_->GetRelativeRect().GetRight() + distance < 0)) {
507             PopItem(childrenHead_);
508             popRet = true;
509         }
510     }
511     return (popRet || pushRet);
512 }
513 
MoveChildStep(int16_t distance)514 bool UIList::MoveChildStep(int16_t distance)
515 {
516     if (direction_ == VERTICAL) {
517         return MoveChildStepVertical(distance);
518     } else {
519         return MoveChildStepHorizontal(distance);
520     }
521 }
522 
SetAdapter(AbstractAdapter * adapter)523 void UIList::SetAdapter(AbstractAdapter* adapter)
524 {
525     recycle_.SetAdapter(adapter);
526     recycle_.InitRecycle();
527 }
528 
GetSelectView()529 UIView* UIList::GetSelectView()
530 {
531     if (onSelectedView_ != nullptr) {
532         return onSelectedView_;
533     }
534     if ((childrenHead_ == nullptr) || (selectPosition_ == 0)) {
535         return nullptr;
536     }
537     UIView* child = childrenHead_;
538     while (child != nullptr) {
539         if (direction_ == VERTICAL) {
540             if ((child->GetY() <= selectPosition_) &&
541                 (child->GetY() + child->GetRelativeRect().GetHeight() >= selectPosition_)) {
542                 if (scrollListener_ != nullptr) {
543                     scrollListener_->OnItemSelected(child->GetViewIndex(), child);
544                 }
545                 return child;
546             }
547         } else {
548             if ((child->GetX() <= selectPosition_) &&
549                 (child->GetX() + child->GetRelativeRect().GetWidth() >= selectPosition_)) {
550                 if (scrollListener_ != nullptr) {
551                     scrollListener_->OnItemSelected(child->GetViewIndex(), child);
552                 }
553                 return child;
554             }
555         }
556         child = child->GetNextSibling();
557     }
558     return nullptr;
559 }
560 
PushBack(UIView * view)561 void UIList::PushBack(UIView* view)
562 {
563     if (view == nullptr) {
564         return;
565     }
566     if (childrenTail_ == nullptr) {
567         SetHead(view);
568     } else {
569         if (direction_ == VERTICAL) {
570             view->SetPosition(0, childrenTail_->GetY() + childrenTail_->GetHeightWithMargin());
571         } else {
572             view->SetPosition(childrenTail_->GetX() + childrenTail_->GetWidthWithMargin(), 0);
573         }
574         bottomIndex_ = GetIndexInc(bottomIndex_);
575     }
576 
577     view->SetDragParentInstead(true);
578     UIViewGroup::Add(view);
579 }
580 
PushFront(UIView * view)581 void UIList::PushFront(UIView* view)
582 {
583     if (view == nullptr) {
584         return;
585     }
586     if (GetChildrenHead() == nullptr) {
587         SetHead(view);
588     } else {
589         if (direction_ == VERTICAL) {
590             view->SetPosition(0, GetChildrenHead()->GetY() - view->GetHeightWithMargin());
591         } else {
592             view->SetPosition(GetChildrenHead()->GetX() - view->GetWidthWithMargin(), 0);
593         }
594         topIndex_ = GetIndexDec(topIndex_);
595     }
596     view->SetDragParentInstead(true);
597     UIViewGroup::Insert(nullptr, view);
598 }
599 
PopItem(UIView * view)600 void UIList::PopItem(UIView* view)
601 {
602     if (view == nullptr) {
603         return;
604     }
605     recycle_.AddScrapView(view);
606     if (view == GetChildrenHead()) {
607         topIndex_ = GetIndexInc(topIndex_);
608     }
609 
610     if (view == childrenTail_) {
611         bottomIndex_ = GetIndexDec(bottomIndex_);
612     }
613     UIViewGroup::Remove(view);
614 }
615 
SetHead(UIView * view)616 void UIList::SetHead(UIView* view)
617 {
618     if (view != nullptr) {
619         view->SetPosition(0, 0);
620         topIndex_ = startIndex_;
621         bottomIndex_ = startIndex_;
622     }
623 }
624 
MoveChildByOffset(int16_t xOffset,int16_t yOffset)625 void UIList::MoveChildByOffset(int16_t xOffset, int16_t yOffset)
626 {
627     UIView* view = GetChildrenHead();
628     if (view == nullptr) {
629         return;
630     }
631     int16_t height;
632     int16_t width;
633 
634     if ((onSelectedIndex_ != NULL_SELECT_INDEX) && (selectPosition_ != 0)) {
635         if (yOffset != 0) {
636             height = view->GetRelativeRect().GetHeight();
637             if ((view->GetY() + yOffset > selectPosition_) ||
638                 (childrenTail_->GetY() + height + childrenTail_->GetStyle(STYLE_MARGIN_BOTTOM) + yOffset <
639                  selectPosition_)) {
640                 onSelectedIndex_ = NULL_SELECT_INDEX;
641                 onSelectedView_ = nullptr;
642                 if (scrollListener_ != nullptr) {
643                     scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
644                 }
645             }
646         }
647         if (xOffset != 0) {
648             width = view->GetRelativeRect().GetWidth();
649             if ((view->GetX() + xOffset > selectPosition_) ||
650                 (childrenTail_->GetX() + width + childrenTail_->GetStyle(STYLE_MARGIN_RIGHT) < selectPosition_)) {
651                 onSelectedIndex_ = NULL_SELECT_INDEX;
652                 onSelectedView_ = nullptr;
653                 if (scrollListener_ != nullptr) {
654                     scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
655                 }
656             }
657         }
658     }
659     bool isSelectViewFind = false;
660     do {
661         int16_t x = view->GetX() + xOffset;
662         int16_t y = view->GetY() + yOffset;
663         view->SetPosition(x, y);
664         if ((selectPosition_ != 0) && !isSelectViewFind) {
665             if (direction_ == VERTICAL) {
666                 height = view->GetRelativeRect().GetHeight();
667                 /* Views may be the same but have different indexes because of view recycling. */
668                 if ((y - view->GetStyle(STYLE_PADDING_TOP) <= selectPosition_) &&
669                     (y + view->GetStyle(STYLE_MARGIN_BOTTOM) + height >= selectPosition_) &&
670                     ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
671                     onSelectedIndex_ = view->GetViewIndex();
672                     onSelectedView_ = view;
673                     if (scrollListener_ != nullptr) {
674                         scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
675                     }
676                     isSelectViewFind = true;
677                 }
678             } else {
679                 width = view->GetRelativeRect().GetWidth();
680                 if ((x - view->GetStyle(STYLE_MARGIN_LEFT) <= selectPosition_) &&
681                     (x + width + view->GetStyle(STYLE_MARGIN_RIGHT) >= selectPosition_) &&
682                     ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
683                     onSelectedIndex_ = view->GetViewIndex();
684                     onSelectedView_ = view;
685                     if (scrollListener_ != nullptr) {
686                         scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
687                     }
688                     isSelectViewFind = true;
689                 }
690             }
691 #if ENABLE_VIBRATOR
692             VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc();
693             if (isSelectViewFind && isRotating_ && vibratorFunc != nullptr) {
694                 if (!isLoopList_ && (onSelectedIndex_ == 0 || onSelectedIndex_ == recycle_.adapter_->GetCount() - 1)) {
695                     vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE);
696                     GRAPHIC_LOGI("UIList::MoveChildByOffset calls TYPE_THREE vibrator");
697                 } else {
698                     vibratorFunc(VibratorType::VIBRATOR_TYPE_TWO);
699                     GRAPHIC_LOGI("UIList::MoveChildByOffset calls TYPE_TWO vibrator");
700                 }
701             }
702 #endif
703         }
704         view = view->GetNextSibling();
705     } while (view != nullptr);
706 }
707 
StopAnimator()708 void UIList::StopAnimator()
709 {
710     UIAbstractScroll::StopAnimator();
711     if (!ReCalculateDragEnd()) {
712         if ((scrollListener_ != nullptr) &&
713             (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
714             scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
715             scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
716         }
717     }
718 }
719 
GetIndexInc(uint16_t index)720 uint16_t UIList::GetIndexInc(uint16_t index)
721 {
722     uint16_t ret = index + 1;
723     if (isLoopList_ && (recycle_.GetAdapterItemCount() != 0)) {
724         ret = ret % recycle_.GetAdapterItemCount();
725     }
726     return ret;
727 }
728 
GetIndexDec(uint16_t index)729 uint16_t UIList::GetIndexDec(uint16_t index)
730 {
731     if (index == 0) {
732         if (isLoopList_) {
733             return recycle_.GetAdapterItemCount() - 1;
734         } else {
735             return 0;
736         }
737     } else {
738         return index - 1;
739     }
740 }
741 
ScrollTo(uint16_t index)742 void UIList::ScrollTo(uint16_t index)
743 {
744     UIView* child = GetChildrenHead();
745     UIView* tmp = nullptr;
746     while (child != nullptr) {
747         tmp = child;
748         child = child->GetNextSibling();
749         PopItem(tmp);
750     }
751     onSelectedView_ = nullptr;
752     SetStartIndex(index);
753     recycle_.InitRecycle();
754 }
755 
RefreshList()756 void UIList::RefreshList()
757 {
758     int16_t topIndex = topIndex_;
759     UIView* child = GetChildrenHead();
760     UIView* tmp = nullptr;
761     int16_t offset = 0;
762     if (child != nullptr) {
763         if (direction_ == VERTICAL) {
764             offset = child->GetY();
765         } else {
766             offset = child->GetX();
767         }
768     }
769 
770     while (child != nullptr) {
771         tmp = child;
772         child = child->GetNextSibling();
773         PopItem(tmp);
774     }
775     onSelectedView_ = nullptr;
776 
777     uint16_t tmpStartIndex = startIndex_;
778     if (topIndex > recycle_.GetAdapterItemCount() - 1) {
779         startIndex_ = 0;
780         offset = 0;
781     } else {
782         startIndex_ = topIndex;
783     }
784     recycle_.InitRecycle();
785     startIndex_ = tmpStartIndex;
786 
787     if (direction_ == VERTICAL) {
788         DragYInner(offset);
789     } else {
790         DragXInner(offset);
791     }
792     Invalidate();
793 }
794 
RemoveAll()795 void UIList::RemoveAll()
796 {
797     UIViewGroup::RemoveAll();
798     recycle_.ClearScrapView();
799 }
800 
SetXScrollBarVisible(bool visible)801 void UIList::SetXScrollBarVisible(bool visible)
802 {
803     bool lastVisible = xScrollBarVisible_;
804     UIAbstractScroll::SetXScrollBarVisible(visible);
805     if (!lastVisible && xScrollBarVisible_) {
806         if (recycle_.HasInitialiszed()) {
807             recycle_.MeasureAdapterRelativeRect();
808         } else {
809             recycle_.InitRecycle();
810         }
811     }
812 }
813 
SetYScrollBarVisible(bool visible)814 void UIList::SetYScrollBarVisible(bool visible)
815 {
816     bool lastVisible = yScrollBarVisible_;
817     UIAbstractScroll::SetYScrollBarVisible(visible);
818     if (!lastVisible && yScrollBarVisible_) {
819         if (recycle_.HasInitialiszed()) {
820             recycle_.MeasureAdapterRelativeRect();
821         } else {
822             recycle_.InitRecycle();
823         }
824     }
825 }
826 
CalculateReboundDistance(int16_t & dragDistanceX,int16_t & dragDistanceY)827 void UIList::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY)
828 {
829     if (isLoopList_) {
830         return;
831     }
832     Rect rect = GetAllChildRelativeRect();
833     int16_t top = rect.GetTop();
834     int16_t bottom = rect.GetBottom();
835     int16_t scrollHeight = GetHeight();
836     int16_t left = rect.GetLeft();
837     int16_t right = rect.GetRight();
838     int16_t scrollWidth = GetWidth();
839     if ((direction_ == VERTICAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
840         if (top > scrollBlankSize_) {
841             if ((dragDistanceY + top) > (scrollBlankSize_ + reboundSize_)) {
842                 dragDistanceY = 0;
843             }
844             dragDistanceY += scrollBlankSize_ - (top + dragDistanceY);
845         }
846         if (bottom < (scrollHeight - scrollBlankSize_ - 1)) {
847             if ((dragDistanceY + bottom) < (scrollHeight - scrollBlankSize_ - reboundSize_ - 1)) {
848                 dragDistanceY = 0;
849             }
850             dragDistanceY += scrollHeight - scrollBlankSize_ - 1 - (bottom + dragDistanceY);
851         }
852     } else {
853         if (left > scrollBlankSize_) {
854             if ((dragDistanceX + left) > (scrollBlankSize_ + reboundSize_)) {
855                 dragDistanceX = 0;
856             }
857             dragDistanceX += scrollBlankSize_ - (left + dragDistanceX);
858         }
859         if (right < (scrollWidth - scrollBlankSize_ - 1)) {
860             if ((dragDistanceX + right) < (scrollWidth - scrollBlankSize_ - reboundSize_ - 1)) {
861                 dragDistanceX = 0;
862             }
863             dragDistanceX += scrollWidth - scrollBlankSize_ - 1 - (right + dragDistanceX);
864         }
865     }
866 }
867 
868 /* this is a temporary implementation just used for list and will be replaced later,
869    we assume size of all items in scroll are equal for now. */
FixDistance(int16_t & distanceX,int16_t & distanceY)870 void UIList::FixDistance(int16_t& distanceX, int16_t& distanceY)
871 {
872     if (childrenHead_ == nullptr) {
873         GRAPHIC_LOGW("cannot fix drag distance without children!");
874         return;
875     }
876 
877     if (direction_ == VERTICAL) {
878         FixVerDistance(distanceY);
879     } else {
880         FixHorDistance(distanceX);
881     }
882 }
883 
FixHorDistance(int16_t & distanceX)884 void UIList::FixHorDistance(int16_t& distanceX)
885 {
886     UIView* targetView = childrenHead_;
887     while (targetView != nullptr) {
888         int16_t pos = targetView->GetX();
889         int16_t width = targetView->GetRelativeRect().GetWidth();
890         if (width == 0) {
891             return;
892         }
893         if (pos <= selectPosition_ && pos + width >= selectPosition_) {
894             int16_t offset = selectPosition_ - (pos + width / 2); // 2 : half of width
895             if ((distanceX < 0) && (offset > 0)) {
896                 offset = offset - width;
897             } else if ((distanceX > 0) && (offset < 0)) {
898                 offset = offset + width;
899             }
900             distanceX = (distanceX / width) * width + offset;
901             return;
902         }
903         targetView = targetView->GetNextSibling();
904     }
905 }
906 
FixVerDistance(int16_t & distanceY)907 void UIList::FixVerDistance(int16_t& distanceY)
908 {
909     UIView* targetView = childrenHead_;
910     while (targetView != nullptr) {
911         int16_t pos = targetView->GetY();
912         int16_t height = targetView->GetRelativeRect().GetHeight();
913         if (height == 0) {
914             return;
915         }
916         if (pos <= selectPosition_ && pos + height >= selectPosition_) {
917             int16_t offset = selectPosition_ - (pos + height / 2); // 2 : half of height
918             if ((distanceY < 0) && (offset > 0)) {
919                 offset = offset - height;
920             } else if ((distanceY > 0) && (offset < 0)) {
921                 offset = offset + height;
922             }
923             distanceY = (distanceY / height) * height + offset;
924             return;
925         }
926         targetView = targetView->GetNextSibling();
927     }
928 }
929 } // namespace OHOS
930