提问者:小点点

为什么使用CABasicAnimation()沿y轴向下动画后UIButton不工作?


我不能使用UIButton IBAction后,向下动画。我尝试将它带到superview的顶层,使用

cardOneButton.superview?.bringToFront(cardOneButton)

这将按钮带到最上层,但我仍然无法使用按钮Tap触发IBAction。

我试过了

cardOneButton.isUserInteractionEnabled = true

但这个东西也不行。

cardOneButton是放置在视图中的按钮的IBOutlet的名称。

使按钮动画化的代码:

func animateCardOneButton(_ cardOneLabel: UIButton){
        let startX = cardOneButton.frame.origin.x + (cardOneButton.frame.size.width / 2)
        let startY = cardOneButton.frame.origin.y + (cardOneButton.frame.size.height / 2)
        let endX = startX
        let endY = startY + 280
        let animation = baseAnimation(startX, startY, endX, endY)
        cardOneButton.layer.add(animation, forKey: nil)
    }

其中baseAnimation(:、:、:、:)定义为:

func baseAnimation(_ startX: CGFloat, _ startY: CGFloat, _ endX: CGFloat, _ endY: CGFloat) -> CABasicAnimation{
        let animation = CABasicAnimation(keyPath: "position")
        animation.fromValue = CGPoint(x: startX, y: startY)
        animation.toValue = CGPoint(x: endX, y: endY)
        animation.duration = 0.5
        animation.fillMode = .forwards
        animation.isRemovedOnCompletion = false
        animation.beginTime = CACurrentMediaTime()
        return animation
    }

共1个答案

匿名用户

这里有一个简单的例子可以告诉你两者的区别...

它将是这样开始的:

你可以点击每一个红色按钮。

运行动画后会是这样的:

你将能够点击“点击我2”,因为我们动画它的框架而不是它的层。

你不能点击“点击我1”,因为我们动画了它的图层,但是...然后点击“Label 1”,您将看到“tap Me 1”按钮突出显示并调用其.TouchupInside操作。

那是因为“标签1”显示的是“轻拍我1”的原始帧----而且那个帧还在那里!

class ViewController: UIViewController {

    var cardOneButton: UIButton!
    var cardTwoButton: UIButton!
    var labelOne: UILabel!
    var labelTwo: UILabel!

    var runAnimButton: UIButton!
    var infoLabel2: UILabel!
    var infoLabel1: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        labelOne = UILabel()
        labelOne.text = "Label 1"
        labelOne.textAlignment = .center
        labelOne.backgroundColor = .systemTeal
        view.addSubview(labelOne)
        
        labelTwo = UILabel()
        labelTwo.text = "Label 2"
        labelTwo.textAlignment = .center
        labelTwo.backgroundColor = .systemTeal
        view.addSubview(labelTwo)
        
        infoLabel1 = UILabel()
        infoLabel1.text = "Result:"
        infoLabel1.textAlignment = .center
        infoLabel1.backgroundColor = .yellow
        infoLabel1.font = .systemFont(ofSize: 15.0)
        view.addSubview(infoLabel1)
        
        infoLabel2 = UILabel()
        var s = ""
        s += "Tap each red button...\n\n"
        s += "Then tap the Animate button...\n\n"
        s += "Then try to tap each red button...\n\n"
        s += "AND try to Tap each Label"
        infoLabel2.text = s
        infoLabel2.textAlignment = .center
        infoLabel2.numberOfLines = 0
        infoLabel2.backgroundColor = .green
        infoLabel2.font = .systemFont(ofSize: 14.0)
        view.addSubview(infoLabel2)
        
        cardOneButton = UIButton()
        cardOneButton.backgroundColor = .systemRed
        cardOneButton.setTitle("Tap Me 1", for: [])
        cardOneButton.setTitleColor(.black, for: .highlighted)
        view.addSubview(cardOneButton)
        
        cardTwoButton = UIButton()
        cardTwoButton.backgroundColor = .systemRed
        cardTwoButton.setTitle("Tap Me 2", for: [])
        cardTwoButton.setTitleColor(.black, for: .highlighted)
        view.addSubview(cardTwoButton)
        
        runAnimButton = UIButton()
        runAnimButton.backgroundColor = .lightGray
        runAnimButton.setTitle("Animate", for: [])
        runAnimButton.setTitleColor(.black, for: .highlighted)
        view.addSubview(runAnimButton)
        
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        [runAnimButton, cardOneButton, cardTwoButton].forEach { b in
            b.frame = CGRect(origin: .zero, size: CGSize(width: 120, height: 40))
        }
        
        runAnimButton.center.x = view.center.x
        runAnimButton.frame.origin.y = view.safeAreaInsets.top + 20
        
        cardOneButton.frame.origin = CGPoint(x: 40, y: runAnimButton.frame.maxY + 20)
        cardTwoButton.frame.origin = CGPoint(x: cardOneButton.frame.maxX + 40, y: runAnimButton.frame.maxY + 20)

        labelOne.frame = cardOneButton.frame
        labelTwo.frame = cardTwoButton.frame
        
        infoLabel1.frame = CGRect(x: 40, y: cardOneButton.frame.maxY + 20, width: 280, height: 30)

        let sz = infoLabel2.systemLayoutSizeFitting(CGSize(width: 280, height: 300), withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
        
        infoLabel2.frame = CGRect(x: 40, y: infoLabel1.frame.maxY + 20, width: 280, height: sz.height + 16)
        
        cardOneButton.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
        cardTwoButton.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
        
        runAnimButton.addTarget(self, action: #selector(doAnim(_:)), for: .touchUpInside)
    }

    @objc func btnTapped(_ sender: Any?) -> Void {
        guard let b = sender as? UIButton,
              let t = b.currentTitle
        else { return }
        infoLabel1.text = "Result: \(t) was tapped!"
    }
    
    @objc func doAnim(_ sender: Any?) -> Void {
        
        // original LAYER animation
        animateCardOneButton(cardOneButton)
        
        // animate frame of BUTTON itself
        animateButton(cardTwoButton)
    }

    func animateButton(_ aButton: UIButton) -> Void {

        let startY = aButton.frame.origin.y
        let endY = startY + 280

        UIView.animate(withDuration: 0.5, animations: {
            aButton.frame.origin.y = endY
        })
        
    }
    
    func animateCardOneButton(_ aButton: UIButton){
        let startX = aButton.frame.origin.x + (aButton.frame.size.width / 2)
        let startY = aButton.frame.origin.y + (aButton.frame.size.height / 2)
        let endX = startX
        let endY = startY + 280
        let animation = baseAnimation(startX, startY, endX, endY)
        aButton.layer.add(animation, forKey: nil)
    }
    
    func baseAnimation(_ startX: CGFloat, _ startY: CGFloat, _ endX: CGFloat, _ endY: CGFloat) -> CABasicAnimation{
        let animation = CABasicAnimation(keyPath: "position")
        animation.fromValue = CGPoint(x: startX, y: startY)
        animation.toValue = CGPoint(x: endX, y: endY)
        animation.duration = 0.5
        animation.fillMode = .forwards
        animation.isRemovedOnCompletion = false
        animation.beginTime = CACurrentMediaTime()
        return animation
    }

}