1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 
 25 /**
 26  * list view direction
 27  * @type {Object}
 28  */
 29 ccs.ListViewDirection = {
 30     none: 0,
 31     vertical: 1,
 32     horizontal: 2
 33 };
 34 
 35 /**
 36  * list view scroll direction
 37  * @type {Object}
 38  */
 39 ccs.ListViewMoveDirection = {
 40     none: 0,
 41     up: 1,
 42     down: 2,
 43     left: 3,
 44     right: 4
 45 };
 46 
 47 /**
 48  * ListView event type
 49  * @type {Object}
 50  */
 51 ccs.ListViewEventType = {
 52     init_child: 0,
 53     update_child: 1
 54 };
 55 
 56 /**
 57  * Base class for ccs.UIListView
 58  * @class
 59  * @extends ccs.UILayout
 60  */
 61 ccs.UIListView = ccs.UILayout.extend(/** @lends ccs.UIListView# */{
 62     _direction: null,
 63     _moveDirection: null,
 64     _touchStartLocation: 0,
 65     _touchEndLocation: 0,
 66     _touchMoveStartLocation: 0,
 67     _topBoundary: 0,//test
 68     _bottomBoundary: 0,//test
 69     _leftBoundary: 0,
 70     _rightBoundary: 0,
 71     _autoScroll: false,
 72     _autoScrollOriginalSpeed: 0,
 73     _autoScrollAcceleration: 0,
 74     _bePressed: false,
 75     _slidTime: 0,
 76     _moveChildPoint: null,
 77     _childFocusCancelOffset: 0,
 78     _childPool: null,
 79     _updatePool: null,
 80     _dataLength: 0,
 81     _begin: 0,
 82     _end: 0,
 83     _updateChild: null,
 84     _updateDataIndex: 0,
 85     _updateSuccess: false,
 86     _overTopArray: null,
 87     _overBottomArray: null,
 88     _overLeftArray: null,
 89     _overRightArray: null,
 90     _disBoundaryToChild_0: 0,
 91     _disBetweenChild: 0,
 92 
 93     _eventListener: null,
 94     _eventSelector: null,
 95     ctor: function () {
 96         ccs.UILayout.prototype.ctor.call(this);
 97 
 98         this._direction = ccs.ListViewDirection.vertical;
 99         this._moveDirection = ccs.ListViewMoveDirection.none;
100         this._touchStartLocation = 0;
101         this._touchEndLocation = 0;
102         this._touchMoveStartLocation = 0;
103         this._topBoundary = 0;//test
104         this._bottomBoundary = 0;//test
105         this._leftBoundary = 0;
106         this._rightBoundary = 0;
107         this._autoScroll = false;
108         this._autoScrollOriginalSpeed = 0;
109         this._autoScrollAcceleration = 600;
110         this._bePressed = false;
111         this._slidTime = 0;
112         this._moveChildPoint = null;
113         this._childFocusCancelOffset = 50;
114         this._childPool = [];
115         this._updatePool = [];
116         this._dataLength = 0;
117         this._begin = 0;
118         this._end = 0;
119         this._updateChild = null;
120         this._updateDataIndex = -1;
121         this._updateSuccess = false;
122         this._overTopArray = [];
123         this._overBottomArray = [];
124         this._overLeftArray = [];
125         this._overRightArray = [];
126         this._disBoundaryToChild_0 = 0;
127         this._disBetweenChild = 0;
128         this._eventListener = null;
129         this._eventSelector = null;
130     },
131     init: function () {
132         if (ccs.UILayout.prototype.init.call(this)) {
133             this.setUpdateEnabled(true);
134             this.setTouchEnabled(true);
135             this.setClippingEnabled(true);
136             this._childPool = [];
137             this._updatePool = [];
138             this._overTopArray = [];
139             this._overBottomArray = [];
140             this._overLeftArray = [];
141             this._overRightArray = [];
142             return true;
143         }
144         return false;
145     },
146 
147     onSizeChanged: function () {
148         ccs.UILayout.prototype.onSizeChanged.call(this);
149         this._topBoundary = this._size.height;
150         this._rightBoundary = this._size.width;
151     },
152 
153     /**
154      * Add widget child override
155      * @param {ccs.UIWidget} widget
156      * @returns {boolean}
157      */
158     addChild: function (widget) {
159         ccs.UILayout.prototype.addChild.call(this,widget);
160         this.resetProperty();
161         return true;
162     },
163 
164     /**
165      * remove all widget children override
166      */
167     removeAllChildren: function () {
168         this._updatePool = [];
169         this._childPool = [];
170         ccs.UILayout.prototype.removeAllChildren.call(this);
171     },
172 
173     /**
174      *  remove widget child override
175      * @param {ccs.UIWidget} child
176      * @returns {boolean}
177      */
178     removeChild: function (child) {
179         var value = false;
180 
181         if (ccs.UILayout.prototype.removeChild.call(this,child)) {
182             value = true;
183             this.resetProperty();
184         }
185 
186         return value;
187     },
188 
189     onTouchBegan: function (touchPoint) {
190         var pass = ccs.UILayout.prototype.onTouchBegan.call(this,touchPoint);
191         this.handlePressLogic(touchPoint);
192         return pass;
193     },
194 
195     onTouchMoved: function (touchPoint) {
196         ccs.UILayout.prototype.onTouchMoved.call(this,touchPoint);
197         this.handleMoveLogic(touchPoint);
198     },
199 
200     onTouchEnded: function (touchPoint) {
201         ccs.UILayout.prototype.onTouchEnded.call(this,touchPoint);
202         this.handleReleaseLogic(touchPoint);
203     },
204 
205     onTouchCancelled: function (touchPoint) {
206         ccs.UILayout.prototype.onTouchCancelled.call(this,touchPoint);
207     },
208 
209     onTouchLongClicked: function (touchPoint) {
210 
211     },
212 
213     update: function (dt) {
214         if (this._autoScroll) {
215             this.autoScrollChildren(dt);
216         }
217         this.recordSlidTime(dt);
218     },
219 
220     /**
221      * direction setter
222      * @param {ccs.ListViewDirection} dir
223      */
224     setDirection: function (dir) {
225         this._direction = dir;
226     },
227 
228     /**
229      * direction getter
230      * @param {ccs.ListViewDirection} dir
231      */
232     getDirection: function () {
233         return this._direction;
234     },
235 
236     resetProperty: function () {
237         var arrayChildren = this._children;
238 
239         if (arrayChildren.length <= 0) {
240             return;
241         }
242 
243         switch (this._direction) {
244             case ccs.ListViewDirection.vertical: // vertical
245                 if (this._topBoundary == 0) {
246                     return;
247                 }
248                 break;
249 
250             case ccs.ListViewDirection.horizontal: // horizontal
251                 if (this._rightBoundary == 0) {
252                     return;
253                 }
254                 break;
255 
256             default:
257                 break;
258         }
259 
260         var scroll_top = this._topBoundary;
261         var scroll_left = this._leftBoundary;
262 
263         switch (this._children.length) {
264             case 1:
265             {
266                 var child_0 = arrayChildren[0];
267 
268                 switch (this._direction) {
269                     case ccs.ListViewDirection.vertical: // vertical
270                     {
271                         var child_0_top = child_0.getTopInParent();
272                         this._disBoundaryToChild_0 = scroll_top - child_0_top;
273                     }
274                         break;
275 
276                     case ccs.ListViewDirection.horizontal: // horizontal
277                     {
278                         var child_0_left = child_0.getLeftInParent();
279                         this._disBoundaryToChild_0 = child_0_left - scroll_left;
280                     }
281                         break;
282 
283                     default:
284                         break;
285                 }
286             }
287                 break;
288 
289             default:
290             {
291                 var child_0 = arrayChildren[0];
292                 var child_1 = arrayChildren[1];
293 
294                 switch (this._direction) {
295                     case ccs.ListViewDirection.vertical: // vertical
296                     {
297                         var child_0_top = child_0.getTopInParent();
298                         this._disBoundaryToChild_0 = scroll_top - child_0_top;
299                         this._disBetweenChild = child_0.getPosition().y - child_1.getPosition().y;
300                     }
301                         break;
302 
303                     case ccs.ListViewDirection.horizontal: // horizontal
304                     {
305                         var child_0_left = child_0.getLeftInParent();
306                         this._disBoundaryToChild_0 = child_0_left - scroll_left;
307                         this._disBetweenChild = child_1.getPosition().x - child_0.getPosition().x;
308                     }
309                         break;
310 
311                     default:
312                         break;
313                 }
314             }
315                 break;
316         }
317     },
318 
319     handlePressLogic: function (touchPoint) {
320         var nsp = this._renderer.convertToNodeSpace(touchPoint);
321 
322         switch (this._direction) {
323             case ccs.ListViewDirection.vertical: // vertical
324                 this._touchMoveStartLocation = nsp.y;
325                 this._touchStartLocation = nsp.y;
326                 break;
327 
328             case ccs.ListViewDirection.horizontal: // horizontal
329                 this._touchMoveStartLocation = nsp.x;
330                 this._touchStartLocation = nsp.x;
331                 break;
332 
333             default:
334                 break;
335         }
336         this.startRecordSlidAction();
337         this.clearCollectOverArray();
338     },
339 
340     handleMoveLogic: function (touchPoint) {
341         var nsp = this._renderer.convertToNodeSpace(touchPoint);
342         var offset = 0;
343 
344         switch (this._direction) {
345             case ccs.ListViewDirection.vertical: // vertical
346             {
347                 var moveY = nsp.y;
348                 offset = moveY - this._touchMoveStartLocation;
349                 this._touchMoveStartLocation = moveY;
350 
351                 if (offset < 0) {
352                     this._moveDirection = ccs.ListViewMoveDirection.down; // down
353                 }
354                 else if (offset > 0) {
355                     this._moveDirection = ccs.ListViewMoveDirection.up; // up
356                 }
357             }
358                 break;
359 
360             case ccs.ListViewDirection.horizontal: // horizontal
361             {
362                 var moveX = nsp.x;
363                 offset = moveX - this._touchMoveStartLocation;
364                 this._touchMoveStartLocation = moveX;
365 
366                 if (offset < 0) {
367                     this._moveDirection = ccs.ListViewMoveDirection.left; // left
368                 }
369                 else if (offset > 0) {
370                     this._moveDirection = ccs.ListViewMoveDirection.right; // right
371                 }
372             }
373                 break;
374 
375             default:
376                 break;
377         }
378         this.scrollChildren(offset);
379     },
380 
381     handleReleaseLogic: function (touchPoint) {
382         var nsp = this._renderer.convertToNodeSpace(touchPoint);
383 
384         switch (this._direction) {
385             case ccs.ListViewDirection.vertical: // vertical
386                 this._touchEndLocation = nsp.y;
387                 break;
388 
389             case ccs.ListViewDirection.horizontal: // horizontal
390                 this._touchEndLocation = nsp.x;
391                 break;
392 
393             default:
394                 break;
395         }
396         this.endRecordSlidAction();
397     },
398 
399     /**
400      * Intercept touch event
401      * @param {number} handleState
402      * @param {ccs.UIWidget} sender
403      * @param {cc.Point} touchPoint
404      */
405     interceptTouchEvent: function (handleState, sender, touchPoint) {
406         switch (handleState) {
407             case 0:
408                 this.handlePressLogic(touchPoint);
409                 break;
410             case 1:
411                 var offset = 0;
412                 switch (this._direction) {
413                     case ccs.ListViewDirection.vertical: // vertical
414                         offset = Math.abs(sender.getTouchStartPos().y - touchPoint.y);
415                         break;
416                     case ccs.ListViewDirection.horizontal: // horizontal
417                         offset = Math.abs(sender.getTouchStartPos().x - touchPoint.x);
418                         break;
419                     default:
420                         break;
421                 }
422                 if (offset > this._childFocusCancelOffset) {
423                     sender.setFocused(false);
424                     this.handleMoveLogic(touchPoint);
425                 }
426                 break;
427             case 2:
428                 this.handleReleaseLogic(touchPoint);
429                 break;
430 
431             case 3:
432                 break;
433         }
434     },
435 
436     /**
437      *
438      * @param {number} handleState
439      * @param {ccs.UIWidget} sender
440      * @param {cc.Point} touchPoint
441      */
442     checkChildInfo: function (handleState, sender, touchPoint) {
443         this.interceptTouchEvent(handleState, sender, touchPoint);
444     },
445 
446     moveChildren: function (offset) {
447         switch (this._direction) {
448             case ccs.ListViewDirection.vertical: // vertical
449                 var arrayChildren = this._children;
450                 for (var i = 0; i < arrayChildren.length; i++) {
451                     var child = arrayChildren[i];
452                     var pos = child.getPosition();
453                     child.setPosition(cc.p(pos.x, pos.y + offset));
454                 }
455                 break;
456             case ccs.ListViewDirection.horizontal: // horizontal
457                 var arrayChildren = this._children;
458                 for (var i = 0; i < arrayChildren.length; i++) {
459                     var child = arrayChildren[i];
460                     var pos = child.getPosition();
461                     child.setPosition(cc.p(pos.x + offset, pos.y));
462                 }
463                 break;
464             default:
465                 break;
466         }
467     },
468 
469     scroll_VERTICAL_UP:function(realOffset){
470         realOffset = Math.min(realOffset, this._disBetweenChild);
471 
472         var child_last = this._childPool[this._childPool.length - 1];
473         var child_last_bottom = child_last.getBottomInParent();
474         var scroll_bottom = this._bottomBoundary;
475 
476         if (this._end == this._dataLength - 1) {
477             if (realOffset > scroll_bottom + this._disBoundaryToChild_0 - child_last_bottom) {
478                 realOffset = scroll_bottom + this._disBoundaryToChild_0 - child_last_bottom;
479             }
480             this.moveChildren(realOffset);
481             return false;
482         }
483         this.moveChildren(realOffset);
484 
485         if (this._end < this._dataLength - 1) {
486             this.collectOverTopChild();
487             var count = this._overTopArray.length;
488             if (count > 0) {
489                 this.updateChild();
490                 this.setLoopPosition();
491                 this._overTopArray = [];
492             }
493         }
494     },
495     scroll_VERTICAL_DOWN:function(realOffset){
496         realOffset = Math.max(realOffset, -this._disBetweenChild);
497 
498         var child_0 = this._childPool[0];
499         var child_0_top = child_0.getTopInParent();
500         var scroll_top = this._topBoundary;
501 
502         if (this._begin == 0) {
503             if (realOffset < scroll_top - this._disBoundaryToChild_0 - child_0_top) {
504                 realOffset = scroll_top - this._disBoundaryToChild_0 - child_0_top;
505             }
506             this.moveChildren(realOffset);
507             return false;
508         }
509         this.moveChildren(realOffset);
510 
511         if (this._begin > 0) {
512             this.collectOverBottomChild();
513             var count = this._overBottomArray.length;
514             if (count > 0) {
515                 this.updateChild();
516                 this.setLoopPosition();
517                 this._overBottomArray = [];
518             }
519         }
520     },
521     scroll_HORIZONTAL_LEFT:function(realOffset){
522         realOffset = Math.max(realOffset, -this._disBetweenChild);
523 
524         var child_last = this._childPool[this._childPool.length - 1];
525         var child_last_right = child_last.getRightInParent();
526         var scroll_right = this._rightBoundary;
527 
528         if (this._end == this._dataLength - 1) {
529             if (realOffset < scroll_right - this._disBoundaryToChild_0 - child_last_right) {
530                 realOffset = scroll_right - this._disBoundaryToChild_0 - child_last_right;
531             }
532             this.moveChildren(realOffset);
533             return false;
534         }
535         this.moveChildren(realOffset);
536 
537         if (this._end < this._dataLength - 1) {
538             this.collectOverLeftChild();
539             var count = this._overLeftArray.length;
540             if (count > 0) {
541                 this.updateChild();
542                 this.setLoopPosition();
543                 this._overLeftArray = [];
544             }
545         }
546     },
547     scroll_HORIZONTAL_RIGHT:function(realOffset){
548         realOffset = Math.min(realOffset, this._disBetweenChild);
549 
550         var child_0 = this._childPool[0];
551         var child_0_left = child_0.getLeftInParent();
552         var scroll_left = this._leftBoundary;
553 
554         if (this._begin == 0) {
555             if (realOffset > scroll_left + this._disBoundaryToChild_0 - child_0_left) {
556                 realOffset = scroll_left + this._disBoundaryToChild_0 - child_0_left;
557             }
558             this.moveChildren(realOffset);
559             return false;
560         }
561         this.moveChildren(realOffset);
562 
563         this.collectOverRightChild();
564         var count = this._overRightArray.length;
565         if (count > 0) {
566             this.updateChild();
567             this.setLoopPosition();
568             this._overRightArray = [];
569         }
570     },
571     scrollChildren: function (touchOffset) {
572         var realOffset = touchOffset;
573 
574         switch (this._direction) {
575             case ccs.ListViewDirection.vertical: // vertical
576                 switch (this._moveDirection) {
577                     case ccs.ListViewMoveDirection.up: // up
578                         this.scroll_VERTICAL_UP(realOffset);
579                         break;
580                     case ccs.ListViewMoveDirection.down: // down
581                         this.scroll_VERTICAL_DOWN(realOffset);
582                         break;
583                     default:
584                         break;
585                 }
586                 return true;
587                 break;
588 
589             case ccs.ListViewDirection.horizontal: // horizontal
590                 switch (this._moveDirection) {
591                     case ccs.ListViewMoveDirection.left: // left
592                         this.scroll_HORIZONTAL_LEFT(realOffset);
593                         break;
594                     case ccs.ListViewMoveDirection.right: // right
595                         this.scroll_HORIZONTAL_RIGHT(realOffset);
596                         break;
597                     default:
598                         break;
599                 }
600                 return true;
601                 break;
602             default:
603                 break;
604         }
605         return false;
606     },
607 
608     autoScrollChildren: function (dt) {
609         switch (this._direction) {
610             case ccs.ListViewDirection.vertical: // vertical
611                 switch (this._moveDirection) {
612                     case ccs.ListViewMoveDirection.up: // up
613                         var curDis = this.getCurAutoScrollDistance(dt);
614                         if (curDis <= 0) {
615                             curDis = 0;
616                             this.stopAutoScrollChildren();
617                         }
618                         if (!this.scrollChildren(curDis)) {
619                             this.stopAutoScrollChildren();
620                         }
621                         break;
622 
623                     case ccs.ListViewMoveDirection.down: // down
624                         var curDis = this.getCurAutoScrollDistance(dt);
625                         if (curDis <= 0) {
626                             curDis = 0;
627                             this.stopAutoScrollChildren();
628                         }
629                         if (!this.scrollChildren(-curDis)) {
630                             this.stopAutoScrollChildren();
631                         }
632                         break;
633 
634                     default:
635                         break;
636                 }
637                 break;
638 
639             case ccs.ListViewDirection.horizontal: // horizontal
640                 switch (this._moveDirection) {
641                     case ccs.ListViewMoveDirection.left: // left
642                         var curDis = this.getCurAutoScrollDistance(dt);
643                         if (curDis <= 0) {
644                             curDis = 0;
645                             this.stopAutoScrollChildren();
646                         }
647                         if (!this.scrollChildren(-curDis)) {
648                             this.stopAutoScrollChildren();
649                         }
650                         break;
651 
652                     case ccs.ListViewMoveDirection.right: // right
653                         var curDis = this.getCurAutoScrollDistance(dt);
654                         if (curDis <= 0) {
655                             curDis = 0;
656                             this.stopAutoScrollChildren();
657                         }
658                         if (!this.scrollChildren(curDis)) {
659                             this.stopAutoScrollChildren();
660                         }
661                         break;
662 
663                     default:
664                         break;
665                 }
666                 break;
667 
668             default:
669                 break;
670         }
671     },
672 
673     getCurAutoScrollDistance: function (dt) {
674         this._autoScrollOriginalSpeed -= this._autoScrollAcceleration * dt;
675         return this._autoScrollOriginalSpeed * dt;
676     },
677 
678     startAutoScrollChildren: function (v) {
679         this._autoScrollOriginalSpeed = v;
680         this._autoScroll = true;
681     },
682 
683     stopAutoScrollChildren: function () {
684         this._autoScroll = false;
685         this._autoScrollOriginalSpeed = 0;
686     },
687 
688     recordSlidTime: function (dt) {
689         if (this._bePressed) {
690             this._slidTime += dt;
691         }
692     },
693 
694     startRecordSlidAction: function () {
695         if (this._children.length <= 0) {
696             return;
697         }
698         if (this._autoScroll) {
699             this.stopAutoScrollChildren();
700         }
701         this._bePressed = true;
702         this._slidTime = 0.0;
703     },
704 
705     endRecordSlidAction: function () {
706         if (this._children.length <= 0) {
707             return;
708         }
709         if (this._slidTime <= 0.016) {
710             return;
711         }
712         var totalDis = 0;
713         totalDis = this._touchEndLocation - this._touchStartLocation;
714         var orSpeed = Math.abs(totalDis) / (this._slidTime);
715         this.startAutoScrollChildren(orSpeed / 4);
716 
717         this._bePressed = false;
718         this._slidTime = 0.0;
719     },
720 
721     getCheckPositionChild: function () {
722         var child = null;
723 
724         switch (this._direction) {
725             case ccs.ListViewDirection.vertical: // vertical
726                 switch (this._moveDirection) {
727                     case ccs.ListViewMoveDirection.up: // up
728                         child = this._childPool[this._childPool.length];
729                         break;
730 
731                     case ccs.ListViewMoveDirection.down: // down
732                         child = this._childPool[0];
733                         break;
734 
735                     default:
736                         break;
737                 }
738                 break;
739 
740             case ccs.ListViewDirection.horizontal: // horizontal
741                 switch (this._moveDirection) {
742                     case ccs.ListViewMoveDirection.left: // left
743                         child = this._childPool[this._childPool.length];
744                         break;
745 
746                     case ccs.ListViewMoveDirection.right: // right
747                         child = this._childPool[0];
748                         break;
749 
750                     default:
751                         break;
752                 }
753                 break;
754 
755             default:
756                 break;
757         }
758 
759         return child;
760     },
761 
762     initChildWithDataLength: function (length) {
763         this._dataLength = length;
764         this._begin = 0;
765         this._end = 0;
766 
767         // init child pool
768         var arrayChildren = this._children;
769         for (var i = 0; i < arrayChildren.length; ++i) {
770             var child = arrayChildren[i];
771             this.setUpdateChild(child);
772             this.setUpdateDataIndex(i);
773             this.initChildEvent();
774             this._childPool.push(child);
775             this._end = i;
776         }
777     },
778 
779     getChildFromUpdatePool: function () {
780         var child = this._updatePool.pop();
781         return child;
782     },
783 
784     pushChildToPool: function () {
785         switch (this._direction) {
786             case ccs.ListViewDirection.vertical: // vertical
787                 switch (this._moveDirection) {
788                     case ccs.ListViewMoveDirection.up: // up
789                         var child = this._childPool.shift();
790                         cc.ArrayAppendObjectToIndex(this._updatePool,child,0);
791                         break;
792                     case ccs.ListViewMoveDirection.down: // down
793                         var child = this._childPool.pop();
794                         cc.ArrayAppendObjectToIndex(this._updatePool,child,0);
795                         break;
796                     default:
797                         break;
798                 }
799                 break;
800 
801             case ccs.ListViewDirection.horizontal: // horizontal
802                 switch (this._moveDirection) {
803                     case ccs.ListViewMoveDirection.left: // left
804                         var child = this._childPool.shift();
805                         cc.ArrayAppendObjectToIndex(this._updatePool,child,0);
806                         break;
807 
808                     case ccs.ListViewMoveDirection.right: // right
809                         var child = this._childPool.pop();
810                         cc.ArrayAppendObjectToIndex(this._updatePool,child,0);
811                         break;
812 
813                     default:
814                         break;
815                 }
816                 break;
817 
818             default:
819                 break;
820         }
821     },
822 
823     getAndCallback: function () {
824         var child = this.getChildFromUpdatePool();
825 
826         if (child == null) {
827             return;
828         }
829 
830         switch (this._direction) {
831             case ccs.ListViewDirection.vertical: // vertical
832                 switch (this._moveDirection) {
833                     case ccs.ListViewMoveDirection.up: // up
834                         ++this._end;
835                         this.setUpdateChild(child);
836                         this.setUpdateDataIndex(this._end);
837                         this.updateChildEvent();
838 
839                         if (this._updateSuccess == false) {
840                             --this._end;
841                             cc.ArrayAppendObjectToIndex(this._childPool, child, 0);
842                             return;
843                         }
844                         ++this._begin;
845                         break;
846 
847                     case ccs.ListViewMoveDirection.down: // down
848                         --this._begin;
849                         this.setUpdateChild(child);
850                         this.setUpdateDataIndex(this._begin);
851                         this.updateChildEvent();
852 
853                         if (this._updateSuccess == false) {
854                             ++this._begin;
855                             this._childPool.push(child);
856                             return;
857                         }
858                         --this._end;
859                         break;
860 
861                     default:
862                         break;
863                 }
864                 break;
865 
866             case ccs.ListViewDirection.horizontal: // horizontal
867                 switch (this._moveDirection) {
868                     case ccs.ListViewMoveDirection.left: // left
869                         ++this._end;
870                         this.setUpdateChild(child);
871                         this.setUpdateDataIndex(this._end);
872                         this.updateChildEvent();
873 
874                         if (this._updateSuccess == false) {
875                             --this._end;
876                             cc.ArrayAppendObjectToIndex(this._childPool, child, 0);
877                             return;
878                         }
879                         ++this._begin;
880                         break;
881 
882                     case ccs.ListViewMoveDirection.right: // right
883                         --this._begin;
884                         this.setUpdateChild(child);
885                         this.setUpdateDataIndex(this._begin);
886                         this.updateChildEvent();
887 
888                         if (this._updateSuccess == false) {
889                             ++this._begin;
890                             this._childPool.push(child);
891                             return;
892                         }
893                         --this._end;
894                         break;
895 
896                     default:
897                         break;
898                 }
899                 break;
900 
901             default:
902                 break;
903         }
904 
905         switch (this._direction) {
906             case ccs.ListViewDirection.vertical: // vertical
907                 switch (this._moveDirection) {
908                     case ccs.ListViewMoveDirection.up: // up
909                         this._childPool.push(child);
910                         break;
911 
912                     case ccs.ListViewMoveDirection.down: // down
913                         cc.ArrayAppendObjectToIndex(this._childPool, child, 0);
914                         break;
915 
916                     default:
917                         break;
918                 }
919                 break;
920 
921             case ccs.ListViewDirection.horizontal: // horizontal
922                 switch (this._moveDirection) {
923                     case ccs.ListViewMoveDirection.left: // left
924                         this._childPool.push(child);
925                         break;
926                     case ccs.ListViewMoveDirection.right: // right
927                         cc.ArrayAppendObjectToIndex(this._childPool, child, 0);
928                         break;
929 
930                     default:
931                         break;
932                 }
933                 break;
934 
935             default:
936                 break;
937         }
938     },
939 
940     getDataLength: function () {
941         return this._dataLength;
942     },
943 
944     getUpdateChild: function () {
945         return this._updateChild;
946     },
947 
948     setUpdateChild: function (child) {
949         this._updateChild = child;
950     },
951 
952     getUpdateDataIndex: function () {
953         return this._updateDataIndex;
954     },
955 
956     setUpdateDataIndex: function (index) {
957         this._updateDataIndex = index;
958     },
959 
960     getUpdateSuccess: function () {
961         return this._updateSuccess;
962     },
963 
964     setUpdateSuccess: function (sucess) {
965         this._updateSuccess = sucess;
966     },
967 
968     clearCollectOverArray: function () {
969         switch (this._direction) {
970             case ccs.ListViewDirection.vertical:
971                 this._overTopArray = [];
972                 this._overBottomArray = [];
973                 break;
974 
975             case ccs.ListViewDirection.horizontal:
976                 this._overLeftArray = [];
977                 this._overRightArray = [];
978                 break;
979 
980             default:
981                 break;
982         }
983     },
984 
985     collectOverTopChild: function () {
986         var scroll_top = this._topBoundary;
987 
988         var arrayChildren = this._children;
989         for (var i = 0; i < arrayChildren.length; ++i) {
990             var child = arrayChildren[i];
991             var child_bottom = child.getBottomInParent();
992 
993             if (child_bottom >= scroll_top)
994                 this._overTopArray.push(child);
995         }
996     },
997 
998     collectOverBottomChild: function () {
999         var scroll_bottom = this._bottomBoundary;
1000 
1001         var arrayChildren = this._children;
1002         for (var i = 0; i < arrayChildren.length; ++i) {
1003             var child = arrayChildren[i];
1004             var child_top = child.getTopInParent();
1005 
1006             if (child_top <= scroll_bottom)
1007                 this._overBottomArray.push(child);
1008         }
1009     },
1010 
1011     collectOverLeftChild: function () {
1012         var scroll_left = this._leftBoundary;
1013 
1014         var arrayChildren = this._children;
1015         for (var i = 0; i < arrayChildren.length; ++i) {
1016             var child = arrayChildren[i];
1017             var child_right = child.getRightInParent();
1018             if (child_right <= scroll_left)
1019                 this._overLeftArray.push(child);
1020         }
1021     },
1022 
1023     collectOverRightChild: function () {
1024         var scroll_right = this._rightBoundary;
1025 
1026         var arrayChildren = this._children;
1027         for (var i = 0; i < arrayChildren.length; ++i) {
1028             var child = arrayChildren[i];
1029             var child_left = child.getLeftInParent();
1030             if (child_left >= scroll_right)
1031                 this._overRightArray.push(child);
1032         }
1033     },
1034 
1035     setLoopPosition: function () {
1036         switch (this._direction) {
1037             case ccs.ListViewDirection.vertical: // vertical
1038                 switch (this._moveDirection) {
1039                     case ccs.ListViewMoveDirection.up: // up
1040                         var arrayChildren = this._children;
1041                         if (this._overTopArray.length == arrayChildren.length) {
1042                             var count = arrayChildren.length;
1043                             for (var i = 0; i < count; ++i) {
1044                                 var child = this._overTopArray[i];
1045 
1046                                 if (i == 0) {
1047                                     var height = child.getSize().height;
1048                                     var offset = (child.getWidgetType() == ccs.WidgetType.widget) ? height / 2 : height;
1049                                     var y = this._topBoundary - this._disBoundaryToChild_0 - offset;
1050                                     child.setPosition(cc.p(child.getPosition().x, y));
1051                                 }
1052                                 else {
1053                                     var prev_child = this._overTopArray[i - 1];
1054                                     child.setPosition(cc.p(child.getPosition().x, prev_child.getPosition().y - this._disBetweenChild));
1055                                 }
1056                             }
1057                         }
1058                         else {
1059                             var scroll_top = this._topBoundary;
1060 
1061                             var arrayChildren = this._children;
1062                             for (var i = 0; i < arrayChildren.length; ++i) {
1063                                 var child = arrayChildren[i];
1064                                 var child_bottom = child.getBottomInParent();
1065 
1066                                 if (child_bottom >= scroll_top) {
1067                                     var index = (i == 0) ? (arrayChildren.length - 1) : (i - 1);
1068                                     var prev_child = arrayChildren[index];
1069                                     child.setPosition(cc.p(child.getPosition().x, prev_child.getPosition().y - this._disBetweenChild));
1070                                 }
1071                             }
1072                         }
1073                         break;
1074 
1075                     case ccs.ListViewMoveDirection.down: // down
1076                         var arrayChildren = this._children;
1077                         var childrenCount = arrayChildren.length;
1078                         if (this._overBottomArray.length == childrenCount) {
1079                             var count = childrenCount;
1080                             for (var i = 0; i < count; ++i) {
1081                                 var child = this._overBottomArray[i];
1082 
1083                                 if (i == 0) {
1084                                     var y = this._bottomBoundary + this._disBoundaryToChild_0 - this._disBetweenChild;
1085                                     child.setPosition(cc.p(child.getPosition().x, y));
1086                                 }
1087                                 else {
1088                                     var prev_child = this._overBottomArray[i - 1];
1089                                     child.setPosition(cc.p(child.getPosition().x, prev_child.getPosition().y + this._disBetweenChild));
1090                                 }
1091                             }
1092                         }
1093                         else {
1094                             var scroll_bottom = this._bottomBoundary;
1095 
1096                             var arrayChildren = this._children;
1097                             var count = arrayChildren.length;
1098                             for (var i = count - 1; i >= 0; --i) {
1099                                 var child = arrayChildren[i];
1100                                 var child_top = child.getTopInParent();
1101 
1102                                 if (child_top <= scroll_bottom) {
1103                                     var index = (i == count - 1) ? 0 : (i + 1);
1104                                     var next_child = arrayChildren[index];
1105                                     child.setPosition(cc.p(child.getPosition().x, next_child.getPosition().y + this._disBetweenChild));
1106                                 }
1107                             }
1108                         }
1109                         break;
1110 
1111                     default:
1112                         break;
1113                 }
1114                 break;
1115 
1116             case ccs.ListViewDirection.horizontal: // horizontal
1117                 switch (this._moveDirection) {
1118                     case ccs.ListViewMoveDirection.left: // left
1119                         var arrayChildren = this._children;
1120                         var childrenCount = arrayChildren.length;
1121 
1122                         if (this._overLeftArray.length == childrenCount) {
1123                             var count = childrenCount;
1124                             for (var i = 0; i < count; ++i) {
1125                                 var child = this._overLeftArray[i];
1126 
1127                                 if (i == 0) {
1128                                     var width = child.getSize().width;
1129                                     var offset = (child.getWidgetType() == ccs.WidgetType.widget) ? (width / 2) : 0;
1130                                     var x = this._leftBoundary + this._disBoundaryToChild_0 + width + offset;
1131                                     child.setPosition(cc.p(x, child.getPosition().y));
1132                                 }
1133                                 else {
1134                                     var prev_child = this._overLeftArray[i - 1];
1135                                     child.setPosition(cc.p(prev_child.getPosition().x + this._disBetweenChild, child.getPosition().y));
1136                                 }
1137                             }
1138                         }
1139                         else {
1140                             var scroll_left = this._leftBoundary;
1141 
1142                             var arrayChildren = this._children;
1143                             var count = arrayChildren.length;
1144                             for (var i = 0; i < count; ++i) {
1145                                 var child = arrayChildren[i];
1146                                 var child_right = child.getRightInParent();
1147 
1148                                 if (child_right <= scroll_left) {
1149                                     var index = (i == 0) ? (count - 1) : (i - 1);
1150                                     var prev_child = arrayChildren[index];
1151                                     child.setPosition(cc.p(prev_child.getPosition().x + this._disBetweenChild, child.getPosition().y));
1152                                 }
1153                             }
1154                         }
1155                         break;
1156 
1157                     case ccs.ListViewMoveDirection.right: // right
1158                         var arrayChildren = this._children;
1159                         var childrenCount = arrayChildren.length;
1160 
1161                         if (this._overRightArray.length == childrenCount) {
1162                             var count = childrenCount;
1163                             for (var i = 0; i < count; ++i) {
1164                                 var child = this._overRightArray[i];
1165 
1166                                 if (i == 0) {
1167                                     var x = this._rightBoundary - this._disBoundaryToChild_0 + this._disBetweenChild;
1168                                     child.setPosition(cc.p(x, child.getPosition().y));
1169                                 }
1170                                 else {
1171                                     var prev_child = this._overRightArray[i - 1];
1172                                     child.setPosition(cc.p(prev_child.getPosition().x - this._disBetweenChild, child.getPosition().y));
1173                                 }
1174                             }
1175                         }
1176                         else {
1177                             var scroll_right = this._rightBoundary;
1178 
1179                             var arrayChildren = this._children;
1180                             var count = arrayChildren.length;
1181                             for (var i = count - 1; i >= 0; --i) {
1182                                 var child = arrayChildren[i];
1183                                 var child_left = child.getLeftInParent();
1184 
1185                                 if (child_left >= scroll_right) {
1186                                     var index = (i == count - 1) ? 0 : (i + 1);
1187                                     var next_child = arrayChildren[index];
1188                                     child.setPosition(cc.p(next_child.getPosition().x - this._disBetweenChild, child.getPosition().y));
1189                                 }
1190                             }
1191                         }
1192                         break;
1193 
1194                     default:
1195                         break;
1196                 }
1197                 break;
1198 
1199             default:
1200                 break;
1201         }
1202     },
1203 
1204     updateChild: function () {
1205         switch (this._direction) {
1206             case ccs.ListViewDirection.vertical: // vertical
1207                 switch (this._moveDirection) {
1208                     case ccs.ListViewMoveDirection.up: // up
1209                         var count = this._overTopArray.length;
1210                         for (var i = 0; i < count; ++i) {
1211                             this.pushChildToPool();
1212                             this.getAndCallback();
1213                         }
1214                         break;
1215 
1216                     case ccs.ListViewMoveDirection.down: // down
1217                         var count = this._overBottomArray.length;
1218                         for (var i = 0; i < count; ++i) {
1219                             this.pushChildToPool();
1220                             this.getAndCallback();
1221                         }
1222                         break;
1223                     default:
1224                         break;
1225                 }
1226                 break;
1227 
1228             case ccs.ListViewDirection.horizontal: // horizontal
1229                 switch (this._moveDirection) {
1230                     case ccs.ListViewMoveDirection.left: // left
1231                         var count = this._overLeftArray.length;
1232                         for (var i = 0; i < count; ++i) {
1233                             this.pushChildToPool();
1234                             this.getAndCallback();
1235                         }
1236                         break;
1237                     case ccs.ListViewMoveDirection.right: // right
1238                         var count = this._overRightArray.length;
1239                         for (var i = 0; i < count; ++i) {
1240                             this.pushChildToPool();
1241                             this.getAndCallback();
1242                         }
1243                         break;
1244                     default:
1245                         break;
1246                 }
1247                 break;
1248             default:
1249                 break;
1250         }
1251     },
1252 
1253     initChildEvent: function () {
1254         if (this._eventListener && this._eventSelector) {
1255             this._eventSelector.call(this._eventListener, this, ccs.ListViewEventType.init_child);
1256         }
1257     },
1258 
1259     updateChildEvent: function () {
1260         if (this._eventListener && this._eventSelector) {
1261             this._eventSelector.call(this._eventListener, this, ccs.ListViewEventType.update_child);
1262         }
1263     },
1264 
1265     /**
1266      * @param {Function} selector
1267      * @param {Object} target
1268      */
1269     addEventListenerListView: function (selector, target) {
1270         this._eventSelector = selector;
1271         this._eventListener = target;
1272     },
1273 
1274     /**
1275      * Returns the "class name" of widget.
1276      * @returns {string}
1277      */
1278     getDescription: function () {
1279         return "ListView";
1280     }
1281 });
1282 /**
1283  * allocates and initializes a UIListView.
1284  * @constructs
1285  * @return {ccs.UIListView}
1286  * @example
1287  * // example
1288  * var uiListView = ccs.UIListView.create();
1289  */
1290 ccs.UIListView.create = function () {
1291     var uiListView = new ccs.UIListView();
1292     if (uiListView && uiListView.init()) {
1293         return uiListView;
1294     }
1295     return null;
1296 };