开发者

create uibutton subclass

I tried to subclass UIButton to include an activity indicator, but when i use initWithFrame:(since i'm subclassing uibutton i'm not using buttonWithType:) the button doesn't display. 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{
    [su开发者_开发百科per dealloc];
    [_activityView release];
    _activityView = nil;
}

-(void)startAnimating {
    [_activityView startAnimating];
}

-(void)stopAnimating {
    [_activityView stopAnimating];
}
@end


Favour composition over inheritance.

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


I ran into a similar situation, and agree with Jeff that you don't really need to subclass UIButton. I solved this by subclassing UIControl, and then overriding layoutSubviews to do all of the configuration of the views I wanted on my "button". It's a much more simple implementation that subclassing UIButton since there does seem to be some hidden mojo going on 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"
...
}


I have created a custom class, preferring composition over inheritance and it works perfect. My custom class has a button and it knows it's MCContact object. Also it draws a proper button and calculates frames automatically using MCContact object, that is passed.

Header file sample:

#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 


You have a pretty obvious problem that concerns your dealloc method: [super dealloc]; must be called AT THE END of your implementation, or else the line after that will try to access a memory space (the ivar space) that has been already deallocated, so it's going to crash.

For the other problem, I'm not sure it's a good idea to put an activity monitor as the subview of a button in general...


You don’t really want to subclass UIButton. It’s a class cluster, so individual instances will be something like UIRoundRectButton or some other private Apple class. What are you trying to do that requires a subclass?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