Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Sensheng Xu

macrumors newbie
Original poster
Sep 15, 2009
3
0
Hi guys,

I'm a beginner of iPhone Programming. I want to subclass UIButton so that I can have two labels -- one on left side for displaying title and one on right side for displaying value.

To use this new button class, I add a button in Interface Builder, then modify the the class name from UIButton to ValueButton.

My problem is, the button displays neither border nor my additional label. Here's my codes:

ValueButton.h
Code:
#import <UIKit/UIKit.h>


@interface ValueButton : UIButton {
	UILabel * valueLabel;
}

@property (nonatomic, retain) NSString * value;

@end

ValueButton.m
Code:
#import "ValueButton.h"


@implementation ValueButton

#pragma mark -

- (NSString *) value
{
	return valueLabel.text;
}

- (void) setValue:(NSString *)v
{
	valueLabel.text = v;
}


#pragma mark -

- (id) init
{
	self = [super init];
	if (self != nil) {
		valueLabel = [[UILabel alloc] init];
	}
	return self;
}

- (void) layoutSubviews
{
	[super layoutSubviews];
	
	valueLabel.frame = self.titleLabel.frame;
	self.titleLabel.textAlignment = UITextAlignmentLeft;
	valueLabel.textAlignment = UITextAlignmentRight;
	[self addSubview:valueLabel];
}

- (void)dealloc {
	[valueLabel release];
    [super dealloc];
}

Do I miss something? Please help me.
 
Couple things. When a view is built from a nib the init method that is called is initWithCoder. You can also override awakeFromNib. Your layoutSubviews method can be called any number of times. You probably shouldn't add your subview every time.
 
Thank you very much. I overrode initWithCoder function then move addSubview calling to to this function as well, and it works.

This is my latest source code of ValueButton.m file:
Code:
#import "ValueButton.h"

@implementation ValueButton

@synthesize valueLabel;

#pragma mark -

- (NSString *) title
{
	return title;
}

- (void) setTitle:(NSString *)v
{
	[v retain];
	[title release];
	title = v;
	
	[self setTitle:title forState:UIControlStateNormal];
	[self setTitle:title forState:UIControlStateHighlighted];
	[self setTitle:title forState:UIControlStateDisabled];
	[self setTitle:title forState:UIControlStateSelected];
}

- (NSString *) value
{
	return valueLabel.text;
}

- (void) setValue:(NSString *)v
{
	valueLabel.text = v;
}


#pragma mark -

- (id) initWithCoder:(NSCoder *)decoder
{
	self = [super initWithCoder:decoder];
	
	if (self != nil) {
		valueLabel = [[UILabel alloc] init];
		
		CGRect titleFrame = CGRectMake(
									   self.titleLabel.frame.origin.x + 20, 
									   self.titleLabel.frame.origin.y, 
									   self.titleLabel.frame.size.width, 
									   self.titleLabel.frame.size.height
									   );
		self.titleLabel.frame = titleFrame;
		self.titleLabel.textAlignment = UITextAlignmentLeft;
		self.titleLabel.font = [UIFont boldSystemFontOfSize:14];
				
		CGRect valueFrame = CGRectMake(
									   self.titleLabel.frame.origin.x + 80, 
									   self.titleLabel.frame.origin.y, 
									   self.frame.size.width - 100, 
									   self.titleLabel.frame.size.height
									   );
		self.valueLabel.frame = valueFrame;
		self.valueLabel.textAlignment = UITextAlignmentRight;
		self.valueLabel.backgroundColor = [UIColor clearColor];
		self.valueLabel.font = [UIFont systemFontOfSize:14];
		self.valueLabel.textColor = [UIColor blackColor];
		[self addSubview:valueLabel];
	}
	return self;
}

- (void) layoutSubviews
{
	[super layoutSubviews];
}

- (void)dealloc {
	[valueLabel release];
	[super dealloc];
}

@end

But there's still one problem, the border of the button disappear, and when I touch down on the button, the background isn't highlighted.

I've set border style of the button to "Rounded Rect", but there are nothing except two labels shown.

Do I need to override some functions else, or I have to draw a border by myself? Thank you for your help again!
 
Yes, UIButton is odd in that there is no public init method that returns a button that isn't a custom button. In IB did you set the button type to be rounded rect? I understand that you change the class to your custom class. I would expect that if you set the button to be type rounded rect your subclass should also be rounded rect.

If that doesn't work then it's a little more complicated to make this work. I haven't done this but the basic idea is to replace self with a new button inside your initWithCoder method. Something like this:

Code:
- (id) initWithCoder:(NSCoder *)decoder
{
	UIButton* b = [super initWithCoder:decoder];
	
	if (b != nil) {
             self = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            // here copy all of the button properties like frame, font, etc. from b to self
           [b release];
        }
       return self;
}

I haven't done this so this code is a little rough and there may be some additional issues to make it work.
 
Hi, PhoneyDeveloper,

Yes I've set it in IB, but it doesn't work. Your solution is really cool. I will follow this way. thank you!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.