create uibutton subclass

前端 未结 5 1695
说谎
说谎 2020-11-28 14:10

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

相关标签:
5条回答
  • 2020-11-28 14:29

    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 
    
    0 讨论(0)
  • 2020-11-28 14:35

    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"
    ...
    }
    
    0 讨论(0)
  • 2020-11-28 14:45

    Favour composition over inheritance.

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

    0 讨论(0)
  • 2020-11-28 14:47

    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 讨论(0)
  • 2020-11-28 14:47

    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...

    0 讨论(0)
提交回复
热议问题