如何用固定的起始位置替换panGestureDidMove

时间:2016-03-11 12:53:52

标签: swift uiview uigesturerecognizer cabasicanimation

我一直在使用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")

随着职位的变化,很多事情都会受到影响,我怎样才能实现这一目标?

1 个答案:

答案 0 :(得分:0)

如果想要精确控制动画,可以在屏幕像素刷新之前使用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(point:CGPoint,translation: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, waveHeight: waveHeight, 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)
    }