从零开始のcocos2dx生活(十)ScrollView
文章目录
- 概述
- 核心参数
- ScrollViewDelegate
-
滑动方向
-
拖拽状态
-
显示区域
-
触控移动事件
-
可弹出的
-
触控长度
-
创建
-
设置内容大小
-
减速滚动效果
-
最大偏移量范围和最小偏移量范围(maxContainerOffset 和 minContainerOffset)
-
触摸的各阶段
-
- onTouchBegan
- onTouchMoved
- onTouchEnded
-
简介
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
其子节点用于展示所有内容,在此位置完成滚动。
inset分为_minInset和_maxInsets两种类型;当进行bounceback设置时,默认会将该值设定为offset boundary与visual area的20%之和。
_touchMoved
标记处于被拖动状态,在onTouchMoved事件中会被置为true,在onTouchEnded和onTouchCancelled事件中会被设置为false
_bounceable
反弹,在初始化时默认设置为true的情况下,则表示当物体滑动至容器边界后会持续移动一小段距离最终被反弹回边界位置的一种效果
_touchLength
用来计算两个触摸点之间的距离,会换算成缩放的倍数
#方法
create
在创建过程中,请您提供一个已配置好的container作为参数,并将其与滚动视图关联起来;随后,请您通过调用initWithViewSize方法来进行滚动视图的初始化。
initWithViewSize
初始化时调用
如果没有传入container参数会创建一个
setContentSize
该方法的主要目的是设定容器尺寸,并重新设置了InSet的范围为0至100%。在调用setContentSize函数之前,minInSet和maxInSet初始值均为0,因此无需预先设定这些参数.通过调用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参数,在松手前一帧内触点移动的距离将被用于计算触点位移量。随后将容器当前位置累加scrollDistance更新位置,并将其乘以一个参数使其逐步减小从而实现逐渐减速抛出效果
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),除非是又重新设置了。
这一部分内容较为复杂,在图形界面设计中涉及较多的操作逻辑。最大容器偏移量表示为人手操作时将容器左边缘向外拉伸的距离或位置关系。
minContainerOffset表示的是container相对于view左边界的偏移量,并且这个偏移量为负数。具体而言,在代码实现中它是通过计算viewSize减去容器的实际尺寸来确定的。

向左滑动是minContainerOffset
向右滑动是maxContainerOffset
触摸的各阶段
onTouchBegan
1、要求触摸点是一个或者两个,没有在移动,包含在view的区域内
如果未包含touches数组中,则加入以确保后续判断触点数量的准确性
当进行单个触控操作时,touch movement event被设置为false。拖拽动作被设置为true。滚动距离被设置为0。触点长度被设置为0。
4、如果是两点缩放,会记录初始状态时的 两点中点位置 和 两点之间的距离
onTouchMoved
单点触摸
1、获取这一帧内触摸点的移动距离
2、对三种不同的拖动方向,判断拖动的距离是否超出偏移范围
3、如果是第一次touchMoved并且长度小于设定的值,直接返回
当touchMoved首次发生时会将moveDistance初始化为0;其实际效果不可察觉。
5、记录了新的触摸点,将touchMoved设为true
6、对三种不同的拖动方向,分别设置了移动距离
7、设置新的移动偏移
两点缩放
1、获取当前两点之间的距离
通过计算 当前缩放因子 乘以 当前两点间的距离 除以 开始时两点间的距离 来确定 设置缩放参数 并将其传入 setZoomScale 函数中
setZoomScale
计算当前两个触控点之间的中段位置
2、
//在缩放前将触摸点中点坐标转换到节点坐标系
oldCenter = _container->convertToNodeSpace(center);
//执行缩放
_container->setScale(MAX(_minScale, MIN(_maxScale, s)));
//因为是按照(0,0)点缩放的,原来的触摸中点会发生改变,这个时候重新转换触摸中点的位置到世界坐标系
newCenter = _container->convertToWorldSpace(oldCenter);
3、计算缩放前后的触摸点中点的差值,作为偏移量
4、使用容器的位置加偏移量作为容器的新偏移
onTouchEnded
借助accelerateScrolling功能,在每次触摸结束后会调用该功能以达成甩出效果。
