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?