Ios 调用ToucheSStart时,已设置动画的UIView对象跳转

Ios 调用ToucheSStart时,已设置动画的UIView对象跳转,ios,swift,animation,touchesbegan,Ios,Swift,Animation,Touchesbegan,我有一个UILabel对象,它正在设置动画,上下移动。我使用的是Xcode 8.3和Swift 3。用户可以平移此对象并拖动到一个位置以获取一些点。我正在使用触摸xxx手势处理平移/拖动。然而,当我轻触并立即放开它时,由于某种原因,这个物体垂直地跳到了它的位置上方,我一个星期都不明白为什么 当我启用一些调试时,我只能看到调用了touchesbeated(touchesMoved没有按预期调用,也没有touchesend,这对我来说是意外的)。如果我手动禁用对象上的动画,它将按预期工作,并且可以轻

我有一个UILabel对象,它正在设置动画,上下移动。我使用的是Xcode 8.3和Swift 3。用户可以平移此对象并拖动到一个位置以获取一些点。我正在使用
触摸xxx
手势处理平移/拖动。然而,当我轻触并立即放开它时,由于某种原因,这个物体垂直地跳到了它的位置上方,我一个星期都不明白为什么

当我启用一些调试时,我只能看到调用了
touchesbeated
touchesMoved
没有按预期调用,也没有
touchesend
,这对我来说是意外的)。如果我手动禁用对象上的动画,它将按预期工作,并且可以轻松平移对象,并且显然没有对象跳跃

以下是相关代码的摘录:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    let touchLocation = touch!.location(in: self.view)

    if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
        //pauseLayer(self.optOneLbl.layer)      <<<<< comment #1
        //optOneLbl.translatesAutoresizingMaskIntoConstraints = true      <<<<< comment #2
        optOneLbl.center = touchLocation
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    let touchLocation = touch!.location(in: self.view)
    var sender: UILabel

    if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
        self.optOneLbl.center = touchLocation
        sender = self.optOneLbl
    }

    // identify which letter was overlapped
    var overlappedView : UILabel
    if (sender.frame.contains(letter1.center)) {
        ...
    }
    else {
        return
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)
}

您可以使用UIPangestureRecognitor实现同样的功能。将平移手势添加到标签,并在平移时移动标签

@IBAction func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {

        let translation = gestureRecognizer.translation(in: self.view)
        yourLabel!.center = CGPoint(x: yourLabel!.center.x + translation.x, y: yourLabel!.center.y + translation.y)
        gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
    }
}
您可以从情节提要或在viewDidLoad中以编程方式将手势识别器添加到UILabel中

let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
yourLabel.addGestureRecognizer(gestureRecognizer)

使用平移手势作为优势,您不必使用后续触摸XX方法。为了解释为什么视图会向上移动,我认为您可能也在其他地方重置了标签框。也有可能出现手势与触摸相冲突的情况。由于这两种情况在您提供的代码中都不明显,我们需要更多的代码来确认相同的情况。

更改标签位置后,您需要删除/重置动画。动画不知道您更新了值,并且从一开始就试图保持在相同的byValue范围内。下面是更新动画的工作示例

import UIKit

class ViewController: UIViewController {

    var optOneLbl = UILabel()


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.


        optOneLbl = UILabel(frame: CGRect(x: 20, y: 50, width: self.view.bounds.width - 40, height: 40))
        optOneLbl.textAlignment = .center
        optOneLbl.text = "I Will Be Moving Up and Down"
        optOneLbl.textColor = .white
        optOneLbl.backgroundColor = .blue
        self.view.addSubview(optOneLbl)

