我一直在使用UIPanGestureRecognizer来识别触摸,但我想用动画的固定开始到结束位置替换它.请参阅以下代码:
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) }
我试图用CABasicAnimation替换panGestureDidMove来设置起始位置的动画,如下面的代码:
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")
随着职位的变化,很多事情都会受到影响,我该怎样才能做到这一点?
如果您想要精确控制动画,可以使用CADisplayLink在屏幕像素刷新之前进行任何自定义布局或绘图.运行循环尝试每秒绘制60帧,因此考虑到这一点,您可以修改代码以模拟触摸事件.
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
然后,只要我们想要动画运行,我们就可以调用:
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) }
这将设置显示链接并确定我的触摸模拟应在帧之间移动多少,并开始调用在每次绘制屏幕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 } }
在这里,我们检查是否在动画的持续时间内.然后调用updateViewsFor(点:CGPoint,翻译:CGPoint),这是你在手势目标中所拥有的,然后如果我们在其中,则更新我们的触摸模拟,否则我们只是重置我们的属性.
最后,
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,locationX: locationX) updateShapeLayer() }
您还可以将panGestureDidMove更改为:
@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)) } }
编辑
使用关键帧动画有一种更简单的方法.但我不确定它会为updateShapeLayer()设置动画.但是对于动画视图,我们可以编写如下函数:
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 }) }
这会将视图移动到位,然后为视图结束的位置创建关键帧,并为其间的所有内容设置动画.我们可以称之为:
override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) self.animate(CGPointMake(70.0,50.0),toPoint: CGPointMake(90.0,150.0),duration: 2.0) }