animating animate animat swift uiview uigesturerecognizer cabasicanimation

swift - animate - cómo reemplazar panGestureDidMove con una posición fija de inicio a fin



uiview animat (1)

Si desea un control preciso de la animación, puede usar CADisplayLink para hacer cualquier diseño o diseño personalizado antes de la actualización de píxeles de la pantalla. El bucle de ejecución intenta dibujar 60 fotogramas por segundo, por lo que con eso en mente puede modificar su código para simular eventos táctiles.

Necesitarás agregar algunas propiedades:

var displayLink:CADisplayLink? // let''s us tap into the drawing run loop var startTime:NSDate? // while let us keep track of how long we''ve been animating var deltaX:CGFloat = 0.0 // how much we should update in the x direction between frames var deltaY:CGFloat = 0.0 // same but in the y direction var startValue = CGPointMake(70.0, 50.0) // where we want our touch simulation to start var currentPoint = CGPoint(x:0.0, y:0.0) let endValue = CGPointMake(90.0, 150.0) // where we want our touch simulation to end

Entonces, cuando queramos que la animación se ejecute, podemos llamar:

func animate() { let duration:CGFloat = 2.0 self.currentPoint = self.startValue self.deltaX = (endValue.x - startValue.x) / (duration * 60.0) // 60 frames per second so getting the difference then dividing by the duration in seconds times 60 self.deltaY = (endValue.y - startValue.y) / (duration * 60.0) self.startTime = NSDate() self.displayLink = CADisplayLink(target: self, selector: #selector(self.performAnimation)) self.displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode) }

Esto configurará el enlace de la pantalla y determinará cuánto debe moverse nuestra simulación táctil entre fotogramas y comenzará a llamar a la función a la que se llamará antes de que cada dibujo de la pantalla performAnimation la performAnimation :

func performAnimation(){ if self.startTime?.timeIntervalSinceNow > -2 { self.updateViewsFor(self.currentPoint, translation: CGPoint(x:self.currentPoint.x - self.startValue.x, y: self.currentPoint.y - self.startValue.y)) self.currentPoint.x += self.deltaX self.currentPoint.y += self.deltaY } else { self.displayLink?.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode) self.currentPoint = self.startValue } }

Aquí comprobamos si estamos dentro de la duración de la animación. Luego llame a updateViewsFor(point:CGPoint,translation:CGPoint) que es lo que tenía en su objetivo de gesto y luego actualice nuestra simulación táctil si estamos dentro de él, de lo contrario, simplemente reiniciamos nuestras propiedades.

Finalmente,

func updateViewsFor(point:CGPoint,translation:CGPoint) { let additionalHeight = max(translation.y, 0) let waveHeight = min(additionalHeight * 0.6, maxWaveHeight) let baseHeight = minimalHeight + additionalHeight - waveHeight let locationX = point.x layoutControlPoints(baseHeight: baseHeight, waveHeight: waveHeight, locationX: locationX) updateShapeLayer() }

También puede cambiar su panGestureDidMove a:

@objc func panGestureDidMove(gesture: UIPanGestureRecognizer) { if gesture.state == .Ended || gesture.state == .Failed || gesture.state == .Cancelled { } else { self.updateViewsFor(gesture.locationInView(gesture.view), translation: gesture.translationInView(view)) } }

Editar

Hay una manera más fácil de hacerlo usando animación de fotograma clave. Pero no estoy seguro de que animará tu updateShapeLayer() . Pero para animar vistas, podemos escribir una función como:

func animate(fromPoint:CGPoint, toPoint:CGPoint, duration:NSTimeInterval) { // Essentually simulates the beginning of a touch event at our start point and the touch hasn''t moved so tranlation is zero self.updateViewsFor(fromPoint, translation: CGPointZero) // Create our keyframe animation using UIView animation blocks UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: .CalculationModeLinear, animations: { // We really only have one keyframe which is the end. We want everything in between animated. // So start time zero and relativeDuration 1.0 because we want it to be 100% of the animation UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 1.0, animations: { // we want our "touch" to move to the endValue and the translation will just be the difference between end point and start point in the x and y direction. self.updateViewsFor(toPoint, translation: CGPoint(x: toPoint.x - fromPoint.x, y: toPoint.y - fromPoint.y)) }) }, completion: { _ in // do anything you need done after the animation }) }

Esto moverá las vistas a su lugar y luego creará un fotograma clave donde terminarán las vistas y animará todo lo que haya en medio. Podríamos llamarlo así:

override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) self.animate(CGPointMake(70.0, 50.0), toPoint: CGPointMake(90.0, 150.0), duration: 2.0) }

He estado usando UIPanGestureRecognizer para reconocer toques, pero quiero reemplazarlo con una posición fija de inicio a final para mi animación. Por favor mira el código a continuación:

panGestureDidMove:

func panGestureDidMove(gesture: UIPanGestureRecognizer) { if gesture.state == .Ended || gesture.state == .Failed || gesture.state == .Cancelled { } else { let additionalHeight = max(gesture.translationInView(view).y, 0) let waveHeight = min(additionalHeight * 0.6, maxWaveHeight) let baseHeight = minimalHeight + additionalHeight - waveHeight let locationX = gesture.locationInView(gesture.view).x layoutControlPoints(baseHeight: baseHeight, waveHeight: waveHeight, locationX: locationX) updateShapeLayer() } }

layoutControlPoints:

private func layoutControlPoints(baseHeight baseHeight: CGFloat, waveHeight: CGFloat, locationX: CGFloat) { let width = view.bounds.width let minLeftX = min((locationX - width / 2.0) * 0.28, 0.0) let maxRightX = max(width + (locationX - width / 2.0) * 0.28, width) let leftPartWidth = locationX - minLeftX let rightPartWidth = maxRightX - locationX l3ControlPointView.center = CGPoint(x: minLeftX, y: baseHeight) l2ControlPointView.center = CGPoint(x: minLeftX + leftPartWidth * 0.44, y: baseHeight) l1ControlPointView.center = CGPoint(x: minLeftX + leftPartWidth * 0.71, y: baseHeight + waveHeight * 0.64) cControlPointView.center = CGPoint(x: locationX , y: baseHeight + waveHeight * 1.36) r1ControlPointView.center = CGPoint(x: maxRightX - rightPartWidth * 0.71, y: baseHeight + waveHeight * 0.64) r2ControlPointView.center = CGPoint(x: maxRightX - (rightPartWidth * 0.44), y: baseHeight) r3ControlPointView.center = CGPoint(x: maxRightX, y: baseHeight) }

Estoy tratando de reemplazar el panGestureDidMove con CABasicAnimation para animar la posición de principio a fin, algo así como el siguiente código:

let startValue = CGPointMake(70.0, 50.0) let endValue = CGPointMake(90.0, 150.0) CATransaction.setDisableActions(true) //Not necessary view.layer.bounds.size.height = endValue let positionAnimation = CABasicAnimation(keyPath:"bounds.size.height") positionAnimation.fromValue = startValue positionAnimation.toValue = endValue positionAnimation.duration = 2.0 view.layer.addAnimation(positionAnimation, forKey: "bounds")

Muchas cosas se ven afectadas a medida que cambia la posición, ¿cómo puedo lograr esto?