views:

4912

answers:

4

HI. I need to write some text over a custom button. So I subclassed UIButton. In -drawrect, I write the text I need. The problem is that the text ends up under the button. After I write my text, UIButton's drawrect goes ahead and draws on top of me.

I am not even calling [super drawrect: rect] even though I was anticipating calling it before I did my drawing. It seems that UIButton's drawrect will get called regardless.

Any ideas? Thanks.

+1  A: 

You don't need to subclass UIButton just to add some text to it. Here's an example of setting the button title for a custom button within the -viewDidLoad method of a UIViewController subclass:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 44, 44);
[button setTitle:@"x" forState:UIControlStateNormal];
[self.view addSubview:button];

You can also set the font property of your button or change the color using -setTitleColor:forState:.

phatblat
Let me add some detail. The button is an image that is a small circular object. If I let the default titling happen, the title appears to the right of the button, not on top of it. So I keep the title blank, and I want to draw the title on top of it. There is room for about three characters at the font size I need. But if I did the above as an example, the "x" would show up to the side of the button, not on top.
mahboudz
here's what it looks like using setTitle http://www.flickr.com/photos/glasscyclops/3495881450/
mahboudz
A: 

How about adding a subview over the button's view? Then you'd have full control over it and not care what the button did. You could probably even make it a Label and save yourself the drawRect.

dieselmcfadden
+6  A: 

As other people have said, you don't need to subclass UIButton - infact it's best not to as UIButton is pretty complex (as you found). You have three options:

  • Leave the button's title blank and add a new text field to the button at the position you want.
  • if you are using 3.0 access the button's label property. Although the label itself is read only its properties (including frame) are not.
  • Sub-class UIControl. UIControl is a UIView so you can add other views - text and images and it is UIView that implements the action message behaviour (addTarget:action:forControlEvents:). UIButton implements statefulness on top of this.

If you don't need things like UIButton's setTitle:forState: and associated functionality but you are using a lot of these controls I would use the third option. Otherwise use the first (or second if you are on 3.0).

Roger Nolan
+1  A: 

Based on your comment on one of the other answers, this is a case of asking "How do I do X with Y to achieve Z?" when you really should be asking "How do I achieve Z?"

If you want a button to draw text on top of an image instead of next to it, simply make the image the button's background image. Use setBackgroundImage:forState:, rather than setImage:forState:, then set the title normally.

In any case, you're either going to have to draw the image in drawRect:, or move the text into a subview so it'll draw above the image. The solution I mentioned is a version of the second option.

Brent Royal-Gordon
Oddly enough, when I do it this way, I still end up under the image, which is now the background image - there is no foreground image now. I believe what is happening is that my drawRect gets called, and then the super's drawRect is called, overdrawing the text I drew.
mahboudz
If you're using the background image, don't use drawRect: at all. The background image will draw above drawRect:, but you don't really need custom drawing, because the title will draw above the background image.
Brent Royal-Gordon
@mahboudz: as Brent has already said, you shouldn't be overriding -drawRect: if all you need is text over an image. Use setTitle:forState: to set the text. Your situation sounds like exactly what UIButton was intended for - why re-invent the wheel?
Nick Forge