从零开始のcocos2dx生活(十)ScrollView

简介: 从零开始のcocos2dx生活(十)ScrollView

简介

scrollView是在一定可视范围内通过滚动看到更大范围的方法,可视的范围是绑定在滚动视图上的容器。

容器有两个界限,一个是容器偏移,一个是为了回弹设置的延伸的长度。

基础变量

ScrollViewDelegate

设置委托函数实例,继承并重写下面的方法,可以在滚动和缩放时使用回调函数

virtual void scrollViewDidScroll(ScrollView* view) {};
virtual void scrollViewDidZoom(ScrollView* view) {};
//使用
scrollView->setDelegate(this);   ///<添加委托
virtual void scrollViewDidScroll(ScrollView* view) 
{
  /*  */
}

Direction

设置滚动的方向

enum class Direction
    {
        NONE = -1,
        HORIZONTAL = 0,
        VERTICAL,
        BOTH
    };

_dragging

是否开始拖动的标志,在onTouchBegan时会设为true,表示开始拖动,在onTouchEnded、onTouchCancelled中设为false

_container

作为scrollView的子节点,存放显示的所有内容,滚动视图的滚动框就是在这个上面进行滚动的。Inset

inset分为_minInset和_maxInset,如果设置了回弹会被设置成偏移边界加上可视范围的20%

_touchMoved

标记正在拖动的标志,在onTouchMoved时被设为true,在onTouchEnded、onTouchCancelled中设为false

_bounceable

回弹,在初始化时默认被设为true,是指在滑动到container的边界之后,会继续滑动一截最后再弹回到边界处的一种效果。

_touchLength

用来计算两个触摸点之间的距离,会换算成缩放的倍数

方法

create

创建的时候可以将设置好的设置好的container作为参数,将容器绑定到滚动视图中,然后调用initWithViewSize方法来初始化滚动视图

initWithViewSize

初始化时调用

如果没有传入container参数会创建一个

setContentSize

这个方法主要是为了设置容器的大小,同时也刷新了Inset的大小,在调用setContentSize之前,minInset和maxInset都是0,没有被设置,setContentSize会调用updateInset方法,对minInset和maxInset进行了设置,让回弹可以进行,让deaccelerateScrolling可以获得正确的值。

void ScrollView::setContentSize(const Size & size)
{
    if (this->getContainer() != nullptr)
    {
        this->getContainer()->setContentSize(size);
        this->updateInset();
    }
}
void ScrollView::updateInset()
{
    if (this->getContainer() != nullptr)
    {
      _maxInset = this->maxContainerOffset();
      _maxInset.set(_maxInset.x + _viewSize.width * INSET_RATIO,
      _maxInset.y + _viewSize.height * INSET_RATIO);
 
      _minInset = this->minContainerOffset();
      _minInset.set(_minInset.x - _viewSize.width * INSET_RATIO,
      _minInset.y - _viewSize.height * INSET_RATIO);
    }
}

deaccelerateScrolling

在onTouchEnded中会调用这个方法来实现甩出的效果。在onTouchMoved中设置了scrollDistance参数,意思是松手前一帧内触摸点移动的距离,每次会将容器当前的位置加上scrollDisdtance更新位置,然后再将这个距离乘以一个参数让它变小,实现甩出逐渐减速的效果。

void ScrollView::deaccelerateScrolling(float /*dt*/)
{
    if (_dragging)
    {
        this->unschedule(CC_SCHEDULE_SELECTOR(ScrollView::deaccelerateScrolling));
        return;
    }
    
    float newX, newY;
    Vec2 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(Vec2(newX,newY));
    
    //减速并回弹至设定最大偏移处
    //移动是否小于预定值
    //位置是否超出设定的延伸量
    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);
    }
}

maxContainerOffset 和 minContainerOffset

代码中有些地方对container的锚点和忽略锚点影响重新设置了,但不管怎么设置,它的锚点都是(0, 0)。

所以可以知道maxContainerOffset一直是都是(0, 0),除非是又重新设置了。

这里其实有些难理解,最大容器偏移量指的是手指(鼠标)按住向右滑动,container的左边界相对于view的左边界的偏移。

对于minContainerOffset来说也是container的左边界相对于view的左边界的偏移,其值是负值,从代码来看是viewSize - 容器的大小。

向左滑动是minContainerOffset

向右滑动是maxContainerOffset

触摸的各阶段

onTouchBegan

1、要求触摸点是一个或者两个,没有在移动,包含在view的区域内

