首页 > 其他 > 详细

?Cocos2d-x 学习笔记(21.1) ScrollView “甩出”效果与 deaccelerateScrolling 方法

时间:2019-08-22 23:36:19      阅读:174      评论:0      收藏:0      [点我收藏+]

ScrollView的onTouchEnded方法会设置Timer,间隔0、延迟0、无限次数,回调函数是deaccelerateScrolling方法。说明触摸结束时,当该方法不被unschedule时将每帧执行一次。

deaccelerateScrolling方法中会判断ScrollView是否设置了回弹效果,我们先看有回弹的情况,对ScrollView不执行setContentSize时,maxInset和minInset均为0。

    if (_bounceable) //有回弹则true
    {
        maxInset = _maxInset;
        minInset = _minInset;
    }

接下来设置container位置,代码不再粘贴。

然后,该if语句第二第三个条件永远满足,那么将会执行unschedule,说明了deaccelerateScrolling将会只执行这一次。之后,当container此时超出范围时,再通过relocateContainer方法设置回弹效果,不再赘述。

if (
        (fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST) ||
        ((_direction == Direction::BOTH || _direction == Direction::VERTICAL) && (newY >= maxInset.y || newY <= minInset.y)) ||
        ((_direction == Direction::BOTH || _direction == Direction::HORIZONTAL) && (newX >= maxInset.x || newX <= minInset.x))
    )
    {
        this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
        this->relocateContainer(true);
    }

deaccelerateScrolling只执行一次,所以没有“甩出”效果。

刚才说的是有回弹且不执行setContentSize时deaccelerateScrolling方法大致流程。

当没有回弹时,maxInset和minInset被设置成container偏移范围的界限。

if (_bounceable) //false
    {
    //...
    }
else
    {
        maxInset = this->maxContainerOffset();
        minInset = this->minContainerOffset();
    }  

那么,如果拖动在范围之内,接下来if判断的3个条件中后两个将为false,我们看第一个条件:

(fabsf(_scrollDistance.x) <= SCROLL_DEACCEL_DIST && fabsf(_scrollDistance.y) <= SCROLL_DEACCEL_DIST)

_scrollDistance在if之前执行了:

_scrollDistance = _scrollDistance * SCROLL_DEACCEL_RATE;

SCROLL_DEACCEL_DIST是一个界限,当_scrollDistance绝对值小于它时,使得if第一个条件满足,执行unschedule,deaccelerateScrolling将不会在下一帧执行。

onTouchMoved结束时保存了_scrollDistance,该向量是两次Moved之差。在触摸结束后,每帧执行deaccelerateScrolling时,_scrollDistance都会乘以小于0的系数SCROLL_DEACCEL_RATE,使得_scrollDistance渐渐变小。

并且,每次deaccelerateScrolling方法开始会根据当前_scrollDistance设置container的新位置:

_container->setPosition(_container->getPosition() + _scrollDistance);

到这里,显而易见,虽然触摸结束了,但是deaccelerateScrolling将会在触摸结束后每帧执行,设置container的新位置,而每帧位置的增长都渐渐变小,实现了“甩动甩出”的效果。

当_scrollDistance小于界限值时,将会unschedule销毁Timer,deaccelerateScrolling不会在下一阵执行,我们看到的“甩出”效果就结束了。

还有一个问题,在无回弹情况下,如果“甩出”时container到了边界是如何处理的?

看deaccelerateScrolling部分代码:

    _container->setPosition(_container->getPosition() + _scrollDistance); //假设此时设置位置后越界
    
    if (_bounceable) //false
    {
    //...
    }
    else
    {
        maxInset = this->maxContainerOffset();
        minInset = this->minContainerOffset();
    }
    
    newX = _container->getPosition().x;
    newY = _container->getPosition().y;
    
    _scrollDistance     = _scrollDistance * SCROLL_DEACCEL_RATE;
    this->setContentOffset(Vec2(newX,newY)); //

container在setPosition后又用setContentOffset方法设置了一次位置。

看setContentOffset部分代码:

        if (!_bounceable)
        {
            const Vec2 minOffset = this->minContainerOffset();
            const Vec2 maxOffset = this->maxContainerOffset();
            
            offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x));
            offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y));
        }

        _container->setPosition(offset);

        if (_delegate != nullptr)
        {
            _delegate->scrollViewDidScroll(this);
        }

当没有越界时,确实是执行了两次参数一样的setPosition。

越界时,位置会被修正为边界位置setPosition。

同时,因为修正前的坐标已经越界,deaccelerateScrolling方法最后会触发unschedule,“甩出”效果终止。

总结

设置了一个在触摸结束后每帧执行的Timer。对“甩出”时每帧之间container的距离间隔,在回调函数中设为比上一帧缩小,实现了速度慢慢减小,直到到达临界点停止。

?Cocos2d-x 学习笔记(21.1) ScrollView “甩出”效果与 deaccelerateScrolling 方法

原文:https://www.cnblogs.com/deepcho/p/cocos2dx-ccscrollview-deacceleratescrolling.html

(1)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!