Swift: ¿Cómo hacer una inercia suave después del paneo (arrastrar)?

He estado aprendiendo Swift 2.2 por varios días. Después de terminar el tutorial oficial, estoy tratando de hacer algunas muestras funcionales. Por ejemplo, estoy tratando de hacer un decorador de avatar.

@IBAction func moveAvatar(recognizer:UIPanGestureRecognizer) { recognizer.maximumNumberOfTouches = 1 recognizer.minimumNumberOfTouches = 1 let debugOutOfBounds = false let debugGestureRecognizer = false let debugVelocity = true if (debugGestureRecognizer) { print("pan") } let translation = recognizer.translationInView(self.avatar) let standardAvatarSize:CGFloat = Conf.Size.avatarRadius * 2 if (self.avatar.frame.width < standardAvatarSize) { self.avatar.frame = CGRect(origin: self.avatar.frame.origin, size: CGSize(width: standardAvatarSize, height:standardAvatarSize)) } if let view = recognizer.view { switch recognizer.state { case .Began: if (debugVelocity) { print("Began: velocity: \(recognizer.velocityInView(view)) translation: \(translation)") } self.panAvatarLastTranslation = translation self.avatar.center = CGPoint(x: self.avatar.center.x + translation.x, y: self.avatar.center.y + translation.y) case .Changed: if (debugVelocity) { print("Changed: velocity: \(recognizer.velocityInView(view)) translation: \(translation)") } if (translation != CGPoint(x: 0.0, y: 0.0)) { self.panAvatarLastTranslation = translation } self.avatar.center = CGPoint(x: self.avatar.center.x + translation.x, y: self.avatar.center.y + translation.y) case .Ended: if (debugVelocity) { print("Ended: velocity: \(recognizer.velocityInView(view)) translation: \(translation)") } let velocityDistance = sqrt(pow(recognizer.velocityInView(view).x, CGFloat(2)) + pow(recognizer.velocityInView(view).y, CGFloat(2))) print(velocityDistance) if (velocityDistance > 100) { let inertiaDelay: NSTimeInterval = 0.5 let inertiaDistance : CGFloat = velocityDistance * CGFloat(inertiaDelay) * 0.02 let inertiaX:CGFloat = self.panAvatarLastTranslation.x * inertiaDistance let inertiaY:CGFloat = self.panAvatarLastTranslation.y * inertiaDistance //sqrt(pow(inertiaX, CGFloat(2)) + pow(inertiaY, CGFloat(2))) //print("inertiaDelay: \(inertiaDelay)") UIView.animateWithDuration(inertiaDelay, animations: { self.avatar.center.x += inertiaX self.avatar.center.y += inertiaY }) } default: print("default") } let standardAvatarBound: [String:CGFloat] = [ "top": UIApplication.shanetworkingApplication().statusBarFrame.height + UIScreen.mainScreen().bounds.width / 2 - Conf.Size.avatarRadius, "right": UIScreen.mainScreen().bounds.width / 2 + Conf.Size.avatarRadius, "bottom": UIApplication.shanetworkingApplication().statusBarFrame.height + UIScreen.mainScreen().bounds.width / 2 + Conf.Size.avatarRadius, "left": UIScreen.mainScreen().bounds.width / 2 - Conf.Size.avatarRadius ] let avatarBound: [String:CGFloat] = [ "top": self.avatar.center.y - self.avatar.frame.height / 2, "right": self.avatar.frame.width / 2 + self.avatar.center.x, "bottom": self.avatar.center.y + self.avatar.frame.height / 2, "left": self.avatar.center.x - self.avatar.frame.width / 2 ] if (self.panAvatarLastTranslation.x < 0 && avatarBound["right"] < standardAvatarBound["right"]) { UIView.animateWithDuration(0.5, animations: { self.avatar.center.x += (standardAvatarBound["right"]! - avatarBound["right"]!) }) if (debugOutOfBounds) { print("Out of right bound") } } if(self.panAvatarLastTranslation.x > 0 && avatarBound["left"] > standardAvatarBound["left"]) { UIView.animateWithDuration(0.5, animations: { self.avatar.center.x -= (avatarBound["left"]! - standardAvatarBound["left"]!) }) if (debugOutOfBounds) { print("Out of left bound") } } if(self.panAvatarLastTranslation.y > 0 && avatarBound["top"] > standardAvatarBound["top"]) { UIView.animateWithDuration(0.5, animations: { self.avatar.center.y -= (avatarBound["top"]! - standardAvatarBound["top"]!) }) if (debugOutOfBounds) { print("Out of top bound") } } if(self.panAvatarLastTranslation.y < 0 && avatarBound["bottom"] < standardAvatarBound["bottom"]) { UIView.animateWithDuration(0.5, animations: { self.avatar.center.y += (standardAvatarBound["bottom"]! - avatarBound["bottom"]!) }) if (debugOutOfBounds) { print("Out of bottom bound") } } } recognizer.setTranslation(CGPointZero, inView: view) } 

Bien, como puedes ver, manejo la inercia de arrastre en el estado ".Ended" del reconocedor de gestos panorámicos. Funciona bien, pero no es suave. ¿Qué puedo hacer para hacer una inercia de paneo suave?

Aquí está el código fuente: https://github.com/AarioAi/NotesOpen/tree/master/Swift

Intenta usar un método diferente para animar. Demuestra este tutorial