【问题标题】:create uibutton subclass创建 uibutton 子类
【发布时间】:2011-06-30 01:28:55
【问题描述】:

我尝试子类化 UIButton 以包含活动指示器,但是当我使用 initWithFrame:(因为我是子类化 uibutton 我没有使用 buttonWithType:) 时,按钮不显示。另外在这种情况下我将如何设置按钮类型?:

我的视图控制器:

    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];

我的活动指示器按钮类:

#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

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    支持组合而不是继承。

    创建一个 UIView ,其中包含您需要的组件并将它们添加到您的视图中。

    【讨论】:

    • 我能赶上你的漂移,我喜欢它。但如果能提供更多信息,我们将不胜感激。
    • 看我的帖子,我已经意识到了。
    【解决方案2】:

    我遇到了类似的情况,并且同意 Jeff 的观点,即您实际上不需要子类化 UIButton。我通过子类化 UIControl 解决了这个问题,然后覆盖 layoutSubviews 以在我的“按钮”上完成我想要的所有视图配置。这是一个比 UIButton 子类化的更简单的实现,因为引擎盖下似乎有一些隐藏的魔力。我的实现如下所示:

    - (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;
    }
    

    layoutSubviews 看起来像这样:

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

    【讨论】:

    • 能否再添加一些如何布局 textLabel 和 imageView 的示例?
    • 在 initWithFrame 中你可以分配/初始化 textLabel 和 imageView,并给它们两个帧 CGRectZero。在此处将它们添加为 UIControl 的子视图。在layoutSubviews中,设置label和image view的frames。
    【解决方案3】:

    我创建了一个自定义类,它更喜欢组合而不是继承,并且它工作得很好。我的自定义类有一个按钮,它知道它是 MCContact 对象。它还绘制了一个适当的按钮并使用传递的 MCContact 对象自动计算帧。

    头文件示例:

    #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
    

    实施文件:

    #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 
    

    【讨论】:

      【解决方案4】:

      您有一个与您的 dealloc 方法有关的非常明显的问题:[super dealloc];必须在实现的末尾调用,否则后面的行将尝试访问已被释放的内存空间(ivar 空间),因此它会崩溃。

      对于另一个问题,我不确定将活动监视器作为一般按钮的子视图是否是个好主意...

      【讨论】:

      • 不仅会崩溃,而且我遇到的每个例子都很难追踪。调试器没有在问题根源处中断。
      【解决方案5】:

      你并不想继承UIButton。这是一个类集群,因此单个实​​例将类似于 UIRoundRectButton 或其他一些私有 Apple 类。你想做什么需要子类?

      【讨论】:

      • 嗨,杰夫,我正在尝试将活动指示器视图放入按钮中。
      • 没问题。只需将活动指示器视图添加为按钮的子视图即可。
      • UIButton 根本不是一个类簇。一个类簇由一个公共抽象类表示,这意味着没有实例变量,有一堆私有的具体子类,它们提供抽象类的抽象方法的实现。另一方面,UIButton 是一个具体的类,它的方法都不是抽象的,它有实例变量来存储你通过它的参数传递的值。唯一有问题的部分是 +buttonWithType 可以直接实例化子类而不是 UIButton,因此可以将其视为工厂方法,而不是类集群...
      • 心理是正确的。我怎么知道?因为我继承了 UIButton 来实现我自己的按钮(基本上使用 IB 中的运行时属性来定义按钮的外观)。
      • 补充@Psycho 的评论,来自buttonWithType: doc:此方法是一个方便的构造函数,用于创建具有特定配置的按钮对象。如果您将 UIButton 子类化,则此方法不会返回您的子类的实例。如果要创建特定子类的实例,则必须直接分配/初始化按钮。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      • 1970-01-01
      • 1970-01-01
      • 2019-01-31
      • 1970-01-01
      • 1970-01-01
      • 2012-05-03
      相关资源
      最近更新 更多