8

I am subclassing UIControl to compose a custom control that contains different standard controls.

For this discussion let's assume that my custom UIControl contains a UIButton only.

What I would like to achieve is that clicking anywhere in the custom UIControl generates a click event for that custom UIControl. The standard behavior is that the UIButton will process and consume (i.e. not forward) the click event.

As subclassing UIButton is discouraged, I can't really find a straightforward way of achieving this.

Any suggestions?

Beav
  • 495
  • 2
  • 5
  • 14
  • Is subclassing `UIButton` actually discouraged? I didn't see any issue with it on the [`UIButton` Class Reference](http://developer.apple.com/library/ios/#documentation/uikit/reference/UIButton_Class/UIButton/UIButton.html) except to mention the `buttonWithType:` constructor wouldn't return an instance of the subclass. – patridge Jan 31 '13 at 22:52

4 Answers4

14

I came up with a simple solution that doesn't need subclassing of the UIButton.

In the action method defined for the UIButton's TouchUpInside control event, I have added the following line of code:

[self sendActionsForControlEvents:UIControlEventTouchUpInside];

This results in the TouchUpInside control event being called, when clicking anywhere in the custom UIControl.

Beav
  • 495
  • 2
  • 5
  • 14
1

UIViews have a method called -hitTest:withEvent: that the event system uses to crawl the view hierarchy and dispatch events to subviews. If you want a parent view to gobble up all events that might otherwise be dispatched to its subviews, just override the parent's -hitTest:withEvent: with something like the following:

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
  if(CGRectContainsPoint([self bounds], point)){
    return self;
  }
  return [super hitTest:point withEvent:event];
}
richy
  • 2,716
  • 1
  • 33
  • 42
jemmons
  • 18,605
  • 8
  • 55
  • 84
0

UIButton is designed to process touch events. You can either set userInteractionEnabled to NO to have the button not accept any touches, or you can use addTarget:action:forControlEvents: on the button to have it call a method on your class when the button is touched.

BTW, where is subclassing UIButton discouraged?

Anomie
  • 92,546
  • 13
  • 126
  • 145
  • 1
    UIButton is a class cluster, which tends to complicate things. Please refer to the first comment in the following question: http://stackoverflow.com/questions/2920045/subclassing-uibutton-but-cant-access-my-properties – Beav Mar 05 '11 at 20:43
  • 1
    All that means is "don't try to use `buttonWithType:` with your custom subclass". – Anomie Mar 05 '11 at 20:48
  • I understand the purpose of userInteractionEnabled and addTarget:action:forControlEvents:. In fact I use this on the UIButton to process the TouchUpInside event. What I also want to do, however, is to forward the TouchUpInside event to the custom UIControl in which the button is positioned. In this way my custom control can trigger an action (e.g. hiding the keyboard) when clicked, regardless of whether the click was on the UIButton or elsewhere on the UIControl. – Beav Mar 05 '11 at 20:52
  • So, if subclassing UIButton is an option, I guess I could overwrite the sendAction:to:forEvent: method, so it is called on the UIButton and forwarded to the custom UIControl. – Beav Mar 05 '11 at 20:57
  • Just tried subclassing UIButton and ran into problems. Using IB I added my custom UIButton to my custom UIControl and gave it a button type of Rounded Rect. However, when running the app, it displays a custom button. As buttonType is read-only, I don't see a way of solving this in IB. Any suggestions? – Beav Mar 06 '11 at 01:14
  • What exactly is wrong with having your custom control register for UIControlEventTouchUpInside on the button? – Anomie Mar 06 '11 at 01:53
  • Nothing is wrong with that. I just needed a way to also forward the event from there. I did this using sendActionsForControlEvents, which solved my problem. – Beav Mar 06 '11 at 22:10
0

Often I find useful user interaction related tasks in UIResponder class, which is the super class of UIControl - UIButton. Read about – touchesBegan:withEvent:, – touchesMoved:withEvent:, – touchesEnded:withEvent:, – touchesCancelled:withEvent: in http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIResponder_Class/Reference/Reference.html You may find ways to customize user interaction for your UIButton. By the way, I don't think there will be any problem subclassing UIButton, no matter what you've heard, as long as your implementation is correctly added to the super class implementation, or does responsibly override it altogether.

petershine
  • 3,190
  • 1
  • 25
  • 49