Reputation: 3498
This is my button:
import UIKit
class PassButton: UIButton {
var videoVC: VideoGameVC?
required init(isEnabled: Bool = false) {
super.init(frame: .zero)
self.isEnabled = true
self.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)
let imageViewBackground = UIImageView(frame: CGRect(x:0, y:0, width: 70, height: 80))
imageViewBackground.image = UIImage(named: "pass_button")
imageViewBackground.contentMode = UIView.ContentMode.scaleAspectFill
addSubview(imageViewBackground)
sendSubviewToBack(imageViewBackground)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func pressed(_ sender: UIButton) {
print("presovan")
}
}
and this is how I add it to another view controller:
func configPassButton() {
passButton = PassButton()
guard let passButton = passButton else { return }
view.addSubview(passButton)
passButton.translatesAutoresizingMaskIntoConstraints = false
passButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
passButton.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 20).isActive = true
}
it is displayed, as I want it to be, but the area which is tappable is so tiny. Only top left corner of it is tappable, and a very small one (lik, 10% of the whole surface). How can I fix so whole are is tappable?
Upvotes: 0
Views: 85
Reputation: 77423
Assuming you have a 70:80 ratio image. such as this:
Your code displays it like this:
but, as you're aware, you can only tap the upper-left.
If we add a 2-point red border to the button:
passButton.layer.borderColor = UIColor.red.cgColor
passButton.layer.borderWidth = 2
it looks like this:
the button frame is only 30 x 34
... and the 70 x 80
imageView is extending outside the bounds of the button. So, only the actual button frame can be tapped.
If you give the button width and height constraints:
passButton.widthAnchor.constraint(equalToConstant: 70.0).isActive = true
passButton.heightAnchor.constraint(equalToConstant: 80.0).isActive = true
then we see this:
and the entire button can be tapped.
Adding a UIImageView
as a subview is a terrible approach though.
Much more appropriate is to set the background image property:
// safely handle optional
if let img = UIImage(named: "pass_button") {
setBackgroundImage(img, for: [])
}
Again, we also need to set the width and height constraints, but now we are using a "standard" button instead of a subclass with added subviews:
let passButton = UIButton()
passButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(passButton)
NSLayoutConstraint.activate([
passButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
passButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20.0),
passButton.widthAnchor.constraint(equalToConstant: 70.0),
passButton.heightAnchor.constraint(equalToConstant: 80.0),
])
if let img = UIImage(named: "pass_button") {
passButton.setBackgroundImage(img, for: [])
}
If your image is not the same aspect-ratio as your button, there's a little more work to do... but, using your original code, you'd have the same problem - so I assume you're using a 70:80
aspect image to begin with.
Upvotes: 1
Reputation: 6009
Rather than adding a subview manually for the background image, perhaps use the button's .setBackgroundImage() property. Also, the frame size was set for the ImageView but, unless I overlooked it, the frame size was not set for the button itself. This may be why the button's tappable area does not fully correspond to the image size.
To fix, remove these lines that set the background image:
let imageViewBackground = UIImageView(frame: CGRect(x:0, y:0, width: 70, height: 80))
imageViewBackground.image = UIImage(named: "pass_button")
imageViewBackground.contentMode = UIView.ContentMode.scaleAspectFill
addSubview(imageViewBackground)
sendSubviewToBack(imageViewBackground)
And replace the lines above with these to set the button's background image, content mode, width and height:
self.setBackgroundImage(UIImage(named: "pass_button"), for: .normal)
self.layoutIfNeeded()
self.subviews.first?.contentMode = .scaleAspectFill
self.widthAnchor.constraint(equalToConstant: 70).isActive = true
self.heightAnchor.constraint(equalToConstant: 80).isActive = true
With those changes the button should be fully tappable.
Another option
It just occurred to me that if you want to use the imageViewBackground subview instead of .setBackgroundImage(), setting the button's size and then clipping the background image would also work. For example, adding this after sendSubviewToBack():
self.widthAnchor.constraint(equalToConstant: 70).isActive = true
self.heightAnchor.constraint(equalToConstant: 80).isActive = true
self.clipsToBounds = true
Upvotes: 2