2、如果没有加到touches数组中,就加进去,用来在后面判断触摸点个数使用

3、如果是单点触摸touchMoved设为false,dragging设为true,scrollDistance设为0,touchLength设为0

4、如果是两点缩放,会记录初始状态时的 两点中点位置 和 两点之间的距离

onTouchMoved

单点触摸

1、获取这一帧内触摸点的移动距离

2、对三种不同的拖动方向,判断拖动的距离是否超出偏移范围

3、如果是第一次touchMoved并且长度小于设定的值,直接返回

4、如果是第一次touchMoved会将moveDistance设为0,影响是对第一帧移动时的移动设为了0,实际看不出来

5、记录了新的触摸点,将touchMoved设为true

6、对三种不同的拖动方向,分别设置了移动距离

7、设置新的移动偏移

两点缩放

1、获取当前两点之间的距离

2、用 当前zoomScale * 当前两点距离 / 开始时两点距离 获得设置缩放的参数,进入到setZoomScale中

setZoomScale

1、获取当前的两个触摸点的中点,如果是触摸长度是0,则中点为可视区域的中点,否则为两触摸点中点

2、

//在缩放前将触摸点中点坐标转换到节点坐标系
oldCenter = _container->convertToNodeSpace(center);
//执行缩放
 _container->setScale(MAX(_minScale, MIN(_maxScale, s)));
//因为是按照(0,0)点缩放的,原来的触摸中点会发生改变,这个时候重新转换触摸中点的位置到世界坐标系
newCenter = _container->convertToWorldSpace(oldCenter);

3、计算缩放前后的触摸点中点的差值,作为偏移量

4、使用容器的位置加偏移量作为容器的新偏移

onTouchEnded

配合的accelerateScrolling使用,每次触摸结束会调用accelerateScrolling来实现甩出的效果。

相关文章
|
存储
CocosCreator3.8研究笔记(二十二)CocosCreator 动画系统-动画剪辑和动画组件介绍
CocosCreator3.8研究笔记(二十二)CocosCreator 动画系统-动画剪辑和动画组件介绍
632 0
|
Go API 开发工具
Go etcd 的依赖问题终于解决了。。。
Go etcd 的依赖问题终于解决了。。。
|
数据可视化 SDN Python
复动力系统 | 混沌 | Lozi 映射吸引子的可视化与交互式探索
该文介绍了一篇关于Lozi映射吸引子可视化和交互式探索的文章。Lozi映射是混沌理论中的一个模型,展示非线性动力系统的复杂性。通过Python和matplotlib,作者实现了Lozi映射的可视化,并添加交互功能,允许用户缩放以详细观察混沌吸引子。文中还给出了Lozi映射的数学定义,并提供了Python代码示例,演示如何绘制和动态调整吸引子的显示。
|
监控 Cloud Native 关系型数据库
【跨区域PolarDB-MySQL主备互通】:揭秘如何跨越万里实现数据无缝同步,打造坚不可摧的灾备体系!
【8月更文挑战第20天】阿里云PolarDB是一款兼容MySQL协议的云原生数据库服务,提供高性能与高可用性。本文介绍如何在PolarDB-MySQL中实现跨区域主备同步。首先创建主备两个集群,接着通过MySQL复制功能配置同步:获取主节点复制信息、配置备节点复制并启动复制进程。最后,通过`SHOW SLAVE STATUS\G;`监控复制状态,确保数据同步正常。此方法可提升数据的可靠性和可用性,需考虑网络条件对性能的影响。
556 0
|
图形学
【unity小技巧】受伤屏幕闪红、死亡动画、死亡黑屏效果
【unity小技巧】受伤屏幕闪红、死亡动画、死亡黑屏效果
841 2
|
负载均衡 算法 前端开发
Spring Cloud Alibaba-负载均衡
Spring Cloud Alibaba-负载均衡
Spring Cloud Alibaba-负载均衡
|
缓存 安全 Ubuntu
Linux配置代理上网
如何配置Linux代理
813 1
cocos 2.4*项目实战笔记及源码分享 —— 飞机大战小游戏
cocos 2.4*项目实战笔记及源码分享 —— 飞机大战小游戏
471 0
Cocos Creator3.8 项目实战(七)Listview 控件的实现和使用(2)
Cocos Creator3.8 项目实战(七)Listview 控件的实现和使用
322 0
|
算法 图形学 UED
【Unity 3D】AssetBundle工作流程、打包策略详解(超详细必看)
【Unity 3D】AssetBundle工作流程、打包策略详解(超详细必看)
760 0