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