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 list view control of Cocos UI. 28 * @class 29 * @extends ccui.ScrollView 30 * @example 31 * var listView = new ccui.ListView(); 32 * // set list view ex direction 33 * listView.setDirection(ccui.ScrollView.DIR_VERTICAL); 34 * listView.setTouchEnabled(true); 35 * listView.setBounceEnabled(true); 36 * listView.setBackGroundImage("res/cocosui/green_edit.png"); 37 * listView.setBackGroundImageScale9Enabled(true); 38 * listView.setContentSize(cc.size(240, 130)); 39 * this.addChild(listView); 40 */ 41 ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ 42 _model: null, 43 _items: null, 44 _gravity: null, 45 _itemsMargin: 0, 46 47 _curSelectedIndex: 0, 48 _refreshViewDirty: true, 49 50 _listViewEventListener: null, 51 _listViewEventSelector: null, 52 /** 53 * allocates and initializes a UIListView. 54 * Constructor of ccui.ListView, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. 55 * @example 56 * // example 57 * var aListView = new ccui.ListView(); 58 */ 59 ctor: function () { 60 ccui.ScrollView.prototype.ctor.call(this); 61 this._items = []; 62 this._gravity = ccui.ListView.GRAVITY_CENTER_HORIZONTAL; 63 this.setTouchEnabled(true); 64 65 this.init(); 66 }, 67 68 /** 69 * Initializes a ccui.ListView. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. 70 * @returns {boolean} 71 * @override 72 */ 73 init: function () { 74 if (ccui.ScrollView.prototype.init.call(this)) { 75 this.setLayoutType(ccui.Layout.LINEAR_VERTICAL); 76 return true; 77 } 78 return false; 79 }, 80 81 /** 82 * Sets a item model for ListView. A model will be cloned for adding default item. 83 * @param {ccui.Widget} model 84 */ 85 setItemModel: function (model) { 86 if (!model) 87 return; 88 this._model = model; 89 }, 90 91 _updateInnerContainerSize: function () { 92 var locItems = this._items, length, i; 93 switch (this.direction) { 94 case ccui.ScrollView.DIR_VERTICAL: 95 length = locItems.length; 96 var totalHeight = (length - 1) * this._itemsMargin; 97 for (i = 0; i < length; i++) { 98 totalHeight += locItems[i].getContentSize().height; 99 } 100 this.setInnerContainerSize(cc.size(this._contentSize.width, totalHeight)); 101 break; 102 case ccui.ScrollView.DIR_HORIZONTAL: 103 length = locItems.length; 104 var totalWidth = (length - 1) * this._itemsMargin; 105 for (i = 0; i < length; i++) { 106 totalWidth += locItems[i].getContentSize().width; 107 } 108 this.setInnerContainerSize(cc.size(totalWidth, this._contentSize.height)); 109 break; 110 default: 111 break; 112 } 113 }, 114 115 _remedyLayoutParameter: function (item) { 116 if (!item) 117 return; 118 var llp; 119 switch (this.direction) { 120 case ccui.ScrollView.DIR_VERTICAL: 121 llp = item.getLayoutParameter(); 122 if (!llp) { 123 var defaultLp = ccui.LinearLayoutParameter.create(); 124 switch (this._gravity) { 125 case ccui.ListView.GRAVITY_LEFT: 126 defaultLp.setGravity(ccui.LinearLayoutParameter.LEFT); 127 break; 128 case ccui.ListView.GRAVITY_RIGHT: 129 defaultLp.setGravity(ccui.LinearLayoutParameter.RIGHT); 130 break; 131 case ccui.ListView.GRAVITY_CENTER_HORIZONTAL: 132 defaultLp.setGravity(ccui.LinearLayoutParameter.CENTER_HORIZONTAL); 133 break; 134 default: 135 break; 136 } 137 if (this.getIndex(item) == 0) 138 defaultLp.setMargin(ccui.MarginZero()); 139 else 140 defaultLp.setMargin(new ccui.Margin(0.0, this._itemsMargin, 0.0, 0.0)); 141 item.setLayoutParameter(defaultLp); 142 } else { 143 if (this.getIndex(item) == 0) 144 llp.setMargin(ccui.MarginZero()); 145 else 146 llp.setMargin(new ccui.Margin(0, this._itemsMargin, 0, 0)); 147 switch (this._gravity) { 148 case ccui.ListView.GRAVITY_LEFT: 149 llp.setGravity(ccui.LinearLayoutParameter.LEFT); 150 break; 151 case ccui.ListView.GRAVITY_RIGHT: 152 llp.setGravity(ccui.LinearLayoutParameter.RIGHT); 153 break; 154 case ccui.ListView.GRAVITY_CENTER_HORIZONTAL: 155 llp.setGravity(ccui.LinearLayoutParameter.CENTER_HORIZONTAL); 156 break; 157 default: 158 break; 159 } 160 } 161 break; 162 case ccui.ScrollView.DIR_HORIZONTAL: 163 llp = item.getLayoutParameter(); 164 if (!llp) { 165 var defaultLp = ccui.LinearLayoutParameter.create(); 166 switch (this._gravity) { 167 case ccui.ListView.GRAVITY_TOP: 168 defaultLp.setGravity(ccui.LinearLayoutParameter.TOP); 169 break; 170 case ccui.ListView.GRAVITY_BOTTOM: 171 defaultLp.setGravity(ccui.LinearLayoutParameter.BOTTOM ); 172 break; 173 case ccui.ListView.GRAVITY_CENTER_VERTICAL: 174 defaultLp.setGravity(ccui.LinearLayoutParameter.CENTER_VERTICAL); 175 break; 176 default: 177 break; 178 } 179 if (this.getIndex(item) == 0) 180 defaultLp.setMargin(ccui.MarginZero()); 181 else 182 defaultLp.setMargin(new ccui.Margin(this._itemsMargin, 0.0, 0.0, 0.0)); 183 item.setLayoutParameter(defaultLp); 184 } else { 185 if (this.getIndex(item) == 0) 186 llp.setMargin(ccui.MarginZero()); 187 else 188 llp.setMargin(new ccui.Margin(this._itemsMargin, 0.0, 0.0, 0.0)); 189 switch (this._gravity) { 190 case ccui.ListView.GRAVITY_TOP: 191 llp.setGravity(ccui.LinearLayoutParameter.TOP); 192 break; 193 case ccui.ListView.GRAVITY_BOTTOM: 194 llp.setGravity(ccui.LinearLayoutParameter.BOTTOM); 195 break; 196 case ccui.ListView.GRAVITY_CENTER_VERTICAL: 197 llp.setGravity(ccui.LinearLayoutParameter.CENTER_VERTICAL); 198 break; 199 default: 200 break; 201 } 202 } 203 break; 204 default: 205 break; 206 } 207 }, 208 209 /** 210 * Push back a default item(create by a cloned model) into ListView. 211 */ 212 pushBackDefaultItem: function () { 213 if (!this._model) 214 return; 215 var newItem = this._model.clone(); 216 this._remedyLayoutParameter(newItem); 217 this.addChild(newItem); 218 this._refreshViewDirty = true; 219 }, 220 221 /** 222 * Insert a default item(create by a cloned model) into ListView. 223 * @param {Number} index 224 */ 225 insertDefaultItem: function (index) { 226 if (!this._model) 227 return; 228 var newItem = this._model.clone(); 229 this._items.splice(index, 0, newItem); 230 ccui.ScrollView.prototype.addChild.call(this, newItem); 231 this._remedyLayoutParameter(newItem); 232 233 this._refreshViewDirty = true; 234 }, 235 236 /** 237 * Push back custom item into ListView. 238 * @param {ccui.Widget} item 239 */ 240 pushBackCustomItem: function (item) { 241 this._remedyLayoutParameter(item); 242 this.addChild(item); 243 this._refreshViewDirty = true; 244 }, 245 246 /** 247 * add child to ListView 248 * @override 249 * @param {cc.Node} widget 250 * @param {Number} [zOrder] 251 * @param {Number|String} [tag] tag or name 252 */ 253 addChild: function (widget, zOrder, tag) { 254 if (widget) { 255 zOrder = zOrder || widget.getLocalZOrder(); 256 tag = tag || widget.getName(); 257 ccui.ScrollView.prototype.addChild.call(this, widget, zOrder, tag); 258 if(widget instanceof ccui.Widget) 259 this._items.push(widget); 260 } 261 }, 262 263 /** 264 * remove child from ListView 265 * @override 266 * @param {cc.Node} widget 267 * @param {Boolean} [cleanup=true] 268 */ 269 removeChild: function(widget, cleanup){ 270 if (widget) { 271 var index = this._items.indexOf(widget); 272 if(index > -1) 273 this._items.splice(index, 1); 274 ccui.ScrollView.prototype.removeChild.call(this, widget, cleanup); 275 } 276 }, 277 278 /** 279 * Removes all children from ccui.ListView. 280 */ 281 removeAllChildren: function(){ 282 this.removeAllChildrenWithCleanup(true); 283 }, 284 285 /** 286 * Removes all children from ccui.ListView and do a cleanup all running actions depending on the cleanup parameter. 287 * @param {Boolean} cleanup 288 */ 289 removeAllChildrenWithCleanup: function(cleanup){ 290 ccui.ScrollView.prototype.removeAllChildrenWithCleanup.call(this, cleanup); 291 this._items = []; 292 }, 293 294 /** 295 * Push back custom item into ccui.ListView. 296 * @param {ccui.Widget} item 297 * @param {Number} index 298 */ 299 insertCustomItem: function (item, index) { 300 this._items.splice(index, 0, item); 301 ccui.ScrollView.prototype.addChild.call(this, item); 302 this._remedyLayoutParameter(item); 303 this._refreshViewDirty = true; 304 }, 305 306 /** 307 * Removes a item whose index is same as the parameter. 308 * @param {Number} index 309 */ 310 removeItem: function (index) { 311 var item = this.getItem(index); 312 if (!item) 313 return; 314 this.removeChild(item, true); 315 this._refreshViewDirty = true; 316 }, 317 318 /** 319 * Removes the last item of ccui.ListView. 320 */ 321 removeLastItem: function () { 322 this.removeItem(this._items.length - 1); 323 }, 324 325 /** 326 * Removes all items from ccui.ListView. 327 */ 328 removeAllItems: function(){ 329 this.removeAllChildren(); 330 }, 331 332 /** 333 * Returns a item whose index is same as the parameter. 334 * @param {Number} index 335 * @returns {ccui.Widget} 336 */ 337 getItem: function (index) { 338 if (index < 0 || index >= this._items.length) 339 return null; 340 return this._items[index]; 341 }, 342 343 /** 344 * Returns the item container. 345 * @returns {Array} 346 */ 347 getItems: function () { 348 return this._items; 349 }, 350 351 /** 352 * Returns the index of item. 353 * @param {ccui.Widget} item the item which need to be checked. 354 * @returns {Number} the index of item. 355 */ 356 getIndex: function (item) { 357 return this._items.indexOf(item); 358 }, 359 360 /** 361 * Changes the gravity of ListView. 362 * @param {ccui.ListView.GRAVITY_LEFT|ccui.ListView.GRAVITY_RIGHT|ccui.ListView.GRAVITY_CENTER_HORIZONTAL|ccui.ListView.GRAVITY_BOTTOM|ccui.ListView.GRAVITY_CENTER_VERTICAL} gravity 363 */ 364 setGravity: function (gravity) { 365 if (this._gravity == gravity) 366 return; 367 this._gravity = gravity; 368 this._refreshViewDirty = true; 369 }, 370 371 /** 372 * Changes the margin between each item. 373 * @param {Number} margin 374 */ 375 setItemsMargin: function (margin) { 376 if (this._itemsMargin == margin) 377 return; 378 this._itemsMargin = margin; 379 this._refreshViewDirty = true; 380 }, 381 382 /** 383 * Returns the margin between each item. 384 * @returns {Number} 385 */ 386 getItemsMargin:function(){ 387 return this._itemsMargin; 388 }, 389 390 /** 391 * Changes scroll direction of ccui.ListView. 392 * @param {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} dir 393 */ 394 setDirection: function (dir) { 395 switch (dir) { 396 case ccui.ScrollView.DIR_VERTICAL: 397 this.setLayoutType(ccui.Layout.LINEAR_VERTICAL); 398 break; 399 case ccui.ScrollView.DIR_HORIZONTAL: 400 this.setLayoutType(ccui.Layout.LINEAR_HORIZONTAL); 401 break; 402 case ccui.ScrollView.DIR_BOTH: 403 return; 404 default: 405 return; 406 break; 407 } 408 ccui.ScrollView.prototype.setDirection.call(this, dir); 409 }, 410 411 /** 412 * Requests refresh list view. 413 */ 414 requestRefreshView: function () { 415 this._refreshViewDirty = true; 416 }, 417 418 /** 419 * Refreshes list view. 420 */ 421 refreshView: function () { 422 var locItems = this._items; 423 for (var i = 0; i < locItems.length; i++) { 424 var item = locItems[i]; 425 item.setLocalZOrder(i); 426 this._remedyLayoutParameter(item); 427 } 428 this._updateInnerContainerSize(); 429 }, 430 431 /** 432 * provides a public _doLayout function for Editor. it calls _doLayout. 433 */ 434 doLayout: function(){ 435 this._doLayout(); 436 }, 437 438 _doLayout: function(){ 439 ccui.Layout.prototype._doLayout.call(this); 440 if (this._refreshViewDirty) { 441 this.refreshView(); 442 this._refreshViewDirty = false; 443 } 444 }, 445 446 /** 447 * Adds event listener to ccui.ListView. 448 * @param {Function} selector 449 * @param {Object} [target=] 450 * @deprecated since v3.0, please use addEventListener instead. 451 */ 452 addEventListenerListView: function (selector, target) { 453 this.addEventListener(selector, target); 454 }, 455 456 /** 457 * Adds event listener to ccui.ListView. 458 * @param {Function} selector 459 * @param {Object} [target=] 460 */ 461 addEventListener: function(selector, target){ 462 this._listViewEventListener = target; 463 this._listViewEventSelector = selector; 464 }, 465 466 _selectedItemEvent: function (event) { 467 var eventEnum = (event == ccui.Widget.TOUCH_BEGAN) ? ccui.ListView.ON_SELECTED_ITEM_START : ccui.ListView.ON_SELECTED_ITEM_END; 468 if(this._listViewEventSelector){ 469 if (this._listViewEventListener) 470 this._listViewEventSelector.call(this._listViewEventListener, this, eventEnum); 471 else 472 this._listViewEventSelector(this, eventEnum); 473 } 474 }, 475 476 /** 477 * Intercept touch event, handle its child's touch event. 478 * @param {Number} eventType 479 * @param {ccui.Widget} sender 480 * @param {cc.Touch} touch 481 */ 482 interceptTouchEvent: function (eventType, sender, touch) { 483 ccui.ScrollView.prototype.interceptTouchEvent.call(this, eventType, sender, touch); 484 if (eventType != ccui.Widget.TOUCH_MOVED) { 485 var parent = sender; 486 while (parent) { 487 if (parent && parent.getParent() == this._innerContainer) { 488 this._curSelectedIndex = this.getIndex(parent); 489 break; 490 } 491 parent = parent.getParent(); 492 } 493 if (sender.isHighlighted()) 494 this._selectedItemEvent(eventType); 495 } 496 }, 497 498 /** 499 * Returns current selected index 500 * @returns {number} 501 */ 502 getCurSelectedIndex: function () { 503 return this._curSelectedIndex; 504 }, 505 506 _onSizeChanged: function () { 507 ccui.ScrollView.prototype._onSizeChanged.call(this); 508 this._refreshViewDirty = true; 509 }, 510 511 /** 512 * Returns the "class name" of ccui.ListView. 513 * @returns {string} 514 */ 515 getDescription: function () { 516 return "ListView"; 517 }, 518 519 _createCloneInstance: function () { 520 return ccui.ListView.create(); 521 }, 522 523 _copyClonedWidgetChildren: function (model) { 524 var arrayItems = model.getItems(); 525 for (var i = 0; i < arrayItems.length; i++) { 526 var item = arrayItems[i]; 527 this.pushBackCustomItem(item.clone()); 528 } 529 }, 530 531 _copySpecialProperties: function (listView) { 532 if(listView instanceof ccui.ListView){ 533 ccui.ScrollView.prototype._copySpecialProperties.call(this, listView); 534 this.setItemModel(listView._model); 535 this.setItemsMargin(listView._itemsMargin); 536 this.setGravity(listView._gravity); 537 538 this._listViewEventListener = listView._listViewEventListener; 539 this._listViewEventSelector = listView._listViewEventSelector; 540 } 541 } 542 }); 543 544 /** 545 * allocates and initializes a UIListView. 546 * @deprecated since v3.0, please use new ccui.ListView() instead. 547 * @example 548 * // example 549 * var uiPageView = ccui.ListView.create(); 550 */ 551 ccui.ListView.create = function () { 552 return new ccui.ListView(); 553 }; 554 555 // Constants 556 //listView event type 557 /** 558 * The flag selected item of ccui.ListView's event. 559 * @constant 560 * @type {number} 561 */ 562 ccui.ListView.EVENT_SELECTED_ITEM = 0; 563 564 /** 565 * The flag selected item start of ccui.ListView's event. 566 * @constant 567 * @type {number} 568 */ 569 ccui.ListView.ON_SELECTED_ITEM_START = 0; 570 /** 571 * The flag selected item end of ccui.ListView's event. 572 * @constant 573 * @type {number} 574 */ 575 ccui.ListView.ON_SELECTED_ITEM_END = 1; 576 577 //listView gravity 578 /** 579 * The left flag of ccui.ListView's gravity. 580 * @constant 581 * @type {number} 582 */ 583 ccui.ListView.GRAVITY_LEFT = 0; 584 /** 585 * The right flag of ccui.ListView's gravity. 586 * @constant 587 * @type {number} 588 */ 589 ccui.ListView.GRAVITY_RIGHT = 1; 590 /** 591 * The center horizontal flag of ccui.ListView's gravity. 592 * @constant 593 * @type {number} 594 */ 595 ccui.ListView.GRAVITY_CENTER_HORIZONTAL = 2; 596 /** 597 * The top flag of ccui.ListView's gravity. 598 * @constant 599 * @type {number} 600 */ 601 ccui.ListView.GRAVITY_TOP = 3; 602 /** 603 * The bottom flag of ccui.ListView's gravity. 604 * @constant 605 * @type {number} 606 */ 607 ccui.ListView.GRAVITY_BOTTOM = 4; 608 /** 609 * The center vertical flag of ccui.ListView's gravity. 610 * @constant 611 * @type {number} 612 */ 613 ccui.ListView.GRAVITY_CENTER_VERTICAL = 5;