        //starts it in the beginnning with a y
        fireAnimation(toY:  self.view.bounds.midY*1.1)


    }

    func fireAnimation(toY:CGFloat) {
        UIView.animate(withDuration: 12.0, delay: 0.0, options: [ .allowUserInteraction, .curveLinear, .autoreverse, .repeat ], animations: {
            self.optOneLbl.center = CGPoint(x: self.optOneLbl.center.x, y:toY)
        })
    }



    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self.view)

        if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
            //re
            optOneLbl.layer.removeAllAnimations()
            optOneLbl.center = touchLocation
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self.view)
        var sender: UILabel

        if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
            self.optOneLbl.center = touchLocation
            sender = self.optOneLbl
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        //restart animation after finished and change the Y if you want.  
        // you could change duration or whatever
        fireAnimation(toY: self.view.bounds.height - optOneLbl.bounds.height)
    }

}
导入UIKit
类ViewController:UIViewController{
var optOneLbl=UILabel()
重写func viewDidLoad(){
super.viewDidLoad()
//加载视图后,通常从nib执行任何其他设置。
optOneLbl=UILabel(帧:CGRect(x:20,y:50,宽度:self.view.bounds.width-40,高度:40))
optOneLbl.textAlignment=.center
optOneLbl.text=“我将上下移动”
optOneLbl.textColor=.white
optOneLbl.backgroundColor=.blue
self.view.addSubview(optOneLbl)
//从一开始就用y开始
fireAnimation(玩具:self.view.bounds.midY*1.1)
}
func fireAnimation(玩具:CGFloat){
UIView.animate(持续时间:12.0,延迟:0.0,选项:[.allowUserInteraction、.curveLinear、.autoreverse、.repeat],动画:{
self.optOneLbl.center=CGPoint(x:self.optOneLbl.center.x,y:toY)
})
}
覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
让我们先接触
让touchLocation=touch!.location(在:self.view中)
如果self.optOneLbl.layer.presentation()!.hitTest(touchLocation)!=nil{
//再
optOneLbl.layer.RemoveAllianimations()
光电中心=触摸位置
}
}
覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
让我们先接触
让touchLocation=touch!.location(在:self.view中)
var发送方:UILabel
如果self.optOneLbl.layer.presentation()!.hitTest(touchLocation)!=nil{
self.optOneLbl.center=触摸位置
发送器=自发光二极管
}
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
super.touchesend(触摸,带有:事件)
//完成后重新启动动画,并根据需要更改Y轴。
//你可以改变持续时间或其他什么
fireAnimation(玩具:self.view.bounds.height-optOneLbl.bounds.height)
}
}

触摸开始后,是否应设置项目动画。也许尝试删除它,并在拖动完成后读取。实际上,让我看看动画代码。它在重复。必须设置图层的新值。移除它。拖曳然后读动画看看这个答案也许能帮你让我know@agibson007,是的,动画正在重复。我已经编辑了我的原始文章,包括动画代码。请允许我澄清一下“您必须设置图层的新值。删除它。”?谢谢你的建议。仅供参考,我以前使用的是
UIPangestureRecognitor
。但是由于在中强调的问题,我采用了当前的方法,现在有了新的挑战。哇!!非常感谢这个快速工作的代码。添加
removeAllAnimations()
解决了此问题。我原以为暂停动画是在做同样的事情,但现在我知道不是这样。@Heelara很高兴它起了作用。将动画视为在真实模型之上进行的单独电影。这个过程将在将来帮助你。
import UIKit

class ViewController: UIViewController {

    var optOneLbl = UILabel()


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.


        optOneLbl = UILabel(frame: CGRect(x: 20, y: 50, width: self.view.bounds.width - 40, height: 40))
        optOneLbl.textAlignment = .center
        optOneLbl.text = "I Will Be Moving Up and Down"
        optOneLbl.textColor = .white
        optOneLbl.backgroundColor = .blue
        self.view.addSubview(optOneLbl)

        //starts it in the beginnning with a y
        fireAnimation(toY:  self.view.bounds.midY*1.1)


    }

    func fireAnimation(toY:CGFloat) {
        UIView.animate(withDuration: 12.0, delay: 0.0, options: [ .allowUserInteraction, .curveLinear, .autoreverse, .repeat ], animations: {
            self.optOneLbl.center = CGPoint(x: self.optOneLbl.center.x, y:toY)
        })
    }



    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self.view)

        if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
            //re
            optOneLbl.layer.removeAllAnimations()
            optOneLbl.center = touchLocation
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchLocation = touch!.location(in: self.view)
        var sender: UILabel

        if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
            self.optOneLbl.center = touchLocation
            sender = self.optOneLbl
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        //restart animation after finished and change the Y if you want.  
        // you could change duration or whatever
        fireAnimation(toY: self.view.bounds.height - optOneLbl.bounds.height)
    }

}