当前位置: 首页 > 知识库问答 >
问题:

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

殳勇
2023-03-14

我不能使用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个答案

谷梁建中
2023-03-14

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

它将是这样开始的:

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

运行动画后会是这样的:

你将能够点击“点击我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
    }

}
 类似资料:
  • 我正在用python编写一个蛇游戏,蛇可以向上、向左和向右移动,当我试图向下移动时(使用箭头)总是会出错。我正在处理碰撞,因为蛇会与自身碰撞(蛇头接触身体),屏幕将显示“游戏结束-你输了”。

  • 我的图表数据正在工作,但我希望Y轴从低于我的最低值开始,延伸到高于最大值一点,我正在查看Yax-

  • 我正在为我的游戏设计一个区块旋转组件,我遇到了一个我无法理解的小问题。基本上,我希望能够沿所有三个轴旋转网格组件。玩家一次只能旋转一个轴,旋转90度或-90度。我还希望玩家始终根据世界的X、Y和Z轴旋转网格,而不是块的相对轴,它将随着旋转而改变。我如何做到这一点? 无旋转的网格: 网格沿X轴逆时针旋转90度: 这里的问题是,如果我想沿着Y轴旋转块,相反,它将沿着Z轴旋转块,因为块现在被旋转。我如何

  • 我想使用chartjs折线图来可视化我的数据点。默认情况下,Chartjs似乎会为图形设置动画,但不会为x轴上的值设置动画。x轴仅以离散步骤移动。 是否有任何方法也可以启用轴上的动画? 谢谢

  • 问题内容: 我在jsf应用程序中使用来遍历人员列表。我不使用,因为每个人都有自己的标签(primefaces)。JSF英雄“BalusC”已经在这一环节上帮助了我。现在,我尝试保存(回发)数据。这不适用于,永远不会调用Person对象的适当设置器。有了它的作品。显然,我还没有掌握两个标签之间的区别,因此我将给您一些启发。 谢谢 马塞尔 问题答案: 不在服务器上构建JSF树节点。您可以直接在html

  • 问题内容: 考虑以下示例: 我不确定Java语言规范中是否有一项规定要加载变量的先前值以便与右侧()进行比较,该变量应按照方括号内的顺序进行计算。 为什么第一个表达式求值,而第二个表达式求值?我本来希望先被评估,然后再与自身()比较并返回。 这个问题与Java表达式中子表达式的求值顺序不同,因为这里绝对不是“子表达式”。需要 加载 它以进行比较,而不是对其进行“评估”。这个问题是特定于Java的,