Subclass uibutton

I tried to subclass UIButton to turn on the activity indicator, but when I use initWithFrame: (since I subclass uibutton, I do not use buttonWithType :), the button does not appear. Also how would I set the button type in this case ?:

my view controller:

ActivityIndicatorButton *button = [[ActivityIndicatorButton alloc] initWithFrame:CGRectMake(10, 10, 300, 44)]; [button addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside]; [button setTitle:@"Older Posts..." forState: UIControlStateNormal]; [cell addSubview:button]; [button release]; 

my activityindicatorbutton class:

 #import <Foundation/Foundation.h> @interface ActivityIndicatorButton : UIButton { UIActivityIndicatorView *_activityView; } -(void)startAnimating; -(void)stopAnimating; @end @implementation ActivityIndicatorButton - (id)initWithFrame:(CGRect)frame { if (self=[super initWithFrame:frame]) { _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; _activityView.frame = CGRectOffset(_activityView.frame, 60.0f, 10.0f); [self addSubview: _activityView]; } return self; } -(void) dealloc{ [super dealloc]; [_activityView release]; _activityView = nil; } -(void)startAnimating { [_activityView startAnimating]; } -(void)stopAnimating { [_activityView stopAnimating]; } @end 
+6
objective-c iphone
source share
5 answers

You really don't want to subclass UIButton . This is a class cluster, so individual instances will look like UIRoundRectButton or some other private Apple class. What are you trying to do, does this require a subclass?

-one
source share

Enjoy composition over inheritance.

Create a UIView that contains the components you need and add them to your view.

+10
source share

I came across a similar situation and agree with Jeff that you really don't need UIButton subclasses. I solved this by subclassing UIControl and then overriding layoutSubviews to complete the entire configuration of the views I needed on my "button". This is a much simpler implementation that subclasses UIButton, as there seems to be a hidden mojo running under the hood. My implementation looked like this:

 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.opaque = YES; self.imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; [self addSubview:self.imageView]; self.textLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [self addSubview:self.textLabel]; } return self; } 

And layoutSubviews looked like this:

 - (void)layoutSubviews { [super layoutSubviews]; // Get the size of the button CGRect bounds = self.bounds; // Configure the subviews of the "button" ... } 
+5
source share

I created a custom class, preferring composition over inheritance, and it works great. My custom class has a button and it knows the MCContact object. It also draws the correct button and automatically calculates frames using the MCContact object that is being transmitted.

Example header file:

 #import <UIKit/UIKit.h> @protocol MCContactViewDelegate; @interface MCContactView : UIView { } @property (nonatomic, strong) MCContact *mcContact; @property (nonatomic, weak) id <MCContactViewDelegate> delegate; - (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate; @end @protocol MCContactViewDelegate <NSObject> - (void)contactViewButtonClicked:(MCContactView*)contactView; @end 

Implementation File:

 #import "MCContactView.h" @interface MCContactView() { UIButton *_button; } @end @implementation MCContactView - (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate { self = [super initWithFrame:CGRectZero]; if (self) { GetTheme(); _mcContact = mcContact; _delegate = delegate; _button = [UIButton buttonWithType:UIButtonTypeCustom]; UIImage *normalBackgroundImage = [[UIImage imageNamed:@"tokenNormal.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5]; [_button setBackgroundImage:normalBackgroundImage forState:UIControlStateNormal]; UIImage *highlightedBackgroundImage = [[UIImage imageNamed:@"tokenHighlighted.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5]; [_button setBackgroundImage:highlightedBackgroundImage forState:UIControlStateHighlighted]; _button.titleLabel.font = [theme contactButtonFont]; [_button setTitleColor:[theme contactButtonTextColor] forState:UIControlStateNormal]; [_button setTitleEdgeInsets:UIEdgeInsetsMake(4, 6, 4, 6)]; NSString *tokenString = ([allTrim(mcContact.name) length]>0) ? mcContact.name : mcContact.eMail; [_button setTitle:tokenString forState:UIControlStateNormal]; [_button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; CGSize size = [tokenString sizeWithFont:[theme contactButtonFont]]; size.width += 20; if (size.width > 200) { size.width = 200; } size.height = normalBackgroundImage.size.height; [_button setFrame:CGRectMake(0, 0, size.width, size.height)]; self.frame = _button.frame; [self addSubview:_button]; } return self; } - (void)buttonClicked:(id)sender { [self.delegate contactViewButtonClicked:self]; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end 
+2
source share

You have a pretty obvious problem regarding your dealloc method: [super dealloc]; must be called in your implementation END, otherwise the line after that will try to access the memory space (ivar space), which is already freed, so it will fail.

For another problem, I'm not sure if it is a good idea to put an activity monitor as a subview of a button altogether ...

+1
source share

All Articles