問題在於用於動畫的計時功能。動畫應該像用戶在第一次拖動一樣快,然後迅速減速。以下代碼顯示了實現此行爲的一個非常簡單的示例。
首先,在我的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];
}
然後,在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];
}
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];
}
這是一個非常簡單的例子。你可能想要一個更好的向量獲取機制。此外,這隻會移動一個可視化組件(CALayer)。您可能需要一個UIView對象來處理來自該對象的事件。在這種情況下,您可能想要通過CALayer進行動畫處理,並分別移動實際的UIView對象。可以有多種方式來處理CALayer動畫和UIView重定位。
來源
2011-03-09 06:03:39
MHC
請輸入示例代碼? – 2011-03-10 00:52:05
我意識到'touchesMoved:withEvent:'中的動畫不適合你的情況,因爲在這種情況下,用戶在脫下手指之前不應該開始動畫。但是,我也意識到,當您提交動畫和實際開始動畫之間的時間差別不應該只是簡單地移動視圖。問題在於計時功能,所以動畫的開始應該足夠快以感覺運動是連續的。查看我的代碼更新的答案。 – MHC 2011-03-10 03:33:36