将alpha设置为0.0后,即使重置为1.0也无法点击UIButton

时间:2018-10-09 10:19:41

标签: ios uibutton

我有这个简单的代码:

func tappedButton() {
   self.button.alpha = 1.0
    UIView.animate(withDuration: 1.0, delay: 4.0, options: .curveLinear, animations: {
        self.button.alpha = 0.0
    }) { _ in }
}

此功能旨在在隐藏按钮之前再次显示按钮4秒钟(带有1秒动画)。但是,虽然在这4秒钟内完全可见该按钮,但是点击它不再起作用。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

根据有关UIView https://developer.apple.com/documentation/uikit/uiview/1622469-hittest的hittest(_:with :)方法的文档,

  

此方法将忽略隐藏的视图对象,禁用的用户交互或alpha级别小于0.01的视图对象。确定点击时,此方法不会考虑视图的内容。因此,即使指定点位于该视图内容的透明部分中,该视图仍然可以返回。

这意味着将不会触摸任何带有alpha 0.0的视图,尤其是按钮。

但是,这里的问题是,至少对于您来说,该按钮仍然可见。之所以会出现这种 odd 行为,是因为在动画开始时,按钮的实际alpha值已经已经设置为0.0。动画通过更改视觉层次并通过为函数提供的参数转换差异来起作用。在您的情况下,您有两种状态:一个带有可见按钮的视图和另一个没有该按钮的视图。仅可视部分具有动画效果,但已经设置了相应的值。一个解决方案是:

func tappedButton() {
   self.button.alpha = 1.0
    UIView.animate(withDuration: 1.0, delay: 4.0, options: .curveLinear, animations: { [weak self] in
        self?.button.alpha = 0.01
    }) { [weak self] _ in self?.button.alpha = 0.0 }
}

编辑:此解决方案似乎很简单,但可行。我使用这种方法是因为完成处理程序总是使用true值来调用。

func tapped() {
    let duration = 1.0
    let delay = 2.0
    let delayDuration = delay + duration
    UIView.animate(withDuration: duration, delay: delay, options: [.curveLinear, .allowUserInteraction], animations: { [weak self] in
        self?.saveButton.alpha = 0.1
    })
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayDuration, execute: { [weak self] in
        self?.saveButton.alpha = 0.0
    })
}

答案 1 :(得分:0)

您需要在选项中使用allUserInteraction并检查是否有触摸。立即添加了动画,尽管您看到了系统按钮,但该按钮已被隐藏。这是什么意思?这意味着您正在看电影。但是至少在启用userInteraction的情况下,您可以检查触摸事件。很棒,但是我们如何知道按钮是否真正显示呢?好吧,您最有可能必须使用两种不同的检查。一种检查按钮的真实UIView alpha,另一种检查显示层的不透明度。我从未完全研究过UIView动画和Core Animation之间的联系,只是我认为UIView动画是Core Animations的包装。 UIView动画肯定会立即更新视图模型。因此,alpha动画很可能会解释为图层上的不透明度动画。有了此功能,我们就可以检查表示层在触摸时的不透明度,即使视图模型认为alpha为0,也可以看到单击了按钮。只要不透明度大于0,就可以在表示层进行检查。所以你去。

 import UIKit

class ViewController: UIViewController {

    lazy var testButton : UIButton = {
        let v = UIButton(frame: CGRect(x: 20, y: 50, width: self.view.bounds.width - 40, height: 50))
        v.backgroundColor = UIColor.blue
        v.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside)
        return v
    }()



    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(testButton)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        UIView.animate(withDuration: 1.0, delay: 4.0, options: .allowUserInteraction, animations: {
            self.testButton.alpha = 0
        }, completion: nil)

        //test the layer
         //test the layer for opacity
        if let presentation = testButton.layer.presentation()?.animation(forKey: "opacity"){
            print("the animation is already added so normal clicks won't work")
        }
    }

    @objc func buttonClicked(){
        print("clicked")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        if let touch = touches.first{
            let location = touch.location(in: self.view)
            if self.testButton.frame.contains(location){
                //but what you might not know is the animation is probably already running
                //and so the check above misses this
                if let buttonPres = testButton.layer.presentation(),
                    let _ = buttonPres.animation(forKey: "opacity"),
                    let opacity = buttonPres.value(forKey: "opacity") as? CGFloat{
                    if opacity > 0{
                        buttonClicked()
                    }
                }
            }
        }
    }
}