1 /**************************************************************************** 2 Copyright (c) 2011-2012 cocos2d-x.org 3 Copyright (c) 2013-2014 Chukong Technologies Inc. 4 5 http://www.cocos2d-x.org 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in 15 all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 THE SOFTWARE. 24 ****************************************************************************/ 25 26 /** 27 * The ScrollView control of Cocos UI 28 * @class 29 * @extends ccui.Layout 30 * 31 * @property {Number} innerWidth - Inner container width of the scroll view 32 * @property {Number} innerHeight - Inner container height of the scroll view 33 * @property {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} direction - Scroll direction of the scroll view 34 * @property {Boolean} bounceEnabled - Indicate whether bounce is enabled 35 * @property {Boolean} inertiaScrollEnabled - Indicate whether inertiaScroll is enabled 36 * @property {Number} touchTotalTimeThreshold - Touch total time threshold 37 */ 38 ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ 39 _innerContainer: null, 40 _direction: null, 41 42 _topBoundary: 0, 43 _bottomBoundary: 0, 44 _leftBoundary: 0, 45 _rightBoundary: 0, 46 47 _touchMoveDisplacements: null, 48 _touchMoveTimeDeltas: null, 49 _touchMovePreviousTimestamp: 0, 50 _touchTotalTimeThreshold : 0.5, 51 52 _autoScrolling: false, 53 _autoScrollTargetDelta: null, 54 _autoScrollAttenuate: true, 55 _autoScrollStartPosition : null, 56 _autoScrollTotalTime: 0, 57 _autoScrollAccumulatedTime: 0, 58 _autoScrollCurrentlyOutOfBoundary: false, 59 _autoScrollBraking: false, 60 _autoScrollBrakingStartPosition: null, 61 62 _bePressed: false, 63 64 _childFocusCancelOffset: 0, 65 66 bounceEnabled: false, 67 68 _outOfBoundaryAmount: null, 69 _outOfBoundaryAmountDirty: true, 70 71 inertiaScrollEnabled: false, 72 73 _scrollBarEnabled: true, 74 _verticalScrollBar: null, 75 _horizontalScrollBar: null, 76 77 _scrollViewEventListener: null, 78 _scrollViewEventSelector: null, 79 _className: "ScrollView", 80 81 /** 82 * Allocates and initializes a UIScrollView. 83 * Constructor of ccui.ScrollView. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 84 * @example 85 * // example 86 * var uiScrollView = new ccui.ScrollView(); 87 */ 88 ctor: function () { 89 ccui.Layout.prototype.ctor.call(this); 90 this.setClippingEnabled(true); 91 this._innerContainer.setTouchEnabled(false); 92 93 this._direction = ccui.ScrollView.DIR_NONE; 94 95 this._childFocusCancelOffset = 5; 96 this.inertiaScrollEnabled = true; 97 98 this._outOfBoundaryAmount = cc.p(0, 0); 99 this._autoScrollTargetDelta = cc.p(0, 0); 100 this._autoScrollStartPosition = cc.p(0, 0); 101 this._autoScrollBrakingStartPosition = cc.p(0, 0); 102 this._touchMoveDisplacements = []; 103 this._touchMoveTimeDeltas = []; 104 this._touchMovePreviousTimestamp = 0; 105 106 this._scrollBarEnabled = true; 107 this._initScrollBar(); 108 109 this.setTouchEnabled(true); 110 }, 111 112 /** 113 * Initializes a ccui.ScrollView. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. 114 * @returns {boolean} 115 */ 116 init: function () { 117 if (ccui.Layout.prototype.init.call(this)) { 118 119 120 return true; 121 } 122 return false; 123 }, 124 125 /** 126 * Calls the parent class' onEnter and schedules update function. 127 * @override 128 */ 129 onEnter: function () { 130 ccui.Layout.prototype.onEnter.call(this); 131 this.scheduleUpdate(); 132 }, 133 134 onExit: function () { 135 cc.renderer._removeCache(this.__instanceId); 136 ccui.Layout.prototype.onExit.call(this); 137 }, 138 139 /** 140 * When a widget is in a layout, you could call this method to get the next focused widget within a specified _direction. <br/> 141 * If the widget is not in a layout, it will return itself 142 * 143 * @param {Number} _direction the _direction to look for the next focused widget in a layout 144 * @param {ccui.Widget} current the current focused widget 145 * @returns {ccui.Widget} 146 */ 147 findNextFocusedWidget: function(direction, current){ 148 if (this.getLayoutType() === ccui.Layout.LINEAR_VERTICAL 149 || this.getLayoutType() === ccui.Layout.LINEAR_HORIZONTAL) { 150 return this._innerContainer.findNextFocusedWidget(direction, current); 151 } else 152 return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, current); 153 }, 154 155 _initRenderer: function () { 156 ccui.Layout.prototype._initRenderer.call(this); 157 158 this._innerContainer = new ccui.Layout(); 159 this._innerContainer.setColor(cc.color(255,255,255)); 160 this._innerContainer.setOpacity(255); 161 this._innerContainer.setCascadeColorEnabled(true); 162 this._innerContainer.setCascadeOpacityEnabled(true); 163 164 this.addProtectedChild(this._innerContainer, 1, 1); 165 }, 166 167 _createRenderCmd: function(){ 168 if(cc._renderType === cc.game.RENDER_TYPE_WEBGL) 169 return new ccui.ScrollView.WebGLRenderCmd(this); 170 else 171 return new ccui.ScrollView.CanvasRenderCmd(this); 172 }, 173 174 _onSizeChanged: function () { 175 ccui.Layout.prototype._onSizeChanged.call(this); 176 var locSize = this._contentSize; 177 this._topBoundary = locSize.height; 178 this._rightBoundary = locSize.width; 179 var innerSize = this._innerContainer.getContentSize(); 180 this._innerContainer.setContentSize(cc.size(Math.max(innerSize.width, locSize.width), Math.max(innerSize.height, locSize.height))); 181 this._innerContainer.setPosition(0, locSize.height - this._innerContainer.getContentSize().height); 182 183 if(this._verticalScrollBar) 184 this._verticalScrollBar.onScrolled(this._getHowMuchOutOfBoundary()); 185 186 if(this._horizontalScrollBar) 187 this._horizontalScrollBar.onScrolled(this._getHowMuchOutOfBoundary()); 188 }, 189 190 /** 191 * Changes inner container size of ScrollView. <br/> 192 * Inner container size must be larger than or equal the size of ScrollView. 193 * @param {cc.Size} size inner container size. 194 */ 195 setInnerContainerSize: function (size) { 196 var innerContainer = this._innerContainer, 197 locSize = this._contentSize, 198 innerSizeWidth = locSize.width, innerSizeHeight = locSize.height; 199 200 if (size.width < locSize.width) 201 cc.log("Inner width <= ScrollView width, it will be force sized!"); 202 else 203 innerSizeWidth = size.width; 204 205 if (size.height < locSize.height) 206 cc.log("Inner height <= ScrollView height, it will be force sized!"); 207 else 208 innerSizeHeight = size.height; 209 210 innerContainer.setContentSize(cc.size(innerSizeWidth, innerSizeHeight)); 211 212 var pos = this._innerContainer.getPosition(); 213 var contAP = this._innerContainer.getAnchorPoint(); 214 215 if (this._innerContainer.getLeftBoundary() != 0.0) 216 { 217 pos.x = contAP.x * innerSizeWidth; 218 } 219 if (this._innerContainer.getTopBoundary() != this._contentSize.height) 220 { 221 pos.y = this._contentSize.height - (1.0 - contAP.y) * innerSizeHeight; 222 } 223 this.setInnerContainerPosition(pos); 224 225 this._updateScrollBar(cc.p(0 ,0)); 226 }, 227 228 _setInnerWidth: function (width) { 229 var locW = this._contentSize.width, 230 innerWidth = locW, 231 container = this._innerContainer, 232 oldInnerWidth = container.width; 233 if (width < locW) 234 cc.log("Inner width <= scrollview width, it will be force sized!"); 235 else 236 innerWidth = width; 237 container.width = innerWidth; 238 239 switch (this._direction) { 240 case ccui.ScrollView.DIR_HORIZONTAL: 241 case ccui.ScrollView.DIR_BOTH: 242 if (container.getRightBoundary() <= locW) { 243 var newInnerWidth = container.width; 244 var offset = oldInnerWidth - newInnerWidth; 245 this._scrollChildren(offset, 0); 246 } 247 break; 248 } 249 var innerAX = container.anchorX; 250 if (container.getLeftBoundary() > 0.0) 251 container.x = innerAX * innerWidth; 252 if (container.getRightBoundary() < locW) 253 container.x = locW - ((1.0 - innerAX) * innerWidth); 254 }, 255 256 _setInnerHeight: function (height) { 257 var locH = this._contentSize.height, 258 innerHeight = locH, 259 container = this._innerContainer, 260 oldInnerHeight = container.height; 261 if (height < locH) 262 cc.log("Inner height <= scrollview height, it will be force sized!"); 263 else 264 innerHeight = height; 265 container.height = innerHeight; 266 267 switch (this._direction) { 268 case ccui.ScrollView.DIR_VERTICAL: 269 case ccui.ScrollView.DIR_BOTH: 270 var newInnerHeight = innerHeight; 271 var offset = oldInnerHeight - newInnerHeight; 272 this._scrollChildren(0, offset); 273 break; 274 } 275 var innerAY = container.anchorY; 276 if (container.getLeftBoundary() > 0.0) 277 container.y = innerAY * innerHeight; 278 if (container.getRightBoundary() < locH) 279 container.y = locH - ((1.0 - innerAY) * innerHeight); 280 }, 281 /** 282 * Set inner container position 283 * 284 * @param {cc.Point} position Inner container position. 285 */ 286 setInnerContainerPosition: function(position) 287 { 288 if(position.x === this._innerContainer.getPositionX() && position.y === this._innerContainer.getPositionY()) 289 { 290 return; 291 } 292 this._innerContainer.setPosition(position); 293 this._outOfBoundaryAmountDirty = true; 294 295 // Process bouncing events 296 if(this.bounceEnabled) 297 { 298 for(var _direction = ccui.ScrollView.MOVEDIR_TOP; _direction < ccui.ScrollView.MOVEDIR_RIGHT; ++_direction) 299 { 300 if(this._isOutOfBoundary(_direction)) 301 { 302 this._processScrollEvent(_direction, true); 303 } 304 } 305 } 306 307 this._dispatchEvent(ccui.ScrollView.EVENT_CONTAINER_MOVED); 308 }, 309 310 /** 311 * Get inner container position 312 * 313 * @return The inner container position. 314 */ 315 getInnerContainerPosition: function() 316 { 317 return this._innerContainer.getPosition(); 318 }, 319 320 /** 321 * Returns inner container size of ScrollView. <br/> 322 * Inner container size must be larger than or equal ScrollView's size. 323 * 324 * @return {cc.Size} inner container size. 325 */ 326 getInnerContainerSize: function () { 327 return this._innerContainer.getContentSize(); 328 }, 329 _getInnerWidth: function () { 330 return this._innerContainer.width; 331 }, 332 _getInnerHeight: function () { 333 return this._innerContainer.height; 334 }, 335 336 _isInContainer: function (widget) { 337 if(!this._clippingEnabled) 338 return true; 339 var wPos = widget._position, 340 wSize = widget._contentSize, 341 wAnchor = widget._anchorPoint, 342 size = this._customSize, 343 pos = this._innerContainer._position, 344 bottom = 0, left = 0; 345 if ( 346 // Top 347 (bottom = wPos.y - wAnchor.y * wSize.height) >= size.height - pos.y || 348 // Bottom 349 bottom + wSize.height <= -pos.y || 350 // right 351 (left = wPos.x - wAnchor.x * wSize.width) >= size.width - pos.x || 352 // left 353 left + wSize.width <= -pos.x 354 ) 355 return false; 356 else return true; 357 }, 358 359 updateChildren: function () { 360 var child, i, l; 361 var childrenArray = this._innerContainer._children; 362 for(i = 0, l = childrenArray.length; i < l; i++) { 363 child = childrenArray[i]; 364 if(child._inViewRect === true && this._isInContainer(child) === false) 365 child._inViewRect = false; 366 else if (child._inViewRect === false && this._isInContainer(child) === true) 367 child._inViewRect = true; 368 } 369 }, 370 /** 371 * Add child to ccui.ScrollView. 372 * @param {cc.Node} widget 373 * @param {Number} [zOrder] 374 * @param {Number|string} [tag] tag or name 375 * @returns {boolean} 376 */ 377 addChild: function (widget, zOrder, tag) { 378 if(!widget) 379 return false; 380 if(this._isInContainer(widget) === false) 381 widget._inViewRect = false; 382 zOrder = zOrder || widget.getLocalZOrder(); 383 tag = tag || widget.getTag(); 384 return this._innerContainer.addChild(widget, zOrder, tag); 385 }, 386 387 /** 388 * Removes all children. 389 */ 390 removeAllChildren: function () { 391 this.removeAllChildrenWithCleanup(true); 392 }, 393 394 /** 395 * Removes all children. 396 * @param {Boolean} cleanup 397 */ 398 removeAllChildrenWithCleanup: function(cleanup){ 399 this._innerContainer.removeAllChildrenWithCleanup(cleanup); 400 }, 401 402 /** 403 * Removes widget child 404 * @override 405 * @param {ccui.Widget} child 406 * @param {Boolean} cleanup 407 * @returns {boolean} 408 */ 409 removeChild: function (child, cleanup) { 410 return this._innerContainer.removeChild(child, cleanup); 411 }, 412 413 /** 414 * Returns inner container's children 415 * @returns {Array} 416 */ 417 getChildren: function () { 418 return this._innerContainer.getChildren(); 419 }, 420 421 /** 422 * Gets the count of inner container's children 423 * @returns {Number} 424 */ 425 getChildrenCount: function () { 426 return this._innerContainer.getChildrenCount(); 427 }, 428 429 /** 430 * Gets a child from the container given its tag 431 * @param {Number} tag 432 * @returns {ccui.Widget} 433 */ 434 getChildByTag: function (tag) { 435 return this._innerContainer.getChildByTag(tag); 436 }, 437 438 /** 439 * Gets a child from the container given its name 440 * @param {String} name 441 * @returns {ccui.Widget} 442 */ 443 getChildByName: function (name) { 444 return this._innerContainer.getChildByName(name); 445 }, 446 447 _flattenVectorByDirection: function(vector) 448 { 449 var result = cc.p(0 ,0); 450 result.x = (this._direction === ccui.ScrollView.DIR_VERTICAL ? 0 : vector.x); 451 result.y = (this._direction === ccui.ScrollView.DIR_HORIZONTAL ? 0 : vector.y); 452 return result; 453 }, 454 455 _getHowMuchOutOfBoundary: function(addition) 456 { 457 if(addition === undefined) 458 addition = cc.p(0, 0); 459 460 if(addition.x === 0 && addition.y === 0 && !this._outOfBoundaryAmountDirty) 461 { 462 return this._outOfBoundaryAmount; 463 } 464 465 var outOfBoundaryAmount = cc.p(0, 0); 466 467 if(this._innerContainer.getLeftBoundary() + addition.x > this._leftBoundary) 468 { 469 outOfBoundaryAmount.x = this._leftBoundary - (this._innerContainer.getLeftBoundary() + addition.x); 470 } 471 else if(this._innerContainer.getRightBoundary() + addition.x < this._rightBoundary) 472 { 473 outOfBoundaryAmount.x = this._rightBoundary - (this._innerContainer.getRightBoundary() + addition.x); 474 } 475 476 if(this._innerContainer.getTopBoundary() + addition.y < this._topBoundary) 477 { 478 outOfBoundaryAmount.y = this._topBoundary - (this._innerContainer.getTopBoundary() + addition.y); 479 } 480 else if(this._innerContainer.getBottomBoundary() + addition.y > this._bottomBoundary) 481 { 482 outOfBoundaryAmount.y = this._bottomBoundary - (this._innerContainer.getBottomBoundary() + addition.y); 483 } 484 485 if(addition.x === 0 && addition.y === 0 ) 486 { 487 this._outOfBoundaryAmount = outOfBoundaryAmount; 488 this._outOfBoundaryAmountDirty = false; 489 } 490 return outOfBoundaryAmount; 491 }, 492 493 _isOutOfBoundary: function(dir) 494 { 495 var outOfBoundary = this._getHowMuchOutOfBoundary(); 496 if(dir !== undefined) 497 { 498 switch (dir) 499 { 500 case ccui.ScrollView.MOVEDIR_TOP: 501 return outOfBoundary.y > 0; 502 case ccui.ScrollView.MOVEDIR_BOTTOM: 503 return outOfBoundary.y < 0; 504 case ccui.ScrollView.MOVEDIR_LEFT: 505 return outOfBoundary.x < 0; 506 case ccui.ScrollView.MOVEDIR_RIGHT: 507 return outOfBoundary.x > 0; 508 } 509 } 510 else 511 { 512 return !this._fltEqualZero(outOfBoundary); 513 } 514 515 return false; 516 }, 517 518 519 _moveInnerContainer: function(deltaMove, canStartBounceBack) 520 { 521 var adjustedMove = this._flattenVectorByDirection(deltaMove); 522 523 this.setInnerContainerPosition(cc.pAdd(this.getInnerContainerPosition(), adjustedMove)); 524 525 var outOfBoundary =this._getHowMuchOutOfBoundary(); 526 this._updateScrollBar(outOfBoundary); 527 528 if(this.bounceEnabled && canStartBounceBack) 529 { 530 this._startBounceBackIfNeeded(); 531 } 532 }, 533 534 _updateScrollBar: function(outOfBoundary) 535 { 536 if(this._verticalScrollBar) 537 { 538 this._verticalScrollBar.onScrolled(outOfBoundary); 539 } 540 if(this._horizontalScrollBar) 541 { 542 this._horizontalScrollBar.onScrolled(outOfBoundary); 543 } 544 }, 545 546 _calculateTouchMoveVelocity: function() 547 { 548 var totalTime = 0; 549 for(var i = 0; i < this._touchMoveTimeDeltas.length; ++i) 550 { 551 totalTime += this._touchMoveTimeDeltas[i]; 552 } 553 if(totalTime == 0 || totalTime >= this._touchTotalTimeThreshold) 554 { 555 return cc.p(0, 0); 556 } 557 558 var totalMovement = cc.p(0 ,0); 559 560 for(var i = 0; i < this._touchMoveDisplacements.length; ++i) 561 { 562 totalMovement.x += this._touchMoveDisplacements[i].x; 563 totalMovement.y += this._touchMoveDisplacements[i].y; 564 } 565 566 return cc.pMult(totalMovement, 1 / totalTime); 567 }, 568 569 /** 570 * Set the touch total time threshold 571 * @param {Number} touchTotalTimeThreshold 572 */ 573 setTouchTotalTimeThreshold: function(touchTotalTimeThreshold) 574 { 575 this._touchTotalTimeThreshold = touchTotalTimeThreshold; 576 }, 577 578 579 /** 580 * Get the touch total time threshold 581 * @returns {Number} 582 */ 583 getTouchTotalTimeThreshold: function() 584 { 585 return this._touchTotalTimeThreshold; 586 }, 587 588 _startInertiaScroll: function(touchMoveVelocity) 589 { 590 var MOVEMENT_FACTOR = 0.7; 591 var inertiaTotalMovement = cc.pMult(touchMoveVelocity, MOVEMENT_FACTOR); 592 this._startAttenuatingAutoScroll(inertiaTotalMovement, touchMoveVelocity); 593 }, 594 595 _startBounceBackIfNeeded: function() 596 { 597 if (!this.bounceEnabled) 598 { 599 return false; 600 } 601 var bounceBackAmount = this._getHowMuchOutOfBoundary(); 602 if(this._fltEqualZero(bounceBackAmount)) 603 { 604 return false; 605 } 606 607 var BOUNCE_BACK_DURATION = 1.0; 608 this._startAutoScroll(bounceBackAmount, BOUNCE_BACK_DURATION, true); 609 return true; 610 }, 611 612 _startAutoScrollToDestination: function(destination, timeInSec, attenuated) 613 { 614 this._startAutoScroll(cc.pSub(destination , this._innerContainer.getPosition()), timeInSec, attenuated); 615 }, 616 617 _calculateAutoScrollTimeByInitialSpeed: function(initialSpeed) 618 { 619 // Calculate the time from the initial speed according to quintic polynomial. 620 return Math.sqrt(Math.sqrt(initialSpeed / 5)); 621 }, 622 623 _startAttenuatingAutoScroll: function(deltaMove, initialVelocity) 624 { 625 var time = this._calculateAutoScrollTimeByInitialSpeed(cc.pLength(initialVelocity)); 626 this._startAutoScroll(deltaMove, time, true); 627 }, 628 629 _startAutoScroll: function(deltaMove, timeInSec, attenuated) 630 { 631 var adjustedDeltaMove = this._flattenVectorByDirection(deltaMove); 632 633 this._autoScrolling = true; 634 this._autoScrollTargetDelta = adjustedDeltaMove; 635 this._autoScrollAttenuate = attenuated; 636 this._autoScrollStartPosition = this._innerContainer.getPosition(); 637 this._autoScrollTotalTime = timeInSec; 638 this._autoScrollAccumulatedTime = 0; 639 this._autoScrollBraking = false; 640 this._autoScrollBrakingStartPosition = cc.p(0,0 ); 641 642 // If the destination is also out of boundary of same side, start brake from beggining. 643 var currentOutOfBoundary = this._getHowMuchOutOfBoundary(); 644 if(!this._fltEqualZero(currentOutOfBoundary)) 645 { 646 this._autoScrollCurrentlyOutOfBoundary = true; 647 var afterOutOfBoundary = this._getHowMuchOutOfBoundary(adjustedDeltaMove); 648 if(currentOutOfBoundary.x * afterOutOfBoundary.x > 0 || currentOutOfBoundary.y * afterOutOfBoundary.y > 0) 649 { 650 this._autoScrollBraking = true; 651 } 652 } 653 }, 654 655 /** 656 * Immediately stops inner container scroll initiated by any of the "scrollTo*" member functions 657 */ 658 stopAutoScroll: function() 659 { 660 this._autoScrolling = false; 661 this._autoScrollAttenuate = true; 662 this._autoScrollTotalTime = 0; 663 this._autoScrollAccumulatedTime = 0; 664 }, 665 666 _isNecessaryAutoScrollBrake: function() 667 { 668 if(this._autoScrollBraking) 669 { 670 return true; 671 } 672 673 if(this._isOutOfBoundary()) 674 { 675 // It just went out of boundary. 676 if(!this._autoScrollCurrentlyOutOfBoundary) 677 { 678 this._autoScrollCurrentlyOutOfBoundary = true; 679 this._autoScrollBraking = true; 680 this._autoScrollBrakingStartPosition = this.getInnerContainerPosition(); 681 return true; 682 } 683 } 684 else 685 { 686 this._autoScrollCurrentlyOutOfBoundary = false; 687 } 688 return false; 689 }, 690 691 _getAutoScrollStopEpsilon: function() 692 { 693 return 0.0001; 694 }, 695 696 _fltEqualZero: function(point) 697 { 698 return (Math.abs(point.x) <= 0.0001 && Math.abs(point.y) <= 0.0001); 699 }, 700 701 _processAutoScrolling: function(deltaTime) 702 { 703 var OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05; 704 // Make auto scroll shorter if it needs to deaccelerate. 705 var brakingFactor = (this._isNecessaryAutoScrollBrake() ? OUT_OF_BOUNDARY_BREAKING_FACTOR : 1); 706 707 // Elapsed time 708 this._autoScrollAccumulatedTime += deltaTime * (1 / brakingFactor); 709 710 // Calculate the progress percentage 711 var percentage = Math.min(1, this._autoScrollAccumulatedTime / this._autoScrollTotalTime); 712 if(this._autoScrollAttenuate) 713 { 714 percentage -= 1; 715 percentage = percentage * percentage * percentage * percentage * percentage + 1; 716 } 717 718 // Calculate the new position 719 var newPosition = cc.pAdd(this._autoScrollStartPosition, cc.pMult(this._autoScrollTargetDelta,percentage)); 720 var reachedEnd = Math.abs(percentage - 1) <= this._getAutoScrollStopEpsilon(); 721 722 if(this.bounceEnabled) 723 { 724 // The new position is adjusted if out of boundary 725 newPosition = cc.pAdd(this._autoScrollBrakingStartPosition, cc.pMult(cc.pSub(newPosition, this._autoScrollBrakingStartPosition), brakingFactor)); 726 } 727 else 728 { 729 // Don't let go out of boundary 730 var moveDelta = cc.pSub(newPosition, this.getInnerContainerPosition()); 731 var outOfBoundary = this._getHowMuchOutOfBoundary(moveDelta); 732 if(!this._fltEqualZero(outOfBoundary)) 733 { 734 newPosition.x += outOfBoundary.x; 735 newPosition.y += outOfBoundary.y; 736 737 reachedEnd = true; 738 } 739 } 740 741 // Finish auto scroll if it ended 742 if(reachedEnd) 743 { 744 this._autoScrolling = false; 745 this._dispatchEvent(ccui.ScrollView.EVENT_AUTOSCROLL_ENDED); 746 } 747 748 this._moveInnerContainer(cc.pSub(newPosition, this.getInnerContainerPosition()), reachedEnd); 749 }, 750 751 _jumpToDestination: function (desOrX, y) 752 { 753 if(desOrX.x === undefined) 754 { 755 desOrX = cc.p(desOrX, y); 756 } 757 758 this._autoScrolling = false; 759 this._moveInnerContainer(cc.pSub(desOrX, this.getInnerContainerPosition()), true); 760 }, 761 762 _scrollChildren: function(deltaMove) 763 { 764 var realMove = deltaMove; 765 if(this.bounceEnabled) 766 { 767 // If the position of the inner container is out of the boundary, the offsets should be divided by two. 768 var outOfBoundary = this._getHowMuchOutOfBoundary(); 769 realMove.x *= (outOfBoundary.x == 0 ? 1 : 0.5); 770 realMove.y *= (outOfBoundary.y == 0 ? 1 : 0.5); 771 } 772 773 if(!this.bounceEnabled) 774 { 775 var outOfBoundary = this._getHowMuchOutOfBoundary(realMove); 776 realMove.x += outOfBoundary.x; 777 realMove.y += outOfBoundary.y; 778 } 779 780 var scrolledToLeft = false; 781 var scrolledToRight = false; 782 var scrolledToTop = false; 783 var scrolledToBottom = false; 784 785 if (realMove.y > 0.0) // up 786 { 787 var icBottomPos = this._innerContainer.getBottomBoundary(); 788 if (icBottomPos + realMove.y >= this._bottomBoundary) 789 { 790 scrolledToBottom = true; 791 } 792 } 793 else if (realMove.y < 0.0) // down 794 { 795 var icTopPos = this._innerContainer.getTopBoundary(); 796 if (icTopPos + realMove.y <= this._topBoundary) 797 { 798 scrolledToTop = true; 799 } 800 } 801 802 if (realMove.x < 0.0) // left 803 { 804 var icRightPos = this._innerContainer.getRightBoundary(); 805 if (icRightPos + realMove.x <= this._rightBoundary) 806 { 807 scrolledToRight = true; 808 } 809 } 810 else if (realMove.x > 0.0) // right 811 { 812 var icLeftPos = this._innerContainer.getLeftBoundary(); 813 if (icLeftPos + realMove.x >= this._leftBoundary) 814 { 815 scrolledToLeft = true; 816 } 817 } 818 this._moveInnerContainer(realMove, false); 819 820 if(realMove.x != 0 || realMove.y != 0) 821 { 822 this._processScrollingEvent(); 823 } 824 if(scrolledToBottom) 825 { 826 this._processScrollEvent(ccui.ScrollView.MOVEDIR_BOTTOM, false); 827 } 828 if(scrolledToTop) 829 { 830 this._processScrollEvent(ccui.ScrollView.MOVEDIR_TOP, false); 831 } 832 if(scrolledToLeft) 833 { 834 this._processScrollEvent(ccui.ScrollView.MOVEDIR_LEFT, false); 835 } 836 if(scrolledToRight) 837 { 838 this._processScrollEvent(ccui.ScrollView.MOVEDIR_RIGHT, false); 839 } 840 }, 841 842 /** 843 * Scroll inner container to bottom boundary of ScrollView. 844 * @param {Number} time 845 * @param {Boolean} attenuated 846 */ 847 scrollToBottom: function (time, attenuated) { 848 this._startAutoScrollToDestination(cc.p(this._innerContainer.getPositionX(), 0), time, attenuated); 849 }, 850 851 /** 852 * Scroll inner container to top boundary of ScrollView. 853 * @param {Number} time 854 * @param {Boolean} attenuated 855 */ 856 scrollToTop: function (time, attenuated) { 857 this._startAutoScrollToDestination( 858 cc.p(this._innerContainer.getPositionX(), this._contentSize.height - this._innerContainer.getContentSize().height), time, attenuated); 859 }, 860 861 /** 862 * Scroll inner container to left boundary of ScrollView. 863 * @param {Number} time 864 * @param {Boolean} attenuated 865 */ 866 scrollToLeft: function (time, attenuated) { 867 this._startAutoScrollToDestination(cc.p(0, this._innerContainer.getPositionY()), time, attenuated); 868 }, 869 870 /** 871 * Scroll inner container to right boundary of ScrollView. 872 * @param {Number} time 873 * @param {Boolean} attenuated 874 */ 875 scrollToRight: function (time, attenuated) { 876 this._startAutoScrollToDestination( 877 cc.p(this._contentSize.width - this._innerContainer.getContentSize().width, this._innerContainer.getPositionY()), time, attenuated); 878 }, 879 880 /** 881 * Scroll inner container to top and left boundary of ScrollView. 882 * @param {Number} time 883 * @param {Boolean} attenuated 884 */ 885 scrollToTopLeft: function (time, attenuated) { 886 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 887 cc.log("Scroll direction is not both!"); 888 return; 889 } 890 this._startAutoScrollToDestination(cc.p(0, this._contentSize.height - this._innerContainer.getContentSize().height), time, attenuated); 891 }, 892 893 /** 894 * Scroll inner container to top and right boundary of ScrollView. 895 * @param {Number} time 896 * @param {Boolean} attenuated 897 */ 898 scrollToTopRight: function (time, attenuated) { 899 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 900 cc.log("Scroll direction is not both!"); 901 return; 902 } 903 var inSize = this._innerContainer.getContentSize(); 904 this._startAutoScrollToDestination(cc.p(this._contentSize.width - inSize.width, 905 this._contentSize.height - inSize.height), time, attenuated); 906 }, 907 908 /** 909 * Scroll inner container to bottom and left boundary of ScrollView. 910 * @param {Number} time 911 * @param {Boolean} attenuated 912 */ 913 scrollToBottomLeft: function (time, attenuated) { 914 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 915 cc.log("Scroll direction is not both!"); 916 return; 917 } 918 this._startAutoScrollToDestination(cc.p(0, 0), time, attenuated); 919 }, 920 921 /** 922 * Scroll inner container to bottom and right boundary of ScrollView. 923 * @param {Number} time 924 * @param {Boolean} attenuated 925 */ 926 scrollToBottomRight: function (time, attenuated) { 927 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 928 cc.log("Scroll direction is not both!"); 929 return; 930 } 931 this._startAutoScrollToDestination(cc.p(this._contentSize.width - this._innerContainer.getContentSize().width, 0), time, attenuated); 932 }, 933 934 /** 935 * Scroll inner container to vertical percent position of ScrollView. 936 * @param {Number} percent 937 * @param {Number} time 938 * @param {Boolean} attenuated 939 */ 940 scrollToPercentVertical: function (percent, time, attenuated) { 941 var minY = this._contentSize.height - this._innerContainer.getContentSize().height; 942 var h = -minY; 943 this._startAutoScrollToDestination(cc.p(this._innerContainer.getPositionX(), minY + percent * h / 100), time, attenuated); 944 }, 945 946 /** 947 * Scroll inner container to horizontal percent position of ScrollView. 948 * @param {Number} percent 949 * @param {Number} time 950 * @param {Boolean} attenuated 951 */ 952 scrollToPercentHorizontal: function (percent, time, attenuated) { 953 var w = this._innerContainer.getContentSize().width - this._contentSize.width; 954 this._startAutoScrollToDestination(cc.p(-(percent * w / 100), this._innerContainer.getPositionY()), time, attenuated); 955 }, 956 957 /** 958 * Scroll inner container to both _direction percent position of ScrollView. 959 * @param {cc.Point} percent 960 * @param {Number} time 961 * @param {Boolean} attenuated 962 */ 963 scrollToPercentBothDirection: function (percent, time, attenuated) { 964 if (this._direction !== ccui.ScrollView.DIR_BOTH) 965 return; 966 var minY = this._contentSize.height - this._innerContainer.getContentSize().height; 967 var h = -minY; 968 var w = this._innerContainer.getContentSize().width - this._contentSize.width; 969 this._startAutoScrollToDestination(cc.p(-(percent.x * w / 100), minY + percent.y * h / 100), time, attenuated); 970 }, 971 972 /** 973 * Move inner container to bottom boundary of ScrollView. 974 */ 975 jumpToBottom: function () { 976 this._jumpToDestination(this._innerContainer.getPositionX(), 0); 977 }, 978 979 /** 980 * Move inner container to top boundary of ScrollView. 981 */ 982 jumpToTop: function () { 983 this._jumpToDestination(this._innerContainer.getPositionX(), this._contentSize.height - this._innerContainer.getContentSize().height); 984 }, 985 986 /** 987 * Move inner container to left boundary of ScrollView. 988 */ 989 jumpToLeft: function () { 990 this._jumpToDestination(0, this._innerContainer.getPositionY()); 991 }, 992 993 /** 994 * Move inner container to right boundary of ScrollView. 995 */ 996 jumpToRight: function () { 997 this._jumpToDestination(this._contentSize.width - this._innerContainer.getContentSize().width, this._innerContainer.getPositionY()); 998 }, 999 1000 /** 1001 * Move inner container to top and left boundary of ScrollView. 1002 */ 1003 jumpToTopLeft: function () { 1004 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 1005 cc.log("Scroll _direction is not both!"); 1006 return; 1007 } 1008 this._jumpToDestination(0, this._contentSize.height - this._innerContainer.getContentSize().height); 1009 }, 1010 1011 /** 1012 * Move inner container to top and right boundary of ScrollView. 1013 */ 1014 jumpToTopRight: function () { 1015 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 1016 cc.log("Scroll _direction is not both!"); 1017 return; 1018 } 1019 var inSize = this._innerContainer.getContentSize(); 1020 this._jumpToDestination(this._contentSize.width - inSize.width, this._contentSize.height - inSize.height); 1021 }, 1022 1023 /** 1024 * Move inner container to bottom and left boundary of ScrollView. 1025 */ 1026 jumpToBottomLeft: function () { 1027 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 1028 cc.log("Scroll _direction is not both!"); 1029 return; 1030 } 1031 this._jumpToDestination(0, 0); 1032 }, 1033 1034 /** 1035 * Move inner container to bottom and right boundary of ScrollView. 1036 */ 1037 jumpToBottomRight: function () { 1038 if (this._direction !== ccui.ScrollView.DIR_BOTH) { 1039 cc.log("Scroll _direction is not both!"); 1040 return; 1041 } 1042 this._jumpToDestination(this._contentSize.width - this._innerContainer.getContentSize().width, 0); 1043 }, 1044 1045 /** 1046 * Move inner container to vertical percent position of ScrollView. 1047 * @param {Number} percent The destination vertical percent, accept value between 0 - 100 1048 */ 1049 jumpToPercentVertical: function (percent) { 1050 var minY = this._contentSize.height - this._innerContainer.getContentSize().height; 1051 var h = -minY; 1052 this._jumpToDestination(this._innerContainer.getPositionX(), minY + percent * h / 100); 1053 }, 1054 1055 /** 1056 * Move inner container to horizontal percent position of ScrollView. 1057 * @param {Number} percent The destination vertical percent, accept value between 0 - 100 1058 */ 1059 jumpToPercentHorizontal: function (percent) { 1060 var w = this._innerContainer.getContentSize().width - this._contentSize.width; 1061 this._jumpToDestination(-(percent * w / 100), this._innerContainer.getPositionY()); 1062 }, 1063 1064 /** 1065 * Move inner container to both _direction percent position of ScrollView. 1066 * @param {cc.Point} percent The destination vertical percent, accept value between 0 - 100 1067 */ 1068 jumpToPercentBothDirection: function (percent) { 1069 if (this._direction !== ccui.ScrollView.DIR_BOTH) 1070 return; 1071 var inSize = this._innerContainer.getContentSize(); 1072 var minY = this._contentSize.height - inSize.height; 1073 var h = -minY; 1074 var w = inSize.width - this._contentSize.width; 1075 this._jumpToDestination(-(percent.x * w / 100), minY + percent.y * h / 100); 1076 }, 1077 1078 _gatherTouchMove: function(delta) 1079 { 1080 var NUMBER_OF_GATHERED_TOUCHES_FOR_MOVE_SPEED = 5; 1081 while(this._touchMoveDisplacements.length >= NUMBER_OF_GATHERED_TOUCHES_FOR_MOVE_SPEED) 1082 { 1083 this._touchMoveDisplacements.splice(0,1); 1084 this._touchMoveTimeDeltas.splice(0,1) 1085 } 1086 this._touchMoveDisplacements.push(delta); 1087 1088 var timestamp = (new Date()).getTime(); 1089 this._touchMoveTimeDeltas.push((timestamp - this._touchMovePreviousTimestamp) / 1000); 1090 this._touchMovePreviousTimestamp = timestamp; 1091 }, 1092 1093 _handlePressLogic: function (touch) { 1094 this._bePressed = true; 1095 this._autoScrolling = false; 1096 1097 // Clear gathered touch move information 1098 1099 this._touchMovePreviousTimestamp = (new Date()).getTime(); 1100 this._touchMoveDisplacements.length = 0; 1101 this._touchMoveTimeDeltas.length = 0; 1102 1103 1104 if(this._verticalScrollBar) 1105 { 1106 this._verticalScrollBar.onTouchBegan(); 1107 } 1108 if(this._horizontalScrollBar) 1109 { 1110 this._horizontalScrollBar.onTouchBegan(); 1111 } 1112 }, 1113 1114 _handleMoveLogic: function (touch) { 1115 var touchPositionInNodeSpace = this.convertToNodeSpace(touch.getLocation()), 1116 previousTouchPositionInNodeSpace = this.convertToNodeSpace(touch.getPreviousLocation()); 1117 var delta = cc.pSub(touchPositionInNodeSpace, previousTouchPositionInNodeSpace); 1118 1119 this._scrollChildren(delta); 1120 this._gatherTouchMove(delta); 1121 }, 1122 1123 _handleReleaseLogic: function (touch) { 1124 1125 var touchPositionInNodeSpace = this.convertToNodeSpace(touch.getLocation()), 1126 previousTouchPositionInNodeSpace = this.convertToNodeSpace(touch.getPreviousLocation()); 1127 var delta = cc.pSub(touchPositionInNodeSpace, previousTouchPositionInNodeSpace); 1128 1129 this._gatherTouchMove(delta); 1130 1131 this._bePressed = false; 1132 1133 var bounceBackStarted = this._startBounceBackIfNeeded(); 1134 if(!bounceBackStarted && this.inertiaScrollEnabled) 1135 { 1136 var touchMoveVelocity = this._calculateTouchMoveVelocity(); 1137 if(touchMoveVelocity.x !== 0 || touchMoveVelocity.y !== 0) 1138 { 1139 this._startInertiaScroll(touchMoveVelocity); 1140 } 1141 } 1142 1143 if(this._verticalScrollBar) 1144 { 1145 this._verticalScrollBar.onTouchEnded(); 1146 } 1147 if(this._horizontalScrollBar) 1148 { 1149 this._horizontalScrollBar.onTouchEnded(); 1150 } 1151 }, 1152 1153 /** 1154 * The touch began event callback handler of ccui.ScrollView. 1155 * @param {cc.Touch} touch 1156 * @param {cc.Event} event 1157 * @returns {boolean} 1158 */ 1159 onTouchBegan: function (touch, event) { 1160 var pass = ccui.Layout.prototype.onTouchBegan.call(this, touch, event); 1161 if(!this._isInterceptTouch){ 1162 if (this._hit) 1163 this._handlePressLogic(touch); 1164 } 1165 return pass; 1166 }, 1167 1168 /** 1169 * The touch moved event callback handler of ccui.ScrollView. 1170 * @param {cc.Touch} touch 1171 * @param {cc.Event} event 1172 */ 1173 onTouchMoved: function (touch, event) { 1174 ccui.Layout.prototype.onTouchMoved.call(this, touch, event); 1175 if(!this._isInterceptTouch) 1176 this._handleMoveLogic(touch); 1177 }, 1178 1179 /** 1180 * The touch ended event callback handler of ccui.ScrollView. 1181 * @param {cc.Touch} touch 1182 * @param {cc.Event} event 1183 */ 1184 onTouchEnded: function (touch, event) { 1185 ccui.Layout.prototype.onTouchEnded.call(this, touch, event); 1186 if(!this._isInterceptTouch) 1187 this._handleReleaseLogic(touch); 1188 this._isInterceptTouch = false; 1189 }, 1190 1191 /** 1192 * The touch canceled event callback of ccui.ScrollView. 1193 * @param {cc.Touch} touch 1194 * @param {cc.Event} event 1195 */ 1196 onTouchCancelled: function (touch, event) { 1197 ccui.Layout.prototype.onTouchCancelled.call(this, touch, event); 1198 if (!this._isInterceptTouch) 1199 this._handleReleaseLogic(touch); 1200 this._isInterceptTouch = false; 1201 }, 1202 1203 /** 1204 * The update callback handler. 1205 * @param {Number} dt 1206 */ 1207 update: function (dt) { 1208 if (this._autoScrolling) 1209 this._processAutoScrolling(dt); 1210 }, 1211 1212 /** 1213 * Intercept touch event, handle its child's touch event. 1214 * @override 1215 * @param {number} event event type 1216 * @param {ccui.Widget} sender 1217 * @param {cc.Touch} touch 1218 */ 1219 interceptTouchEvent: function (event, sender, touch) { 1220 if(!this._touchEnabled) 1221 { 1222 ccui.Layout.prototype.interceptTouchEvent.call(this, event, sender, touch); 1223 return; 1224 } 1225 1226 if(this._direction === ccui.ScrollView.DIR_NONE) 1227 return; 1228 1229 var touchPoint = touch.getLocation(); 1230 switch (event) { 1231 case ccui.Widget.TOUCH_BEGAN: 1232 this._isInterceptTouch = true; 1233 this._touchBeganPosition.x = touchPoint.x; 1234 this._touchBeganPosition.y = touchPoint.y; 1235 this._handlePressLogic(touch); 1236 break; 1237 case ccui.Widget.TOUCH_MOVED: 1238 var offset = cc.pLength(cc.pSub(sender.getTouchBeganPosition(), touchPoint)); 1239 this._touchMovePosition.x = touchPoint.x; 1240 this._touchMovePosition.y = touchPoint.y; 1241 if (offset > this._childFocusCancelOffset) { 1242 sender.setHighlighted(false); 1243 this._handleMoveLogic(touch); 1244 } 1245 break; 1246 case ccui.Widget.TOUCH_CANCELED: 1247 case ccui.Widget.TOUCH_ENDED: 1248 this._touchEndPosition.x = touchPoint.x; 1249 this._touchEndPosition.y = touchPoint.y; 1250 this._handleReleaseLogic(touch); 1251 if (sender.isSwallowTouches()) 1252 this._isInterceptTouch = false; 1253 break; 1254 } 1255 }, 1256 1257 _processScrollEvent: function(_directionEvent, bounce) 1258 { 1259 var event = 0; 1260 1261 switch(_directionEvent) 1262 { 1263 case ccui.ScrollView.MOVEDIR_TOP: 1264 event = (bounce ? ccui.ScrollView.EVENT_BOUNCE_TOP : ccui.ScrollView.EVENT_SCROLL_TO_TOP); 1265 break; 1266 case ccui.ScrollView.MOVEDIR_BOTTOM: 1267 event = (bounce ? ccui.ScrollView.EVENT_BOUNCE_BOTTOM : ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM); 1268 break; 1269 case ccui.ScrollView.MOVEDIR_LEFT: 1270 event = (bounce ? ccui.ScrollView.EVENT_BOUNCE_LEFT : ccui.ScrollView.EVENT_SCROLL_TO_LEFT); 1271 break; 1272 case ccui.ScrollView.MOVEDIR_RIGHT: 1273 event = (bounce ? ccui.ScrollView.EVENT_BOUNCE_RIGHT : ccui.ScrollView.EVENT_SCROLL_TO_RIGHT); 1274 break; 1275 } 1276 1277 this._dispatchEvent(event); 1278 }, 1279 1280 _processScrollingEvent: function() 1281 { 1282 this._dispatchEvent( ccui.ScrollView.EVENT_SCROLLING); 1283 }, 1284 1285 _dispatchEvent: function(event) 1286 { 1287 if(this._scrollViewEventSelector){ 1288 if (this._scrollViewEventListener) 1289 this._scrollViewEventSelector.call(this._scrollViewEventListener, this, event); 1290 else 1291 this._scrollViewEventSelector(this, event); 1292 } 1293 if(this._ccEventCallback) 1294 this._ccEventCallback(this, event); 1295 }, 1296 1297 /** 1298 * Adds callback function called ScrollView event triggered 1299 * @param {Function} selector 1300 * @param {Object} [target=] 1301 * @deprecated since v3.0, please use addEventListener instead. 1302 */ 1303 addEventListenerScrollView: function (selector, target) { 1304 this._scrollViewEventSelector = selector; 1305 this._scrollViewEventListener = target; 1306 }, 1307 1308 /** 1309 * Adds callback function called ScrollView event triggered 1310 * @param {Function} selector 1311 */ 1312 addEventListener: function(selector){ 1313 this._ccEventCallback = selector; 1314 }, 1315 1316 /** 1317 * Changes scroll _direction of ScrollView. 1318 * @param {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} dir 1319 * Direction::VERTICAL means vertical scroll, Direction::HORIZONTAL means horizontal scroll 1320 */ 1321 setDirection: function (dir) { 1322 this._direction = dir; 1323 1324 if(this._scrollBarEnabled) 1325 { 1326 this._removeScrollBar(); 1327 this._initScrollBar(); 1328 } 1329 }, 1330 1331 /** 1332 * Returns scroll direction of ScrollView. 1333 * @returns {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} 1334 */ 1335 getDirection: function () { 1336 return this._direction; 1337 }, 1338 1339 /** 1340 * Sets bounce enabled 1341 * @param {Boolean} enabled 1342 */ 1343 setBounceEnabled: function (enabled) { 1344 this.bounceEnabled = enabled; 1345 }, 1346 1347 /** 1348 * Returns whether bounce is enabled 1349 * @returns {boolean} 1350 */ 1351 isBounceEnabled: function () { 1352 return this.bounceEnabled; 1353 }, 1354 1355 /** 1356 * Sets inertiaScroll enabled 1357 * @param {boolean} enabled 1358 */ 1359 setInertiaScrollEnabled: function (enabled) { 1360 this.inertiaScrollEnabled = enabled; 1361 }, 1362 1363 /** 1364 * Returns whether inertiaScroll is enabled 1365 * @returns {boolean} 1366 */ 1367 isInertiaScrollEnabled: function () { 1368 return this.inertiaScrollEnabled; 1369 }, 1370 1371 /** 1372 * Toggle scroll bar enabled. 1373 * @param {boolean} enabled True if enable scroll bar, false otherwise. 1374 */ 1375 setScrollBarEnabled: function(enabled) 1376 { 1377 if(this._scrollBarEnabled === enabled) 1378 { 1379 return; 1380 } 1381 1382 if(this._scrollBarEnabled) 1383 { 1384 this._removeScrollBar(); 1385 } 1386 this._scrollBarEnabled = enabled; 1387 if(this._scrollBarEnabled) 1388 { 1389 this._initScrollBar(); 1390 } 1391 }, 1392 /** 1393 * Query scroll bar state. 1394 * @returns {boolean} True if scroll bar is enabled, false otherwise. 1395 */ 1396 isScrollBarEnabled: function() 1397 { 1398 return this._scrollBarEnabled; 1399 }, 1400 1401 /** 1402 * Set the scroll bar positions from the left-bottom corner (horizontal) and right-top corner (vertical). 1403 * @param {cc.Point} positionFromCorner The position from the left-bottom corner (horizontal) and right-top corner (vertical). 1404 */ 1405 setScrollBarPositionFromCorner: function(positionFromCorner) 1406 { 1407 if(this._direction !== ccui.ScrollView.DIR_HORIZONTAL) 1408 { 1409 this.setScrollBarPositionFromCornerForVertical(positionFromCorner); 1410 } 1411 if(this._direction !== ccui.ScrollView.DIR_VERTICAL) 1412 { 1413 this.setScrollBarPositionFromCornerForHorizontal(positionFromCorner); 1414 } 1415 }, 1416 1417 /** 1418 * Set the vertical scroll bar position from right-top corner. 1419 * @param {cc.Point} positionFromCorner The position from right-top corner 1420 */ 1421 setScrollBarPositionFromCornerForVertical: function(positionFromCorner) 1422 { 1423 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1424 cc.assert(this._direction !== ccui.ScrollView.DIR_HORIZONTAL, "Scroll view doesn't have a vertical scroll bar!"); 1425 this._verticalScrollBar.setPositionFromCorner(positionFromCorner); 1426 }, 1427 1428 /** 1429 * Get the vertical scroll bar's position from right-top corner. 1430 * @returns {cc.Point} 1431 */ 1432 getScrollBarPositionFromCornerForVertical: function() 1433 { 1434 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1435 cc.assert(this._direction !== ccui.ScrollView.DIR_HORIZONTAL, "Scroll view doesn't have a vertical scroll bar!"); 1436 return this._verticalScrollBar.getPositionFromCorner(); 1437 }, 1438 1439 /** 1440 * Set the horizontal scroll bar position from left-bottom corner. 1441 * @param {cc.Point} positionFromCorner The position from left-bottom corner 1442 */ 1443 setScrollBarPositionFromCornerForHorizontal: function(positionFromCorner) 1444 { 1445 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1446 cc.assert(this._direction !== ccui.ScrollView.DIR_VERTICAL, "Scroll view doesn't have a horizontal scroll bar!"); 1447 this._horizontalScrollBar.setPositionFromCorner(positionFromCorner); 1448 }, 1449 1450 /** 1451 * Get the horizontal scroll bar's position from right-top corner. 1452 * @returns {cc.Point} 1453 */ 1454 getScrollBarPositionFromCornerForHorizontal: function() 1455 { 1456 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1457 cc.assert(this._direction !== ccui.ScrollView.DIR_VERTICAL, "Scroll view doesn't have a horizontal scroll bar!"); 1458 return this._horizontalScrollBar.getPositionFromCorner(); 1459 }, 1460 1461 /** 1462 * Set the scroll bar's width 1463 * @param {number} width The scroll bar's width 1464 */ 1465 setScrollBarWidth: function(width) 1466 { 1467 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1468 if(this._verticalScrollBar) 1469 { 1470 this._verticalScrollBar.setWidth(width); 1471 } 1472 if(this._horizontalScrollBar) 1473 { 1474 this._horizontalScrollBar.setWidth(width); 1475 } 1476 }, 1477 1478 /** 1479 * Get the scroll bar's width 1480 * @returns {number} the scroll bar's width 1481 */ 1482 getScrollBarWidth: function() 1483 { 1484 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1485 if(this._verticalScrollBar) 1486 { 1487 return this._verticalScrollBar.getWidth(); 1488 } 1489 if(this._horizontalScrollBar) 1490 { 1491 return this._horizontalScrollBar.getWidth(); 1492 } 1493 return 0; 1494 }, 1495 1496 /** 1497 * Set the scroll bar's color 1498 * @param {cc.Color} color the scroll bar's color 1499 */ 1500 setScrollBarColor: function(color) 1501 { 1502 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1503 if(this._verticalScrollBar) 1504 { 1505 this._verticalScrollBar.setColor(color); 1506 } 1507 if(this._horizontalScrollBar) 1508 { 1509 this._horizontalScrollBar.setColor(color); 1510 } 1511 }, 1512 1513 /** 1514 * Get the scroll bar's color 1515 * @returns {cc.Color} the scroll bar's color 1516 */ 1517 getScrollBarColor: function() 1518 { 1519 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1520 if(this._verticalScrollBar) 1521 { 1522 this._verticalScrollBar.getColor(); 1523 } 1524 if(this._horizontalScrollBar) 1525 { 1526 this._horizontalScrollBar.getColor(); 1527 } 1528 return cc.color.WHITE; 1529 }, 1530 1531 /** 1532 * Set the scroll bar's opacity 1533 * @param {number} opacity the scroll bar's opacity 1534 */ 1535 setScrollBarOpacity: function(opacity) 1536 { 1537 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1538 if(this._verticalScrollBar) 1539 { 1540 this._verticalScrollBar.opacity = opacity; 1541 } 1542 if(this._horizontalScrollBar) 1543 { 1544 this._horizontalScrollBar.opacity = opacity; 1545 } 1546 }, 1547 1548 /** 1549 * Get the scroll bar's opacity 1550 * @returns {number} 1551 */ 1552 getScrollBarOpacity: function() 1553 { 1554 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1555 if(this._verticalScrollBar) 1556 { 1557 return this._verticalScrollBar.opacity; 1558 } 1559 if(this._horizontalScrollBar) 1560 { 1561 return this._horizontalScrollBar.opacity; 1562 } 1563 return -1; 1564 }, 1565 1566 /** 1567 * Set scroll bar auto hide state 1568 * @param {boolean} autoHideEnabled scroll bar auto hide state 1569 */ 1570 setScrollBarAutoHideEnabled: function(autoHideEnabled) 1571 { 1572 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1573 if(this._verticalScrollBar) 1574 { 1575 this._verticalScrollBar.autoHideEnabled = autoHideEnabled; 1576 } 1577 if(this._horizontalScrollBar) 1578 { 1579 this._horizontalScrollBar.autoHideEnabled = autoHideEnabled; 1580 } 1581 }, 1582 1583 /** 1584 * Query scroll bar auto hide state 1585 * @returns {boolean} 1586 */ 1587 isScrollBarAutoHideEnabled: function() 1588 { 1589 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1590 if(this._verticalScrollBar) 1591 { 1592 return this._verticalScrollBar.autoHideEnabled; 1593 } 1594 if(this._horizontalScrollBar) 1595 { 1596 return this._horizontalScrollBar.autoHideEnabled; 1597 } 1598 return false; 1599 }, 1600 1601 /** 1602 * Set scroll bar auto hide time 1603 * @param {number} autoHideTime scroll bar auto hide state 1604 */ 1605 setScrollBarAutoHideTime: function(autoHideTime) 1606 { 1607 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1608 if(this._verticalScrollBar) 1609 { 1610 this._verticalScrollBar.autoHideTime = autoHideTime; 1611 } 1612 if(this._horizontalScrollBar) 1613 { 1614 this._horizontalScrollBar.autoHideTime = autoHideTime; 1615 } 1616 }, 1617 1618 /** 1619 * Get the scroll bar's auto hide time 1620 * @returns {number} 1621 */ 1622 getScrollBarAutoHideTime: function() 1623 { 1624 cc.assert(this._scrollBarEnabled, "Scroll bar should be enabled!"); 1625 if(this._verticalScrollBar) 1626 { 1627 return this._verticalScrollBar.autoHideTime; 1628 } 1629 if(this._horizontalScrollBar) 1630 { 1631 return this._horizontalScrollBar.autoHideTime; 1632 } 1633 return 0; 1634 }, 1635 1636 /** 1637 * Gets inner container of ScrollView. Inner container is the container of ScrollView's children. 1638 * @returns {ccui.Layout} 1639 */ 1640 getInnerContainer: function () { 1641 return this._innerContainer; 1642 }, 1643 1644 /** 1645 * Sets LayoutType of ccui.ScrollView. 1646 * @param {ccui.Layout.ABSOLUTE|ccui.Layout.LINEAR_VERTICAL|ccui.Layout.LINEAR_HORIZONTAL|ccui.Layout.RELATIVE} type 1647 */ 1648 setLayoutType: function (type) { 1649 this._innerContainer.setLayoutType(type); 1650 }, 1651 1652 /** 1653 * Returns the layout type of ccui.ScrollView. 1654 * @returns {ccui.Layout.ABSOLUTE|ccui.Layout.LINEAR_VERTICAL|ccui.Layout.LINEAR_HORIZONTAL|ccui.Layout.RELATIVE} 1655 */ 1656 getLayoutType: function () { 1657 return this._innerContainer.getLayoutType(); 1658 }, 1659 1660 _doLayout: function () { 1661 if (!this._doLayoutDirty) 1662 return; 1663 this._doLayoutDirty = false; 1664 }, 1665 1666 /** 1667 * Returns the "class name" of ccui.ScrollView. 1668 * @returns {string} 1669 */ 1670 getDescription: function () { 1671 return "ScrollView"; 1672 }, 1673 1674 _createCloneInstance: function(){ 1675 return new ccui.ScrollView(); 1676 }, 1677 1678 _copyClonedWidgetChildren: function (model) { 1679 ccui.Layout.prototype._copyClonedWidgetChildren.call(this, model); 1680 }, 1681 1682 _copySpecialProperties: function (scrollView) { 1683 if(scrollView instanceof ccui.ScrollView) { 1684 ccui.Layout.prototype._copySpecialProperties.call(this, scrollView); 1685 this.setInnerContainerSize(scrollView.getInnerContainerSize()); 1686 this.setInnerContainerPosition(scrollView.getInnerContainerPosition()); 1687 this.setDirection(scrollView._direction); 1688 1689 this._topBoundary = scrollView._topBoundary; 1690 this._bottomBoundary = scrollView._bottomBoundary; 1691 this._leftBoundary = scrollView._leftBoundary; 1692 this._rightBoundary = scrollView._rightBoundary; 1693 this._bePressed = scrollView._bePressed; 1694 this._childFocusCancelOffset = scrollView._childFocusCancelOffset; 1695 this._touchMoveDisplacements = scrollView._touchMoveDisplacements; 1696 this._touchMoveTimeDeltas = scrollView._touchMoveTimeDeltas; 1697 this._touchMovePreviousTimestamp = scrollView._touchMovePreviousTimestamp; 1698 this._autoScrolling = scrollView._autoScrolling; 1699 this._autoScrollAttenuate = scrollView._autoScrollAttenuate; 1700 this._autoScrollStartPosition = scrollView._autoScrollStartPosition; 1701 this._autoScrollTargetDelta = scrollView._autoScrollTargetDelta; 1702 this._autoScrollTotalTime = scrollView._autoScrollTotalTime; 1703 this._autoScrollAccumulatedTime = scrollView._autoScrollAccumulatedTime; 1704 this._autoScrollCurrentlyOutOfBoundary = scrollView._autoScrollCurrentlyOutOfBoundary; 1705 this._autoScrollBraking = scrollView._autoScrollBraking; 1706 this._autoScrollBrakingStartPosition = scrollView._autoScrollBrakingStartPosition; 1707 1708 this.setBounceEnabled(scrollView.bounceEnabled); 1709 this.setInertiaScrollEnabled(scrollView.inertiaScrollEnabled); 1710 1711 this._scrollViewEventListener = scrollView._scrollViewEventListener; 1712 this._scrollViewEventSelector = scrollView._scrollViewEventSelector; 1713 this._ccEventCallback = scrollView._ccEventCallback; 1714 1715 this.setScrollBarEnabled(scrollView.isScrollBarEnabled()); 1716 if(this.isScrollBarEnabled()) 1717 { 1718 if(this._direction !== ccui.ScrollView.DIR_HORIZONTAL) 1719 { 1720 this.setScrollBarPositionFromCornerForVertical(scrollView.getScrollBarPositionFromCornerForVertical()); 1721 } 1722 if(this._direction !== ccui.ScrollView.DIR_VERTICAL) 1723 { 1724 this.setScrollBarPositionFromCornerForHorizontal(scrollView.getScrollBarPositionFromCornerForHorizontal()); 1725 } 1726 this.setScrollBarWidth(scrollView.getScrollBarWidth()); 1727 this.setScrollBarColor(scrollView.getScrollBarColor()); 1728 this.setScrollBarAutoHideEnabled(scrollView.isScrollBarAutoHideEnabled()); 1729 this.setScrollBarAutoHideTime(scrollView.getScrollBarAutoHideTime()); 1730 } 1731 } 1732 }, 1733 1734 _initScrollBar: function() 1735 { 1736 if(this._direction !== ccui.ScrollView.DIR_HORIZONTAL && !this._verticalScrollBar) 1737 { 1738 this._verticalScrollBar = new ccui.ScrollViewBar(this, ccui.ScrollView.DIR_VERTICAL); 1739 this.addProtectedChild(this._verticalScrollBar, 2); 1740 } 1741 if(this._direction !== ccui.ScrollView.DIR_VERTICAL && !this._horizontalScrollBar) 1742 { 1743 this._horizontalScrollBar = new ccui.ScrollViewBar(this, ccui.ScrollView.DIR_HORIZONTAL); 1744 this.addProtectedChild(this._horizontalScrollBar, 2); 1745 } 1746 }, 1747 1748 _removeScrollBar: function() 1749 { 1750 if(this._verticalScrollBar) 1751 { 1752 this.removeProtectedChild(this._verticalScrollBar); 1753 this._verticalScrollBar = null; 1754 } 1755 if(this._horizontalScrollBar) 1756 { 1757 this.removeProtectedChild(this._horizontalScrollBar); 1758 this._horizontalScrollBar = null; 1759 } 1760 }, 1761 1762 /** 1763 * Returns a node by tag 1764 * @param {Number} tag 1765 * @returns {cc.Node} 1766 * @deprecated since v3.0, please use getChildByTag instead. 1767 */ 1768 getNodeByTag: function (tag) { 1769 return this._innerContainer.getNodeByTag(tag); 1770 }, 1771 1772 /** 1773 * Returns all nodes of inner container 1774 * @returns {Array} 1775 * @deprecated since v3.0, please use getChildren instead. 1776 */ 1777 getNodes: function () { 1778 return this._innerContainer.getNodes(); 1779 }, 1780 1781 /** 1782 * Removes a node from ccui.ScrollView. 1783 * @param {cc.Node} node 1784 * @deprecated since v3.0, please use removeChild instead. 1785 */ 1786 removeNode: function (node) { 1787 this._innerContainer.removeNode(node); 1788 }, 1789 1790 /** 1791 * Removes a node by tag 1792 * @param {Number} tag 1793 * @deprecated since v3.0, please use removeChildByTag instead. 1794 */ 1795 removeNodeByTag: function (tag) { 1796 this._innerContainer.removeNodeByTag(tag); 1797 }, 1798 1799 /** 1800 * Remove all node from ccui.ScrollView. 1801 * @deprecated since v3.0, please use removeAllChildren instead. 1802 */ 1803 removeAllNodes: function () { 1804 this._innerContainer.removeAllNodes(); 1805 }, 1806 1807 /** 1808 * Add node for scrollView 1809 * @param {cc.Node} node 1810 * @param {Number} zOrder 1811 * @param {Number} tag 1812 * @deprecated since v3.0, please use addChild instead. 1813 */ 1814 addNode: function (node, zOrder, tag) { 1815 this._innerContainer.addNode(node, zOrder, tag); 1816 } 1817 }); 1818 1819 var _p = ccui.ScrollView.prototype; 1820 1821 // Extended properties 1822 /** @expose */ 1823 _p.innerWidth; 1824 cc.defineGetterSetter(_p, "innerWidth", _p._getInnerWidth, _p._setInnerWidth); 1825 /** @expose */ 1826 _p.innerHeight; 1827 cc.defineGetterSetter(_p, "innerHeight", _p._getInnerHeight, _p._setInnerHeight); 1828 /** @expose */ 1829 _p.direction; 1830 cc.defineGetterSetter(_p, "direction", _p.getDirection, _p.setDirection); 1831 /** @expose */ 1832 _p.touchTotalTimeThreshold; 1833 cc.defineGetterSetter(_p, "touchTotalTimeThreshold", _p.getTouchTotalTimeThreshold, _p.setTouchTotalTimeThreshold); 1834 _p = null; 1835 /** 1836 * allocates and initializes a UIScrollView. 1837 * @deprecated since v3.0, please use new ccui.ScrollView() instead. 1838 * @return {ccui.ScrollView} 1839 */ 1840 ccui.ScrollView.create = function () { 1841 return new ccui.ScrollView(); 1842 }; 1843 1844 // Constants 1845 //ScrollView direction 1846 /** 1847 * The none flag of ccui.ScrollView's direction. 1848 * @constant 1849 * @type {number} 1850 */ 1851 ccui.ScrollView.DIR_NONE = 0; 1852 /** 1853 * The vertical flag of ccui.ScrollView's direction. 1854 * @constant 1855 * @type {number} 1856 */ 1857 ccui.ScrollView.DIR_VERTICAL = 1; 1858 /** 1859 * The horizontal flag of ccui.ScrollView's direction. 1860 * @constant 1861 * @type {number} 1862 */ 1863 ccui.ScrollView.DIR_HORIZONTAL = 2; 1864 /** 1865 * The both flag of ccui.ScrollView's direction. 1866 * @constant 1867 * @type {number} 1868 */ 1869 ccui.ScrollView.DIR_BOTH = 3; 1870 1871 //ScrollView event 1872 /** 1873 * The flag scroll to top of ccui.ScrollView's event. 1874 * @constant 1875 * @type {number} 1876 */ 1877 ccui.ScrollView.EVENT_SCROLL_TO_TOP = 0; 1878 /** 1879 * The flag scroll to bottom of ccui.ScrollView's event. 1880 * @constant 1881 * @type {number} 1882 */ 1883 ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM = 1; 1884 /** 1885 * The flag scroll to left of ccui.ScrollView's event. 1886 * @constant 1887 * @type {number} 1888 */ 1889 ccui.ScrollView.EVENT_SCROLL_TO_LEFT = 2; 1890 /** 1891 * The flag scroll to right of ccui.ScrollView's event. 1892 * @constant 1893 * @type {number} 1894 */ 1895 ccui.ScrollView.EVENT_SCROLL_TO_RIGHT = 3; 1896 /** 1897 * The scrolling flag of ccui.ScrollView's event. 1898 * @constant 1899 * @type {number} 1900 */ 1901 ccui.ScrollView.EVENT_SCROLLING = 4; 1902 /** 1903 * The flag bounce top of ccui.ScrollView's event. 1904 * @constant 1905 * @type {number} 1906 */ 1907 ccui.ScrollView.EVENT_BOUNCE_TOP = 5; 1908 /** 1909 * The flag bounce bottom of ccui.ScrollView's event. 1910 * @constant 1911 * @type {number} 1912 */ 1913 ccui.ScrollView.EVENT_BOUNCE_BOTTOM = 6; 1914 /** 1915 * The flag bounce left of ccui.ScrollView's event. 1916 * @constant 1917 * @type {number} 1918 */ 1919 ccui.ScrollView.EVENT_BOUNCE_LEFT = 7; 1920 /** 1921 * The flag bounce right of ccui.ScrollView's event. 1922 * @constant 1923 * @type {number} 1924 */ 1925 ccui.ScrollView.EVENT_BOUNCE_RIGHT = 8; 1926 /** 1927 * The flag container moved of ccui.ScrollView's event. 1928 * @constant 1929 * @type {number} 1930 */ 1931 ccui.ScrollView.EVENT_CONTAINER_MOVED = 9; 1932 /** 1933 * The flag autoscroll ended of ccui.ScrollView's event. 1934 * @constant 1935 * @type {number} 1936 */ 1937 ccui.ScrollView.EVENT_AUTOSCROLL_ENDED = 10; 1938 1939 /** 1940 * @ignore 1941 */ 1942 1943 ccui.ScrollView.MOVEDIR_TOP = 0; 1944 ccui.ScrollView.MOVEDIR_BOTTOM = 1; 1945 ccui.ScrollView.MOVEDIR_LEFT = 2; 1946 ccui.ScrollView.MOVEDIR_RIGHT = 3; 1947