Making an UIButton’s image tappable
In these days I’m developing again in Objective-C and yes, I have to admit, I’m a bit rusty.
Said this, the requirement I received is to create a sort of navigation bar where items
UIButtons. Each button is of type
UIButtonTypeCustom and it has a title and an image.
Ok. Easy for now. The code looks like the following.
UIImage* image = [UIImage imageNamed:@"my_image"]; [self.myButton setImage:image forState:UIControlStateNormal]; [self.myButton setTitle:@"My button" forState:UIControlStateNormal];
The “difficult” part is that both the button and the image need to be tappable. So, if I tap the image
a specific action, different from button one, is performed.
I racked my brain and I had a thought: subclassing
UIButton. Ok this could be a wonderful idea. But it’s not.
According to UIButton Edge Insets you should avoid to
subclass or reimplement
UIButton. In fact, as Richard Turton says
Not only is UIButton a class cluster, so not really suitable for subclassing, it also does a lot for you, and with judicious use of the image view, background image view and (as of iOS6) attributed titles, you can create almost any effect you want.
So, what’s the solution? A
UIButton has an
imageView property that wraps the image you have set with
setImage:forState: method. Even if this property is read-only, as stated by Apple documentation,
you can attach a tap gesture and respond appropriately. For example.
UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewTapped:)]; tapGestureRecognizer.numberOfTapsRequired = 1; self.bindableButton.imageView.userInteractionEnabled = YES; [self.bindableButton.imageView addGestureRecognizer:tapGestureRecognizer];
Since image view objects are configured to disregard user events by default, you must
explicitly change the value of the
userInteractionEnabled property to
after initializing the object.
Now within imageViewTapped: method you can retrieve the button associated with the tapped image as follows:
[[tapGestureRecognizer view] superview];