Cocos2d-x学习之---关于CCScrollView
新版本之后,命名取消了CC前缀,功能变动都不太大。目前发现的一个改动是,ScrollViewDelegate中只有方法了,分别是scrollViewDidScroll和scrollViewDidZoom,之前公司里用的是2.0.4的版本,里面还有一个scrollViewTouchEnd的方法,不知道在2.0.4版本中的这个方法是公司里的人加进去的,还是在新版本中官方去掉了这个代理。反正影响也不是很大吧。本文默认ScrollView是垂直拖动
OK了,回到正题,在这里主要是想记录下工作中在用ScrollView时自己觉得需要注意的一些问题:
- 第一个是:ScrollView创建时用到的Size参数,这个Size设置的是ScrollView的Size,即我们创建的ScrollView的大小,如我们创建时传的参数是:Size(320,480),那么这个ScrollView的Size便是320*480。源码中在创建的init方法中使用:this->setViewSize(size);来设置ScrollView的size,因此如果我们要改变这个ScrollView的显示大小,便需要setViewSize来改变。
- 第二个是:用ScrollView的时候,我们经常会调用:setContentSize和setContentOffSet这两个方法来设置ScrollView的一些属性,在这里这两个设置方法都是对ScrollView的container进行设置(ScrollView是将child加在container上,用这个container来控制滑动等,因此加入我们要得到ScrollView的child,首先需要getContainer在getChild等,这个container是一个Layer)。回到正题,setContentSize即设置的是container的ContenSize(Layer创建的时候,如果没有设置contentsize的话,那么会默认设置为设备的分辨率大小,即:如果是320*480的分辨率,那么Layer默认的contensize便是320*480);setContenOffSet设置的是container的显示偏移量(即假如container的position是(0,0),如果我设置了OffSet为(0,10),那么container的默认显示位置会在(0,10)的位置,这个可以使得加载ScrollView的时候,我们可以控制初始显示的内容,即我们是要现实ScrollView底部的或者是顶部的内容,这个要根据实际使用中将child加入到ScrollView的方式,即如果摆放)。因为ScrollView是以左下角为坐标原点,因此在加child到ScrollView中时,实际是"一个一个往上顶(最先加的在最下边,当然可以通过事先计算出所有child加上去后的最大pos,然后根据child的size去算最高点的pos,然后将第一个加的child的pos设置为最高点pos,之后的类推 Orz,说的好麻烦。。。)"。
- 第三个是:setContentSize有啥用呢?上文提到了,这个设置的是ScrollView的container的方法,因此这个时候改变的是container的size,然后前文又提到了,ScrollView是通过container来控制拖动,拖动回移等操作的。刚开始用的时候不太明白是怎么实现的,随着自己使用了多次ScrollView,也渐进式的理解了点。首先,ScrollView会根据container的size来判断我们能否拖动(即拖动了之后不会回移),假如container的size比ScrollView的ViewSize要小,即加到ScrollView上的内容显示没有超过我们之前设定的ViewSize的大小,那么这个时候是不需要拖动ScrollView来显示其余内容的,因为内容都已经加载了。那如果container的Size比ScrollView的ViewSize更大,即这个时候有内容没有显示出来,那么这个时候就需要拖动ScrollView来显示其余没有显示出来的内容,这个时候ScrollView就可以被拖动了(即我们拖动之后不会回移)。那么或许会有疑问,怎么来控制是否回移呢?在源码中有这么一段代码:
void ScrollView::deaccelerateScrolling(float dt) { if (_dragging) { this->unschedule(schedule_selector(ScrollView::deaccelerateScrolling)); return; } float newX, newY; Point maxInset, minInset; _container->setPosition(_container->getPosition() + _scrollDistance); if (_bounceable) { maxInset = _maxInset; minInset = _minInset; } else { maxInset = this->maxContainerOffset(); minInset = this->minContainerOffset(); } newX = _container->getPosition().x; newY = _container->getPosition().y; _scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE; this->setContentOffset(Point(newX,newY)); if ((fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST) || newY >= maxInset.y || newY <= minInset.y || newX >= maxInset.x || newX <= minInset.x) { this->unschedule(schedule_selector(ScrollView::deaccelerateScrolling)); this->relocateContainer(true); } }
这个便是在我们拖动结束后,控制ScrollView的拖动缓冲、是否要拖动回移的定时器。可以看到:这里有两个值maxInset和minInset,这两个值的差值决定了ScrollView能拖动的范围,引擎便是通过这两个值来控制是否要回移(回移,我的理解就是是否要在拖动完ScrollView之后再更新一次container的位置(更新值也跟这两个最大最小值有关),引擎的依据就是如果这两个值一样,那么就是要回移的,因为拖动范围为0),这两个值的得到方法具体就是:Point ScrollView::maxContainerOffset() { return Point(0.0f, 0.0f); } Point ScrollView::minContainerOffset() { return Point(_viewSize.width - _container->getContentSize().width*_container->getScaleX(), _viewSize.height - _container->getContentSize().height*_container->getScaleY()); }
最大值就是0,0坐标,最小值是根据ViewSize和container的ContentSize的差值来计算的。这个中间转来转去的在计算,反正我个人通俗点的理解就是,假如container的size小于ViewSize,那么最大和最小值都是(0,0),即container的移动范围就是(0,0)-(0,0)之间,所以拖动完之后就要回移(重新调整container的坐标),如果container的size大于ViewSize,minInset就是ViewSize减去container的size,得到的就是移动范围。如:ViewSize是(320,480),container的size是(320,500),那么container的移动范围就是(0,0)-(0,-20)之间,即我们可以将ScrollView向下拖动20个像素,超过这个值变会将ScrollView的container的位置回移到(0,-20),向上超了(0,0)就会回移到(0,0),这就大概完成了拖动回移等操作。因此总的来看,要根据所有child组成的ContentSize来设置container的size,这样总的拖动范围就是一个正确值。 - 另外还有一个我个人表达不明白的要点。各个child的pos值y值一定要大于0,最好是最底部的坐标点的y值是等于0的(如果以正常的一个一个顶上去的方法设置pos,则没这个必要,有必要的是我们以上文提到的那个罗嗦的方法设置pos的情况)。这种情况下就不会出现,container的size设置是正确的,滑动范围也是正确的,可以就是觉得ScrollView偏移了。具体表现就是:如果下偏移,那么就是最底部的pos的y值是小于0的,如果出现了严重的上偏移,那么就是最底部的pos的y值大于0比较严重,这个可以通过打印各个pos来查看。
- 当我们以上面提到的那个罗嗦方法设置pos的时候,我想显示最顶部的内容咋办,那就是setContentOffSet的值来实现,具体设置的值是ViewSize减去container的size后得到的值,这个是我个人提供的一个参考。
说了这么多,差不多把工作中用ScrollView时需要注意的地方说的差不多了吧,这样一番理解之后,以后再使用ScrollView应该不会凭感觉是设置一些值,然后乱猜了,而是有依据的去设置,以提高工作效率。
如果以后发现了错误,再更正吧~!