从零开始の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来实现甩出的效果。
从零开始のcocos2dx生活(十)ScrollView的更多相关文章
- 从零开始のcocos2dx生活(十一)TableView
目录 简述 主要变量 主要方法 setVerticalFillOrder reloadData cellAtIndex updateCellAtIndex insertCellAtIndex remo ...
- 从零开始のcocos2dx生活(七)ParticleSystem
CCParticleSystem是用来设置粒子效果的类 1.粒子分为两种模式:重力模式 和 半径模式 重力模式独占属性: gravity 重力方向,Vec2类型,可以分别指定不同方向的重力大小 spe ...
- 从零开始のcocos2dx生活(二)Node
节点 Node 文章目录 节点 Node 前言 变量初始化 创建一个节点对象 获取节点依赖的计数器 获取节点的描述(获取节点的Tag) 节点的局部层顺序值(LocalZOrder) 设置节点的Loca ...
- 从零开始のcocos2dx生活(九)CCBReader
NodeLoaderLibrary是用来存储节点加载器类型的类,通过registerDefaultNodeLoaders()可以注册所有默认类型的加载器 在CocosBuilder的使用手册中: 1. ...
- 从零开始のcocos2dx生活(八)ParticleSystemQuad
https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/#_1 写的真的非常好-最近没时间拜读,只看 ...
- 从零开始のcocos2dx生活(六)EventDispatcher
EventDispatcher可能是所有的里面比较不容易理解也不容易看的 我说自己的理解可能会误导到你们-[索了你们看不下去>< 我写了几乎所有的代码的注释,有的是废话跳过就好 主要的代码 ...
- 从零开始のcocos2dx生活(一)内存管理
cocos中所有的对象都是继承自Ref基类,Ref的职责就是对对象进行引用计数管理 内存管理中最重要的是三个方法retain().release().autorelease() 在cocos中创建对象 ...
- 从零开始のcocos2dx生活(五)ActionEase
文章目录 sineEaseIn sineEaseOut sineEaseInOut expoEaseIn expoEaseOut expoEaseInOut easeIn easeOut easeIn ...
- 从零开始のcocos2dx生活(四)ActionManager
文章目录 初始化构造函数 析构函数 删除哈希元素 分配存放动作对象的空间 通过索引移除动作 暂停动作 恢复动作 暂停所有的动作 恢复所有的动作 添加动作 移除所有的动作 移除target中的所有动作 ...
随机推荐
- Redis源码解析:05跳跃表
一:基本概念 跳跃表是一种随机化的数据结构,在查找.插入和删除这些字典操作上,其效率可比拟于平衡二叉树(如红黑树),大多数操作只需要O(log n)平均时间,但它的代码以及原理更简单.跳跃表的定义如下 ...
- Python基础:06条件和循环
1:条件表达式(三元操作符) Python 在很长的一段时间里没有条件表达式(C ? X : Y), 或称三元运算符.人们试着用 and 和 or 来模拟它, 但大多都是错误的. 根据 FAQ , 正 ...
- @AGC037 - E@ Reversing and Concatenating
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个长度为 N 且只包含小写字母的字符串 S ,你可以执行 ...
- 阿里云DataV专业版发布,为可视化创造更多可能!
阿里云数据可视化应用工具DataV正式推出专业版,该版本为可视化领域专业团队和从业者量身打造,定位数据可视分析大屏搭建场景,让使用者可以轻松hold住复杂交互设计和实时数据交互查询需求. 什么是Dat ...
- Android教程-01 Android Studio创建第一个项目
视频教程建议采用超清模式, 关注更多视频订阅我的优酷 最近一直使用Android Studio 简单把Android Studio介绍下 1. 首先介绍下 Android Studio的快捷键 由于之 ...
- POJ3080 Blue Jeans 题解 KMP算法
题目链接:http://poj.org/problem?id=3080 题目大意:给你N个长度为60的字符串(N<=10),求他们的最长公共子串(长度>=3). 题目分析:KMP字符串匹配 ...
- Chrome接口请求一直是pending状态,但接口实际上是正常的
1.现象 个别机器突然出现Chrome访问我司产品异常,本该通过接口获取的数据没有呈现,之前都是好好的,而且其他机器同样用同版本Chrome访问正常. 出现问题的机器重装Chrome问题依然存在,直到 ...
- theadClasses设置Bootstrap Table表头样式
通过theadClasses属性设置表头样式. thead-light设置灰色背景 //bootstrap table初始化数据 itxst.com $('#table').bootstrapTabl ...
- HDU 1271
这题做了好久..... 理解别人的代码都理解了好久!!!太弱太弱. #include<iostream> #include<algorithm> #include<cma ...
- pytorch nn.LSTM()参数详解
输入数据格式:input(seq_len, batch, input_size)h0(num_layers * num_directions, batch, hidden_size)c0(num_la ...