How to subclas UIButton?

Discussion in 'iOS Programming' started by Sensheng Xu, Sep 15, 2009.

  1. Sensheng Xu macrumors newbie

    Joined:
    Sep 15, 2009
    #1
    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.
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    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.
     
  3. Sensheng Xu thread starter macrumors newbie

    Joined:
    Sep 15, 2009
    #3
    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!
     
  4. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #4
    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.
     
  5. Sensheng Xu thread starter macrumors newbie

    Joined:
    Sep 15, 2009
    #5
    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!
     

Share This Page