Way*_*man 5 iphone objective-c touch
我需要在减速时点击并拖动屏幕上的UIView.我已经非常好地编写了用于移动具有触摸的视图的代码,但是需要对象以一定程度的惯性(一旦满足某个加速度阈值)继续移动,减速直到它停止,或者满足屏幕的边界.这不适用于游戏,而是使用一些标准的UIView控件.我正在努力解决的最大问题是加速度.
你写的任何好的算法都可以实现同样的目标吗?
编辑:
我在touchesEnded:方法上使用动画块,但是在一个人放开手指和动画开始之间有一个明显的延迟:
[UIView transitionWithView:self
duration:UI_USER_INTERFACE_IDIOM() ==
UIUserInterfaceIdiomPhone ? 0.33f : 0.33f * 2.0f
options:UIViewAnimationCurveEaseOut
animations:^(void){
if (dir == 1) // Flicked left
{
self.center = CGPointMake(self.frame.size.width * 0.5f,
self.center.y);
}
else { // Flicked right
self.center = CGPointMake(
self.superview.bounds.size.width -
(self.frame.size.width * 0.5f), self.center.y);
}
}
completion:^(BOOL finished){
// Do nothing
}];
Run Code Online (Sandbox Code Playgroud)
问题在于用于动画的计时功能.动画应该与用户在第一个中拖动一样快,并快速减速.以下代码显示了实现此行为的一个非常简单的示例.
首先,在我的touchesBegan:withEvent:方法中,我将第一个触摸位置记录到我的点缓冲区.我正在缓冲两个触摸位置以获得视图的运动矢量,并且可以有不同的方式来获取矢量.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
ivar_lastPoint[0] = [[touches anyObject] locationInView:self];
ivar_lastPoint[1] = ivar_lastPoint[0];
ivar_touchOffset.x = ivar_lastPoint[0].x - self.sprite.position.x;
ivar_touchOffset.y = ivar_lastPoint[0].y - self.sprite.position.y;
self.lastTime = [NSDate date];
}
Run Code Online (Sandbox Code Playgroud)
然后,在touchesMoved:withEvent:方法中,我更新了视图的位置.实际上,我使用CALayer而不是视图,因为我想为其动画使用自定义计时功能.因此,我根据用户更新图层的位置,并且对于给定的间隔,我更新位置缓冲区.
#define kSampleInterval 0.02f
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[CATransaction begin];
[CATransaction setDisableActions:YES];
/* First of all, move the object */
CGPoint currentPoint = [[touches anyObject] locationInView:self];
CGPoint center = self.sprite.position;
center.x = currentPoint.x - ivar_touchOffset.x;
center.y = currentPoint.y - ivar_touchOffset.y;
self.sprite.position = center;
/* Sample locations */
NSDate *currentTime = [NSDate date];
NSTimeInterval interval = [currentTime timeIntervalSinceDate:self.lastTime];
if (interval > kSampleInterval) {
ivar_lastPoint[0] = ivar_lastPoint[1];
ivar_lastPoint[1] = currentPoint;
self.lastTime = currentTime;
self.lastInterval = interval;
}
[CATransaction commit];
}
Run Code Online (Sandbox Code Playgroud)
self.sprite是我视图中CALayer对象的引用.我不需要动画来拖动,所以我通过使用CATransaction类对象禁用它.
最后,我计算向量并在touchesEnded:withEvent:方法中应用动画.在这里,我创建了一个自定义的CAMediaTimingFunction,因此它真的是"快速进入,缓出".
#define kDecelerationDuration 1.0f
#define kDamping 5.0f
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint targetPoint;
NSDate *currentTime = [NSDate date];
NSTimeInterval interval = self.lastInterval + [currentTime timeIntervalSinceDate:self.lastTime];
targetPoint.x = self.sprite.position.x + (ivar_lastPoint[1].x - ivar_lastPoint[0].x)/interval*kDecelerationDuration/kDamping;
targetPoint.y = self.sprite.position.y + (ivar_lastPoint[1].y - ivar_lastPoint[0].y)/interval*kDecelerationDuration/kDamping;
if (targetPoint.x < 0) {
targetPoint.x = 0;
} else if (targetPoint.x > self.bounds.size.width) {
targetPoint.x = self.bounds.size.width;
}
if (targetPoint.y < 0) {
targetPoint.y = 0;
} else if (targetPoint.y > self.bounds.size.height) {
targetPoint.y = self.bounds.size.height;
}
CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction functionWithControlPoints:
0.1f : 0.9f :0.2f :1.0f];
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:kDecelerationDuration] forKey:kCATransactionAnimationDuration];
[CATransaction setAnimationTimingFunction:timingFunction];
self.sprite.position = targetPoint;
[CATransaction commit];
}
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的例子.您可能需要更好的矢量获取机制.此外,这只移动一个可视组件(CALayer).您可能需要一个UIView对象来处理来自对象的事件.在这种情况下,您可能希望通过CALayer设置动画,并分别移动实际的UIView对象.可以有多种方法一起处理CALayer动画和UIView重定位.