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