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 PageView control of Cocos UI. 28 * @class 29 * @extends ccui.ListView 30 * @example 31 * var pageView = new ccui.PageView(); 32 * pageView.setTouchEnabled(true); 33 * pageView.addPage(new ccui.Layout()); 34 * this.addChild(pageView); 35 */ 36 ccui.PageView = ccui.ListView.extend(/** @lends ccui.PageView# */{ 37 _curPageIdx: 0, 38 _childFocusCancelOffset: 0, 39 _pageViewEventListener: null, 40 _pageViewEventSelector: null, 41 _className:"PageView", 42 43 _indicator: null, 44 _indicatorPositionAsAnchorPoint: null, 45 /** 46 * Allocates and initializes a UIPageView. 47 * Constructor of ccui.PageView. please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. 48 * @example 49 * // example 50 * var uiPageView = new ccui.PageView(); 51 */ 52 ctor: function () { 53 ccui.ListView.prototype.ctor.call(this); 54 55 this._childFocusCancelOffset = 5; 56 this._indicatorPositionAsAnchorPoint = cc.p(0.5, 0.1); 57 this._pageViewEventListener = null; 58 this._pageViewEventSelector = null; 59 60 this.setDirection(ccui.ScrollView.DIR_HORIZONTAL); 61 this.setMagneticType(ccui.ListView.MAGNETIC_CENTER); 62 this.setScrollBarEnabled(false); 63 }, 64 65 /** 66 * Add a widget to a page of PageView. 67 * @deprecated since v3.9, please use 'insertPage(Widget* page, int idx)' instead. 68 * @param {ccui.Widget} widget widget to be added to PageView. 69 * @param {number} pageIdx index of page. 70 * @param {Boolean} forceCreate if force create and there is no page exist, PageView would create a default page for adding widget. 71 */ 72 addWidgetToPage: function (widget, pageIdx, forceCreate) { 73 this.insertCustomItem(widget, pageIdx); 74 }, 75 76 /** 77 * Insert a page into the end of PageView. 78 * @param {ccui.Widget} page Page to be inserted. 79 */ 80 addPage: function(page) 81 { 82 this.pushBackCustomItem(page); 83 }, 84 85 /** 86 * Insert a page into PageView at a given index. 87 * @param {ccui.Widget} page Page to be inserted. 88 * @param {number} idx A given index. 89 */ 90 insertPage: function(page, idx) 91 { 92 this.insertCustomItem(page, idx); 93 }, 94 95 /** 96 * Removes a page from PageView. 97 * @param {ccui.Widget} page Page to be removed. 98 */ 99 removePage: function (page) { 100 this.removeItem(this.getIndex(page)); 101 }, 102 103 /** 104 * Removes a page at index of PageView. 105 * @param {number} index A given index. 106 */ 107 removePageAtIndex: function (index) { 108 this.removeItem(index); 109 }, 110 111 /** 112 * Removes all pages from PageView 113 */ 114 removeAllPages: function(){ 115 this.removeAllItems(); 116 }, 117 118 /** 119 * scroll PageView to index. 120 * @param {number} idx A given index in the PageView. Index start from 0 to pageCount -1. 121 */ 122 scrollToItem: function (idx) { 123 ccui.ListView.prototype.scrollToItem.call(this, idx, cc.p(0.5, 0.5), cc.p(0.5, 0.5)); 124 }, 125 126 /** 127 * scroll PageView to index. 128 * @param {number} idx A given index in the PageView. Index start from 0 to pageCount -1. 129 */ 130 scrollToPage: function (idx) { 131 this.scrollToItem(idx); 132 }, 133 134 135 _doLayout: function(){ 136 if (!this._refreshViewDirty) 137 return; 138 139 ccui.ListView.prototype._doLayout.call(this); 140 141 if(this._indicator) 142 { 143 var index = this.getIndex(this.getCenterItemInCurrentView()); 144 this._indicator.indicate(index); 145 } 146 147 this._refreshViewDirty = false; 148 }, 149 150 /** 151 * Changes scroll direction of ccui.PageView. 152 * @param {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} direction 153 */ 154 setDirection: function(direction) 155 { 156 ccui.ListView.prototype.setDirection.call(this, direction); 157 if(direction === ccui.ScrollView.DIR_HORIZONTAL) 158 { 159 this._indicatorPositionAsAnchorPoint = cc.p(0.5, 0.1); 160 } 161 else if(direction === ccui.ScrollView.DIR_VERTICAL) 162 { 163 this._indicatorPositionAsAnchorPoint = cc.p(0.1, 0.5); 164 } 165 166 if(this._indicator) 167 { 168 this._indicator.setDirection(direction); 169 this._refreshIndicatorPosition(); 170 } 171 }, 172 173 /** 174 * Set custom scroll threshold to page view. If you don't specify the value, the pageView will scroll when half page view width reached. 175 * @since v3.2 176 * @param threshold 177 * @deprecated Since v3.9, this method has no effect. 178 */ 179 setCustomScrollThreshold: function(threshold){ 180 181 }, 182 183 /** 184 * Returns user defined scroll page threshold. 185 * @since v3.2 186 * @deprecated Since v3.9, this method always returns 0. 187 */ 188 getCustomScrollThreshold: function(){ 189 return 0; 190 }, 191 192 /** 193 * Set using user defined scroll page threshold or not. If you set it to false, then the default scroll threshold is pageView.width / 2. 194 * @since v3.2 195 * @deprecated Since v3.9, this method has no effect. 196 */ 197 setUsingCustomScrollThreshold: function(flag){ 198 }, 199 200 /** 201 * Queries whether we are using user defined scroll page threshold or not 202 * @deprecated Since v3.9, this method always returns false. 203 */ 204 isUsingCustomScrollThreshold: function(){ 205 return false; 206 }, 207 208 _moveInnerContainer: function(deltaMove, canStartBounceBack) 209 { 210 ccui.ListView.prototype._moveInnerContainer.call(this, deltaMove, canStartBounceBack); 211 this._curPageIdx = this.getIndex(this.getCenterItemInCurrentView()); 212 if(this._indicator) 213 { 214 this._indicator.indicate(this._curPageIdx); 215 } 216 }, 217 218 _onItemListChanged: function() 219 { 220 ccui.ListView.prototype._onItemListChanged.call(this); 221 if(this._indicator) 222 { 223 this._indicator.reset(this._items.length); 224 } 225 }, 226 227 _onSizeChanged: function() 228 { 229 ccui.ListView.prototype._onSizeChanged.call(this); 230 this._refreshIndicatorPosition(); 231 }, 232 233 _remedyLayoutParameter: function (item) 234 { 235 item.setContentSize(this.getContentSize()); 236 ccui.ListView.prototype._remedyLayoutParameter.call(this, item); 237 }, 238 239 _refreshIndicatorPosition: function() 240 { 241 if(this._indicator) 242 { 243 var contentSize = this.getContentSize(); 244 var posX = contentSize.width * this._indicatorPositionAsAnchorPoint.x; 245 var posY = contentSize.height * this._indicatorPositionAsAnchorPoint.y; 246 this._indicator.setPosition(cc.p(posX, posY)); 247 } 248 }, 249 250 _handleReleaseLogic: function (touchPoint) { 251 252 ccui.ScrollView.prototype._handleReleaseLogic.call(this, touchPoint); 253 254 if (this._items.length <= 0) 255 return; 256 257 var touchMoveVelocity = this._flattenVectorByDirection(this._calculateTouchMoveVelocity()); 258 259 var INERTIA_THRESHOLD = 500; 260 if(cc.pLength(touchMoveVelocity) < INERTIA_THRESHOLD) 261 { 262 this._startMagneticScroll(); 263 } 264 else 265 { 266 // Handle paging by inertia force. 267 var currentPage = this.getItem(this._curPageIdx); 268 var destination = this._calculateItemDestination(cc.p(0.5, 0.5), currentPage, cc.p(0.5, 0.5)); 269 var deltaToCurrentPage = cc.pSub(destination, this.getInnerContainerPosition()); 270 deltaToCurrentPage = this._flattenVectorByDirection(deltaToCurrentPage); 271 272 // If the direction of displacement to current page and the direction of touch are same, just start magnetic scroll to the current page. 273 // Otherwise, move to the next page of touch direction. 274 if(touchMoveVelocity.x * deltaToCurrentPage.x > 0 || touchMoveVelocity.y * deltaToCurrentPage.y > 0) 275 { 276 this._startMagneticScroll(); 277 } 278 else 279 { 280 if(touchMoveVelocity.x < 0 || touchMoveVelocity.y > 0) 281 { 282 ++this._curPageIdx; 283 } 284 else 285 { 286 --this._curPageIdx; 287 } 288 this._curPageIdx = Math.min(this._curPageIdx, this._items.length); 289 this._curPageIdx = Math.max(this._curPageIdx, 0); 290 this.scrollToItem(this._curPageIdx); 291 } 292 } 293 294 }, 295 296 _getAutoScrollStopEpsilon: function() 297 { 298 return 0.001; 299 }, 300 301 _pageTurningEvent: function () { 302 if(this._pageViewEventSelector){ 303 if (this._pageViewEventListener) 304 this._pageViewEventSelector.call(this._pageViewEventListener, this, ccui.PageView.EVENT_TURNING); 305 else 306 this._pageViewEventSelector(this, ccui.PageView.EVENT_TURNING); 307 } 308 if(this._ccEventCallback) 309 this._ccEventCallback(this, ccui.PageView.EVENT_TURNING); 310 }, 311 312 /** 313 * Adds event listener to ccui.PageView. 314 * @param {Function} selector 315 * @param {Object} [target=] 316 * @deprecated since v3.0, please use addEventListener instead. 317 */ 318 addEventListenerPageView: function (selector, target) { 319 this._pageViewEventSelector = selector; 320 this._pageViewEventListener = target; 321 }, 322 323 addEventListener: function(selector){ 324 this._ccEventCallback = function(ref, eventType) { 325 if(eventType == ccui.ScrollView.EVENT_AUTOSCROLL_ENDED) 326 selector(this, eventType) 327 }; 328 }, 329 330 /** 331 * Jump to a page with a given index without scrolling. 332 * This is the different between scrollToPage. 333 * @param {number} index A given index in PageView. Index start from 0 to pageCount -1. 334 */ 335 setCurrentPageIndex: function(index) 336 { 337 this.jumpToItem(index, cc.p(0.5, 0.5), cc.p(0.5, 0.5)); 338 }, 339 340 /** 341 * Jump to a page with a given index without scrolling. 342 * This is the different between scrollToPage. 343 * @param {number} index A given index in PageView. Index start from 0 to pageCount -1. 344 * @deprecated since v3.9, this is deprecated. Use `setCurrentPageIndex()` instead. 345 */ 346 setCurPageIndex: function(index) 347 { 348 this.setCurrentPageIndex(index); 349 }, 350 351 /** 352 * Returns current page index 353 * @returns {number} 354 */ 355 getCurrentPageIndex: function () { 356 return this._curPageIdx; 357 }, 358 359 /** 360 * Returns current page index 361 * @deprecated since v3.9, this is deprecated. Use `getCurrentPageIndex()` instead. 362 * @returns {number} 363 */ 364 getCurPageIndex: function () { 365 var widget = this.getCenterItemInCurrentView(); 366 return this.getIndex(widget); 367 }, 368 369 /** 370 * Returns all pages of PageView 371 * @returns {Array} 372 */ 373 getPages:function(){ 374 return this.getItems(); 375 }, 376 377 /** 378 * Returns a page from PageView by index 379 * @param {Number} index 380 * @returns {ccui.Layout} 381 */ 382 getPage: function(index){ 383 return this.getItem(index); 384 }, 385 386 /** 387 * Returns the "class name" of ccui.PageView. 388 * @returns {string} 389 */ 390 getDescription: function () { 391 return "PageView"; 392 }, 393 394 _createCloneInstance: function () { 395 return new ccui.PageView(); 396 }, 397 398 _copyClonedWidgetChildren: function (model) { 399 var arrayPages = model.getPages(); 400 for (var i = 0; i < arrayPages.length; i++) { 401 var page = arrayPages[i]; 402 this.addPage(page.clone()); 403 } 404 }, 405 406 _copySpecialProperties: function (pageView) { 407 ccui.ListView.prototype._copySpecialProperties.call(this, pageView); 408 this._ccEventCallback = pageView._ccEventCallback; 409 this._pageViewEventListener = pageView._pageViewEventListener; 410 this._pageViewEventSelector = pageView._pageViewEventSelector; 411 this._customScrollThreshold = pageView._customScrollThreshold; 412 }, 413 414 415 /** 416 * Toggle page indicator enabled. 417 * @param {boolean} enabled True if enable page indicator, false otherwise. 418 */ 419 setIndicatorEnabled: function(enabled) 420 { 421 if(enabled == (this._indicator !== null)) 422 { 423 return; 424 } 425 426 if(!enabled) 427 { 428 this.removeProtectedChild(this._indicator); 429 this._indicator = null; 430 } 431 else 432 { 433 this._indicator = new ccui.PageViewIndicator(); 434 this._indicator.setDirection(this.getDirection()); 435 this.addProtectedChild(this._indicator, 10000); 436 this.setIndicatorSelectedIndexColor(cc.color(100, 100, 255)); 437 this._refreshIndicatorPosition(); 438 } 439 }, 440 441 /** 442 * Query page indicator state. 443 * @returns {boolean} True if page indicator is enabled, false otherwise. 444 */ 445 getIndicatorEnabled: function() 446 { 447 return this._indicator !== null; 448 }, 449 450 /** 451 * Set the page indicator's position using anchor point. 452 * @param {cc.Point} positionAsAnchorPoint The position as anchor point. 453 */ 454 setIndicatorPositionAsAnchorPoint: function(positionAsAnchorPoint) 455 { 456 this._indicatorPositionAsAnchorPoint = positionAsAnchorPoint; 457 this._refreshIndicatorPosition(); 458 }, 459 460 /** 461 * Get the page indicator's position as anchor point. 462 * @returns {cc.Point} 463 */ 464 getIndicatorPositionAsAnchorPoint: function() 465 { 466 return this._indicatorPositionAsAnchorPoint; 467 }, 468 469 /** 470 * Set the page indicator's position in page view. 471 * @param {cc.Point} position The position in page view 472 */ 473 setIndicatorPosition: function(position) 474 { 475 if(this._indicator) 476 { 477 var contentSize = this.getContentSize(); 478 this._indicatorPositionAsAnchorPoint.x = position.x / contentSize.width; 479 this._indicatorPositionAsAnchorPoint.y = position.y / contentSize.height; 480 this._indicator.setPosition(position); 481 } 482 }, 483 484 /** 485 * Get the page indicator's position. 486 * @returns {cc.Point} 487 */ 488 getIndicatorPosition: function() 489 { 490 cc.assert(this._indicator !== null, ""); 491 return this._indicator.getPosition(); 492 }, 493 494 /** 495 * Set space between page indicator's index nodes. 496 * @param {number} spaceBetweenIndexNodes Space between nodes in pixel. 497 */ 498 setIndicatorSpaceBetweenIndexNodes: function(spaceBetweenIndexNodes) 499 { 500 if(this._indicator) 501 { 502 this._indicator.setSpaceBetweenIndexNodes(spaceBetweenIndexNodes); 503 } 504 }, 505 506 /** 507 * Get the space between page indicator's index nodes. 508 * @returns {number} 509 */ 510 getIndicatorSpaceBetweenIndexNodes: function() 511 { 512 cc.assert(this._indicator !== null, ""); 513 return this._indicator.getSpaceBetweenIndexNodes(); 514 }, 515 516 /** 517 * Set color of page indicator's selected index. 518 * @param {cc.Color} color Color for indicator 519 */ 520 setIndicatorSelectedIndexColor: function(color) 521 { 522 if(this._indicator) 523 { 524 this._indicator.setSelectedIndexColor(color); 525 } 526 }, 527 528 /** 529 * Get the color of page indicator's selected index. 530 * @returns {cc.Color} 531 */ 532 getIndicatorSelectedIndexColor: function() 533 { 534 cc.assert(this._indicator !== null, ""); 535 return this._indicator.getSelectedIndexColor(); 536 } 537 }); 538 /** 539 * allocates and initializes a UIPageView. 540 * @deprecated since v3.0, please use new ccui.PageView() instead. 541 * @return {ccui.PageView} 542 */ 543 ccui.PageView.create = function () { 544 return new ccui.PageView(); 545 }; 546 547 // Constants 548 //PageView event 549 /** 550 * The turning flag of ccui.PageView's event. 551 * @constant 552 * @type {number} 553 */ 554 ccui.PageView.EVENT_TURNING = 0; 555 556 //PageView touch direction 557 /** 558 * The left flag of ccui.PageView's touch direction. 559 * @constant 560 * @type {number} 561 */ 562 ccui.PageView.TOUCH_DIR_LEFT = 0; 563 /** 564 * The right flag of ccui.PageView's touch direction. 565 * @constant 566 * @type {number} 567 */ 568 ccui.PageView.TOUCH_DIR_RIGHT = 1; 569 570 //PageView auto scroll direction 571 /** 572 * The right flag of ccui.PageView's auto scroll direction. 573 * @constant 574 * @type {number} 575 */ 576 ccui.PageView.DIRECTION_LEFT = 0; 577 /** 578 * The right flag of ccui.PageView's auto scroll direction. 579 * @constant 580 * @type {number} 581 */ 582 ccui.PageView.DIRECTION_RIGHT = 1; 583