写这篇文章的目的主要是为了要研究自定义控件页面的手势滑动滚动动画的原理
本文不考虑IOS和安卓系统自带的手势函数实现,这里以IOS为例
核心就是计算手势的有效速度
方法就是查询最后释放结束点到前面0.1s左右的点的位移差和时间差,用于计算手势速度
主要采用以下几个函数进行实现
下面给出伪代码的实现方式
安卓套用对应的响应函数应该也能实现
-------------------以下是伪代码实现.h--------------------
//用于记录位置和时间点
@interface YPosTime: NSObject
@property (nonatomic) CFAbsoluteTime lTime;
@property (nonatomic) double y;
@end
//自定义的控件
@interface YourCustomControl
//用于存储位置和时间点(也就是YPosTime)
@property (nonatomic, readwrite, strong) NSMutableArray *sarray_pos;
@property CGPoint movebegintouchPoint;
@property CGPoint begintouchPoint;
@property CGPoint endtouchPoint;
@property (nonatomic) CFAbsoluteTime startclickTime;
@end
-------------------以下是伪代码实现.m--------------------
//附带一个缓动函数
/*
t 指缓动效果开始执行到当前帧开始执行时经过的时间段
d 缓动效果持续的总时间。
b 起始位置
c 要移动的距离,就是终点位置减去起始位置。
return 返回该帧效果位置
*/
double MotionCircEaseOut(double t, double d, double b, double c)
{
return c * sqrt(1 - (t = t / d - 1) * t) + b;
}
@implementation YourCustomControl
//自行定义的定时器函数,用于处理滚动动画
-(void) timerTaskHandler
{
if(_nbScrollAnimation)
{
//设定滚动的时间 vy就是最后求出的手势速度 800.0是设定的最大值
double durtime=0.3 + 0.9*fabs(vy)/800.0;
//利用缓动函数求出当前的位置 _t_time是当前动画运行的时间
double dy=MotionCircEaseOut(_t_time ,durtime,0, vy);
--下面应该是伪代码
--设定视图元素的位置
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
_movebegintouchPoint = [touch locationInView:self.sysView];
_begintouchPoint= [touch locationInView:self.sysView];
_startclickTime=CFAbsoluteTimeGetCurrent();
if(self.sarray_pos) [self.sarray_pos removeAllObjects];
else self.sarray_pos =[[NSMutableArray alloc]init];
YPosTime *yPos_time =[[YPosTime alloc]init];
yPos_time.lTime=0;
yPos_time.y=_begintouchPoint.y;
[_sarray_pos addObject:yPos_time];
if([self InScrollAnimation])
{
//再次点击判断是否处于动画中,并立即停止滚动
[self StopScrollAnimation];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
_endtouchPoint= [touch locationInView:self.sysView];
CFAbsoluteTime dstime = (CFAbsoluteTimeGetCurrent() - _startclickTime);
YPosTime *yPos_time =[[YPosTime alloc]init];
yPos_time.lTime=dstime;
yPos_time.y=_endtouchPoint.y;
[_sarray_pos addObject:yPos_time];
double vy=0;
double vytime=999999;//设定的查询最大值
YPosTime *lpfind=nil;
//主要用于查询最后结束点到前面0.1s左右的位移和时间,用于计算手势速度
for(int i=0;i<_sarray_pos.count;i++)
{
YPosTime *lpf = [_sarray_pos objectAtIndex:i];
double dtime=fabs((dstime-0.1)-lpf.lTime);
if(dtime<vytime)
{
if((dstime-lpf.lTime)==0) continue;
vytime=dtime;
lpfind=lpf;
//后面的120值 可以根据需求修改 SW_H是设备像素高度
vy=-((_endtouchPoint.y-lpf.y)/SW_H)/(dstime-lpf.lTime)*120;
}
NSLog(@">> y:%lf t:%lf",lpf.y,lpf.lTime);
}
//800是设定最大速度 可以根据需求修改
if(vy>800) vy=800;
if(vy<-800) vy=-800;
NSLog(@"最终手势速度:%lf ",vy);
if(fabs(vy)>10)//可以根据需求修改
{
//当>10的时候 才开始滚动动画
[self StartScrollAnimation:vy];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//记录
CGPoint touchPoint2 = [touch locationInView:self.sysView];
CFAbsoluteTime dstime = (CFAbsoluteTimeGetCurrent() - _startclickTime);
YPosTime *yPos_time =[[YPosTime alloc]init];
yPos_time.lTime=dstime;
yPos_time.y=touchPoint2.y;
[_sarray_pos addObject:yPos_time];
//用于记录的点避免超过300,防止意外
if(_sarray_pos.count>=300)
{
YPosTime *lpf= [_sarray_pos objectAtIndex:0];
[_sarray_pos removeObject:lpf];
}
//这里可以处理跟随手指移动的视图元素位置设置
}
@end