Search code examples
swiftuiviewtouchactionopacity

Is there a way to make a completely transparent UIButton that works?


I've a custom UINavigationItem title view. It has a label pushed to the top of it, which I've enabled to respond to .touchDown and send an action.

However, the taps don't register near the top of the label, presumably because the active region is clipped. So I configured another invisible view (not in navigation item), and set it up as a control, and positioned it above that navigation title view label.

However, it doesn't work unless I set the 'invisible' view's alpha to at least 0.02, because Apple seems to intentionally disable action for a view with an alpha less than that. Unfortunately, against a black screen in dark mode, the 'invisible' hitpad view shows up as a slightly grey rectangle, which is not a good aesthetic.

I guess I could go to some lengths to try to make the button background color match the screen background at that location, but it seems a bit tacky.

What alternatives might I have?


Solution

  • You can simply create a blank png image, and add it in top of your title view. make sure to set the imageView and the title view isUserInteractionEnabled properties to true:

    import UIKit
    
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .green
            let imageView = UIImageView()
            imageView.isUserInteractionEnabled = true
            let tap = UITapGestureRecognizer(
                target: self,
                action: #selector(tap)
            )
            imageView.addGestureRecognizer(tap)
            imageView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
            imageView.image = UIImage(named: "blank")
            let titleLabel = UILabel()
            titleLabel.text = "Transparent Button"
            titleLabel.autoresizingMask = [.flexibleHeight, .flexibleWidth]
            titleLabel.addSubview(imageView)
            navigationItem.titleView = titleLabel
            navigationItem.titleView?.isUserInteractionEnabled = true
        }
        @objc func tap(_ gesture: UITapGestureRecognizer) {
            print(#function)
        }
    }
    

    Sample project


    You can also just add your gesture recognizer directly to your titleView. No need for the transparent image at all unless you need to control the area of the gesture:

    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .green
            let tap = UITapGestureRecognizer(
                target: self,
                action: #selector(tap)
            )
            let titleLabel = UILabel()
            titleLabel.text = "Transparent Button"
            titleLabel.autoresizingMask = [.flexibleHeight, .flexibleWidth]
            titleLabel.addGestureRecognizer(tap)
            navigationItem.titleView = titleLabel
            navigationItem.titleView?.isUserInteractionEnabled = true
        }
        @objc func tap(_ gesture: UITapGestureRecognizer) {
            print(#function)
        }
    }