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