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_swipe_view.h" 17#include "dock/focus_manager.h" 18#include "dock/vibrator_manager.h" 19#include "gfx_utils/graphic_log.h" 20 21namespace OHOS { 22UISwipeView::UISwipeView(uint8_t direction) 23 : swipeListener_(nullptr), curIndex_(0), blankSize_(DEFAULT_BLANK_SIZE), curView_(nullptr), loop_(false) 24{ 25#if defined(ENABLE_ROTATE_INPUT) && ENABLE_ROTATE_INPUT 26 rotateFactor_ = DEFAULT_SWIPE_VIEW_ROTATE_FACTOR; 27#endif 28 direction_ = direction; 29 tickTime_ = ANIMATOR_TIME; 30 swipeAccCoefficient_ = DRAG_ACC_FACTOR; 31} 32 33UISwipeView::~UISwipeView() {} 34 35void UISwipeView::Add(UIView* view) 36{ 37 if (view == nullptr) { 38 return; 39 } 40 view->SetDragParentInstead(true); 41 UIViewGroup::Add(view); 42 SortChild(); 43 Invalidate(); 44} 45 46void UISwipeView::Insert(UIView* prevView, UIView* insertView) 47{ 48 if (insertView == nullptr) { 49 return; 50 } 51 insertView->SetDragParentInstead(true); 52 UIViewGroup::Insert(prevView, insertView); 53 SortChild(); 54 Invalidate(); 55} 56 57void UISwipeView::Remove(UIView* view) 58{ 59 if (view == nullptr) { 60 return; 61 } 62 UIViewGroup::Remove(view); 63 if (curView_ == view) { 64 curView_ = nullptr; 65 } 66 SortChild(); 67 Invalidate(); 68} 69 70void UISwipeView::MoveHeadOrTailChild() 71{ 72 if (loop_ && (childrenNum_ != 1)) { 73 if (direction_ == HORIZONTAL) { 74 while (childrenHead_->GetX() >= 0) { 75 MoveLastChildToFirst(); 76 } 77 while (childrenTail_->GetX() + childrenTail_->GetWidth() <= GetWidth()) { 78 MoveFirstChildToLast(); 79 } 80 } else { 81 while (childrenHead_->GetY() >= 0) { 82 MoveLastChildToFirst(); 83 } 84 while (childrenTail_->GetY() + childrenTail_->GetHeight() <= GetHeight()) { 85 MoveFirstChildToLast(); 86 } 87 } 88 } 89} 90 91void UISwipeView::SetCurrentPage(uint16_t index, bool needAnimator) 92{ 93 if (needAnimator) { 94 MoveHeadOrTailChild(); 95 } 96 SwitchToPage(index, needAnimator); 97 Invalidate(); 98} 99 100bool UISwipeView::DragXInner(int16_t distance) 101{ 102 if (distance == 0) { 103 return true; 104 } 105 if (!loop_) { 106 if ((distance > 0) && (childrenHead_ != nullptr)) { 107 if (childrenHead_->GetX() >= blankSize_) { 108 distance = 0; 109 } else if (childrenHead_ && (childrenHead_->GetX() + distance > blankSize_)) { 110 distance = blankSize_ - childrenHead_->GetX(); 111 } 112 } else if (childrenTail_ != nullptr) { 113 int16_t width = GetWidth(); 114 if (childrenTail_->GetRelativeRect().GetRight() < width - blankSize_) { 115 distance = 0; 116 } else if (width - (childrenTail_->GetX() + childrenTail_->GetWidth() + distance) > blankSize_) { 117 distance = width - blankSize_ - childrenTail_->GetX() - childrenTail_->GetWidth(); 118 } 119 } 120 } 121 CalculateInvalidate(); 122 MoveChildByOffset(distance, 0); 123 CalculateInvalidate(); 124 return true; 125} 126 127bool UISwipeView::DragYInner(int16_t distance) 128{ 129 if (distance == 0) { 130 return true; 131 } 132 if (!loop_) { 133 if ((distance > 0) && (childrenHead_ != nullptr)) { 134 if (childrenHead_->GetY() >= blankSize_) { 135 distance = 0; 136 } else if ((childrenHead_ != nullptr) && (childrenHead_->GetY() + distance > blankSize_)) { 137 distance = blankSize_ - childrenHead_->GetY(); 138 } 139 } else if (childrenTail_ != nullptr) { 140 int16_t height = GetHeight(); 141 if (childrenTail_->GetRelativeRect().GetBottom() < height - blankSize_) { 142 distance = 0; 143 } else if (height - (childrenTail_->GetY() + childrenTail_->GetHeight() + distance) > blankSize_) { 144 distance = height - blankSize_ - childrenTail_->GetY() - childrenTail_->GetHeight(); 145 } 146 } 147 } 148 CalculateInvalidate(); 149 MoveChildByOffset(0, distance); 150 CalculateInvalidate(); 151 return true; 152} 153 154bool UISwipeView::OnDragEvent(const DragEvent& event) 155{ 156 UIView* currentView = GetViewByIndex(curIndex_); 157 if (currentView == nullptr) { 158 return UIView::OnDragEvent(event); 159 } 160 if (scrollAnimator_.GetState() != Animator::STOP) { 161 StopAnimator(); 162 } 163 164 if (direction_ == HORIZONTAL) { 165 DragXInner(event.GetDeltaX()); 166 RefreshDelta(event.GetDeltaX()); 167 RefreshCurrentViewByPosition(&UIView::GetX, &UIView::GetWidthWithMargin); 168 } else { 169 DragYInner(event.GetDeltaY()); 170 RefreshDelta(event.GetDeltaY()); 171 RefreshCurrentViewByPosition(&UIView::GetY, &UIView::GetHeightWithMargin); 172 } 173 return UIView::OnDragEvent(event); 174} 175 176bool UISwipeView::OnDragEndEvent(const DragEvent& event) 177{ 178 int16_t distance = 0; 179 if (direction_ == HORIZONTAL) { 180 distance = event.GetCurrentPos().x - event.GetPreLastPoint().x; 181 RefreshCurrentViewByThrow(distance, event.GetDragDirection(), &UIView::GetX, &UIView::GetWidthWithMargin); 182 } else { 183 distance = event.GetCurrentPos().y - event.GetPreLastPoint().y; 184 RefreshCurrentViewByThrow(distance, event.GetDragDirection(), &UIView::GetY, &UIView::GetHeightWithMargin); 185 } 186 187 if (curView_ == nullptr) { 188 return UIView::OnDragEndEvent(event); 189 } 190 191 SwitchToPage(curIndex_); 192 193 Invalidate(); 194 return UIView::OnDragEndEvent(event); 195} 196 197#if defined(ENABLE_ROTATE_INPUT) && ENABLE_ROTATE_INPUT 198 199bool UISwipeView::OnRotateEvent(const RotateEvent& event) 200{ 201 int16_t rotateLen = static_cast<int16_t>(event.GetRotate() * rotateFactor_); 202 RefreshRotate(rotateLen); 203 if (direction_ == HORIZONTAL) { 204 DragXInner(rotateLen); 205 RefreshCurrentViewByPosition(&UIView::GetX, &UIView::GetWidthWithMargin); 206 } else { 207 DragYInner(rotateLen); 208 RefreshCurrentViewByPosition(&UIView::GetY, &UIView::GetHeightWithMargin); 209 } 210 211 return UIView::OnRotateEvent(event); 212} 213 214bool UISwipeView::OnRotateEndEvent(const RotateEvent& event) 215{ 216 uint8_t dir; 217 int16_t lastRotateLen = GetMaxRotate(); 218 if (direction_ == HORIZONTAL) { 219 dir = (lastRotateLen >= 0) ? DragEvent::DIRECTION_LEFT_TO_RIGHT : DragEvent::DIRECTION_RIGHT_TO_LEFT; 220 } else { 221 dir = (lastRotateLen >= 0) ? DragEvent::DIRECTION_TOP_TO_BOTTOM : DragEvent::DIRECTION_BOTTOM_TO_TOP; 222 } 223 if (direction_ == HORIZONTAL) { 224 RefreshCurrentViewByThrow(lastRotateLen, dir, &UIView::GetX, &UIView::GetWidthWithMargin); 225 } else { 226 RefreshCurrentViewByThrow(lastRotateLen, dir, &UIView::GetY, &UIView::GetHeightWithMargin); 227 } 228 if (curView_ == nullptr) { 229 return UIView::OnRotateEndEvent(event); 230 } 231 SwitchToPage(curIndex_); 232 isRotating_ = false; 233 return UIView::OnRotateEndEvent(event); 234} 235#endif 236 237UIView* UISwipeView::GetViewByIndex(uint16_t index) const 238{ 239 UIView* child = childrenHead_; 240 while (child != nullptr) { 241 if (child->GetViewIndex() == index) { 242 return child; 243 } 244 child = child->GetNextSibling(); 245 } 246 return nullptr; 247} 248 249void UISwipeView::SetAnimatorTime(uint16_t time) 250{ 251 tickTime_ = time / DEFAULT_TASK_PERIOD; 252 if (tickTime_ == 0) { 253 tickTime_ = 1; 254 } 255 animatorCallback_.SetDragTimes(tickTime_); 256} 257 258void UISwipeView::SwitchToPage(int16_t dst, bool needAnimator) 259{ 260 if (IsNeedLoop()) { 261 dst = (dst + childrenNum_) % childrenNum_; 262 } else if (dst < 0) { 263 dst = 0; 264 } else if (dst >= childrenNum_) { 265 dst = childrenNum_ - 1; 266 } 267 268 UIView* dstView = GetViewByIndex(dst); 269 if (dstView == nullptr) { 270 return; 271 } 272 curIndex_ = dst; 273 curView_ = dstView; 274 int16_t xOffset = 0; 275 int16_t yOffset = 0; 276 277 if (direction_ == HORIZONTAL) { 278 if (alignMode_ == ALIGN_LEFT) { 279 xOffset = -dstView->GetX(); 280 } else if (alignMode_ == ALIGN_RIGHT) { 281 xOffset = GetWidth() - (dstView->GetX() + dstView->GetWidthWithMargin()); 282 } else { 283 xOffset = (GetWidth() >> 1) - (dstView->GetX() + (dstView->GetWidthWithMargin() >> 1)); 284 } 285 } else { 286 yOffset = (GetHeight() >> 1) - (dstView->GetY() + (dstView->GetHeightWithMargin() >> 1)); 287 } 288 289 if ((xOffset != 0) || (yOffset != 0)) { 290 if (scrollAnimator_.GetState() != Animator::STOP) { 291 scrollAnimator_.Stop(); 292 } 293 if (needAnimator) { 294 animatorCallback_.SetDragTimes(tickTime_); 295 animatorCallback_.SetDragStartValue(0, 0); 296 animatorCallback_.SetDragEndValue(xOffset, yOffset); 297 scrollAnimator_.Start(); 298 } else { 299 MoveChildByOffset(xOffset, yOffset); 300 } 301 } 302} 303 304void UISwipeView::StopAnimator() 305{ 306 UIAbstractScroll::StopAnimator(); 307 if (swipeListener_ != nullptr) { 308 swipeListener_->OnSwipe(*this); 309 } 310} 311 312void UISwipeView::SortChild() 313{ 314 if (childrenHead_ == nullptr) { 315 return; 316 } 317 int16_t index = 0; 318 UIView* pre = childrenHead_; 319 UIView* next = childrenHead_->GetNextSibling(); 320 if (direction_ == HORIZONTAL) { 321 pre->SetX(0); 322 } else { 323 pre->SetY(0); 324 } 325 pre->SetViewIndex(index); 326 index++; 327 328 while (next != nullptr) { 329 if (direction_ == HORIZONTAL) { 330 next->SetX(pre->GetRelativeRect().GetRight() + pre->GetStyle(STYLE_MARGIN_RIGHT) + 1); 331 } else { 332 next->SetY(pre->GetRelativeRect().GetBottom() + pre->GetStyle(STYLE_MARGIN_BOTTOM) + 1); 333 } 334 pre = next; 335 next->SetViewIndex(index); 336 next = next->GetNextSibling(); 337 index++; 338 } 339 bool tmpLoop = loop_; 340 loop_ = false; 341 SwitchToPage(curIndex_, false); 342 loop_ = tmpLoop; 343} 344 345void UISwipeView::RefreshCurrentViewByPosition(int16_t (UIView::*pfnGetXOrY)() const, 346 int16_t (UIView::*pfnGetWidthOrHeight)()) 347{ 348 if (childrenHead_ == nullptr) { 349 curIndex_ = 0; 350 curView_ = nullptr; 351 return; 352 } 353 354#if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR 355 uint16_t lastIndex = curIndex_; 356#endif 357 curIndex_ = 0; 358 curView_ = nullptr; 359 360 /* 361 * It needs to be modified that swipemid should be calculated by the width and height of the current 362 * sub view itself, not the width and height of the parent, especially for ALIGN_LEFT and ALIGN_RIGHT. 363 */ 364 uint16_t swipeMid; 365 if (alignMode_ == ALIGN_LEFT) { 366 swipeMid = 0; 367 } else if (alignMode_ == ALIGN_RIGHT) { 368 swipeMid = (this->*pfnGetWidthOrHeight)(); 369 } else { 370 swipeMid = (this->*pfnGetWidthOrHeight)() >> 1; 371 } 372 UIView* view = childrenHead_; 373 374 if ((childrenHead_->*pfnGetXOrY)() > swipeMid) { 375 curIndex_ = childrenHead_->GetViewIndex(); 376 curView_ = childrenHead_; 377 } else if ((childrenTail_->*pfnGetXOrY)() + (childrenHead_->*pfnGetWidthOrHeight)() < swipeMid) { 378 curIndex_ = childrenTail_->GetViewIndex(); 379 curView_ = childrenTail_; 380 } else { 381 while (view != nullptr) { 382 if ((swipeMid >= (view->*pfnGetXOrY)()) && 383 (swipeMid <= (view->*pfnGetXOrY)() + (view->*pfnGetWidthOrHeight)())) { 384 curIndex_ = view->GetViewIndex(); 385 curView_ = view; 386 break; 387 } 388 view = view->GetNextSibling(); 389 } 390 } 391#if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR 392 if (lastIndex != curIndex_) { 393 Vibrator(); 394 } 395#endif 396} 397 398void UISwipeView::RefreshCurrentViewByThrow(int16_t distance, 399 uint8_t dragDirection, 400 int16_t (UIView::*pfnGetXOrY)() const, 401 int16_t (UIView::*pfnGetWidthOrHeight)()) 402{ 403 if (curView_ == nullptr) { 404 return; 405 } 406#if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR 407 uint16_t lastIndex = curIndex_; 408#endif 409 410 /* 411 * It needs to be modified that swipemid should be calculated by the width and height of the current 412 * sub view itself, not the width and height of the parent, especially for ALIGN_LEFT and ALIGN_RIGHT. 413 */ 414 uint16_t swipeMid; 415 if (alignMode_ == ALIGN_LEFT) { 416 swipeMid = 0; 417 } else if (alignMode_ == ALIGN_RIGHT) { 418 swipeMid = (this->*pfnGetWidthOrHeight)(); 419 } else { 420 swipeMid = (this->*pfnGetWidthOrHeight)() >> 1; 421 } 422 423 int16_t accelerationOffset = GetMaxDelta() * GetSwipeACCLevel() / DRAG_ACC_FACTOR; 424 if (distance < 0) { 425 /* 426 * 7, 10 : Check whether the current view is dragged by more than 1/5, 427 * that is, the x or y coordinate plus 7/10 width or height. 428 */ 429 if (((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() >> 1) < swipeMid) && 430 ((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() * 7 / 10) - accelerationOffset < 431 swipeMid)) { 432 CurrentIndexInc(); 433 } 434 } else if (distance > 0) { 435 /* 436 * 3, 10 : Check whether the current view is dragged by more than 1/5, 437 * that is, the x or y coordinate plus 3/10 width or height. 438 */ 439 if (((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() >> 1) > swipeMid) && 440 ((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() * 3 / 10) + accelerationOffset > 441 swipeMid)) { 442 CurrentIndexDec(); 443 } 444 } else { 445 if (alignMode_ == ALIGN_LEFT) { 446 if (((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() >> 1) < swipeMid)) { 447 CurrentIndexInc(); 448 } 449 } else if (alignMode_ == ALIGN_RIGHT) { 450 if ((curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() >> 1) > swipeMid) { 451 CurrentIndexDec(); 452 } 453 } else { 454 /* 455 * If the absolute value of the offset is greater than the page turning threshold, 456 * page turning is considered. 457 */ 458 int16_t offset = (curView_->*pfnGetXOrY)() + ((curView_->*pfnGetWidthOrHeight)() >> 1) - swipeMid; 459 int16_t threshold = (this->*pfnGetWidthOrHeight)() >> 2; // 2: 1/4 width or height 460 if (offset > threshold && (dragDirection == DragEvent::DIRECTION_TOP_TO_BOTTOM || 461 dragDirection == DragEvent::DIRECTION_LEFT_TO_RIGHT)) { 462 CurrentIndexDec(); 463 } else if ((offset < -threshold) && (dragDirection == DragEvent::DIRECTION_BOTTOM_TO_TOP || 464 dragDirection == DragEvent::DIRECTION_RIGHT_TO_LEFT)) { 465 CurrentIndexInc(); 466 } 467 } 468 } 469 curView_ = GetViewByIndex(curIndex_); 470#if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR 471 if (lastIndex != curIndex_) { 472 Vibrator(); 473 } 474#endif 475} 476 477void UISwipeView::MoveChildByOffset(int16_t xOffset, int16_t yOffset) 478{ 479 UIViewGroup::MoveChildByOffset(xOffset, yOffset); 480 MoveHeadOrTailChild(); 481} 482 483bool UISwipeView::IsNeedLoop() 484{ 485 if (!loop_ || (childrenHead_ == nullptr) || (childrenTail_ == nullptr)) { 486 return false; 487 } 488 Rect childRect = GetAllChildRelativeRect(); 489 if (direction_ == HORIZONTAL) { 490 if ((childRect.GetWidth() - childrenHead_->GetWidth() >= GetWidth()) && 491 (childRect.GetWidth() - childrenTail_->GetWidth() >= GetWidth())) { 492 return true; 493 } 494 } else { 495 if ((childRect.GetHeight() - childrenHead_->GetHeight() >= GetHeight()) && 496 (childRect.GetHeight() - childrenTail_->GetHeight() >= GetHeight())) { 497 return true; 498 } 499 } 500 return false; 501} 502 503void UISwipeView::MoveFirstChildToLast() 504{ 505 if ((childrenTail_ == nullptr) || (childrenHead_ == nullptr)) { 506 return; 507 } 508 if (direction_ == HORIZONTAL) { 509 childrenHead_->SetX(childrenTail_->GetX() + childrenTail_->GetWidth()); 510 } else { 511 childrenHead_->SetY(childrenTail_->GetY() + childrenTail_->GetHeight()); 512 } 513 UIView* head = childrenHead_; 514 UIViewGroup::Remove(childrenHead_); 515 UIViewGroup::Add(head); 516} 517 518void UISwipeView::MoveLastChildToFirst() 519{ 520 if ((childrenTail_ == nullptr) || (childrenHead_ == nullptr)) { 521 return; 522 } 523 if (direction_ == HORIZONTAL) { 524 childrenTail_->SetX(childrenHead_->GetX() - childrenTail_->GetWidth()); 525 } else { 526 childrenTail_->SetY(childrenHead_->GetY() - childrenTail_->GetHeight()); 527 } 528 UIView* last = childrenTail_; 529 UIViewGroup::Remove(childrenTail_); 530 UIViewGroup::Insert(nullptr, last); 531} 532 533void UISwipeView::CalculateInvalidate() 534{ 535 Rect swipeRect(0, 0, GetRelativeRect().GetWidth() - 1, GetRelativeRect().GetHeight() - 1); 536 UIView* view = childrenHead_; 537 bool isFound = false; 538 while (view != nullptr) { 539 Rect rect = view->GetRelativeRect(); 540 if (rect.IsIntersect(swipeRect)) { 541 if (view->IsVisible() && (view->GetOpaScale() != OPA_TRANSPARENT)) { 542 view->Invalidate(); 543 } 544 isFound = true; 545 } else if (isFound) { 546 return; 547 } 548 549 view = view->GetNextSibling(); 550 } 551} 552 553void UISwipeView::CurrentIndexInc() 554{ 555 curIndex_++; 556 if (curIndex_ > childrenNum_ - 1) { 557 if (IsNeedLoop()) { 558 curIndex_ = curIndex_ % childrenNum_; 559 } else { 560 curIndex_ = childrenNum_ - 1; 561 } 562 } 563} 564 565void UISwipeView::CurrentIndexDec() 566{ 567 if (curIndex_ == 0) { 568 if (IsNeedLoop()) { 569 curIndex_ = childrenNum_ - 1; 570 } 571 } else { 572 curIndex_--; 573 } 574} 575 576#if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR 577void UISwipeView::Vibrator() 578{ 579 VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc(); 580 if (vibratorFunc != nullptr && isRotating_) { 581 if (!loop_ && (curIndex_ == 0 || curIndex_ == childrenNum_ - 1)) { 582 GRAPHIC_LOGI("UISwipeView::Vibrator calls TYPE_THREE vibrator"); 583 vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE); 584 } else { 585 GRAPHIC_LOGI("UISwipeView::Vibrator calls TYPE_ONE vibrator"); 586 vibratorFunc(VibratorType::VIBRATOR_TYPE_ONE); 587 } 588 } 589} 590#endif 591} // namespace OHOS 592