目标C:从UIButton类的子类创build的button不起作用

我正在创build一个UIButton的子类,以创build我自己的自定义button。 我的代码如下:

//interface file (subclass of uIButton @interface UICustomButton : UIButton { Answer *answer; NSString *btnType; } @property (nonatomic, retain) Answer *answer; @property (nonatomic, assign) NSString *btnType; - (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; - (void)buttonPressed; @end //Implementation file (.m) @implementation UICustomButton @synthesize answer,btnType; - (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; { self = [super initWithFrame:frame]; if (self) { self = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; self.backgroundColor = [UIColor colorWithHexString:@"#E2E4E7"]; } [self addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlStateNormal]; self.answer = ans; self.btnType = type; return self; } 

我在上面的代码工作中遇到了一些问题。 我有2个问题

1)button不响应select器方法“buttonPressed”

2)我打了一个行self.answer = ans'和'self.btnType =types'堆栈跟踪运行时错误如下:

 -[UIButton setAnswer:]: unrecognized selector sent to instance 0x614ebc0 2011-06-23 00:55:27.038 onethingaday[97355:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton setAnswer:]: unrecognized selector sent to instance 0x614ebc0' 

我在这里做错了什么?

这是因为你正在创build一个UIButtontypes的对象,而不是在init方法中的UICustomButtontypes

 self = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; 

尝试replace你的init方法

 - (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; { self = [self initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; if (self) { self.backgroundColor = [UIColor colorWithHexString:@"#E2E4E7"]; [self addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside]; self.answer = ans; self.btnType = type; } return self; } 

这将使self成为一个UICustomButtontypes的对象。

此外,当您使用addTarget:action:forControlEvents:将目标添加到button时,您正在使用UIControlState参数的错误typesaddTarget:action:forControlEvents: method

你应该使用下面的值:

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel


编辑: 关于UIButton子类的说明

网上有很多参考文献说你不应该UIButton类,但是不仅仅是有人说了为什么,而且还让我非常恼火的是, UIButton类的参考文档根本就没有提到它。

例如,如果您以UIWebView类参考为例,则会明确指出您不应该子类化UIWebView

子类化注意事项UIWebView类不应该被子类化。

UIButton处在于它是从UIControlinheritance而来的, UIControl Class Reference本身就是一个很好而简单的解释

子类化注意事项你可能想要扩展一个UIControl子类,原因有两个:

  • 观察或修改对特定事件的目标的动作消息的发送
  • 要提供自定义的跟踪行为(例如,更改高亮显示的外观)

所以,这意味着你可以UIButton一个UIButton ,但你应该小心你在做什么。 只是将它分类来改变它的行为,不是它的外观 。 要修改一个UIButton外观,你应该使用为其提供的接口方法,比如:

的setTitle:forState:
了setBackgroundImage:forState:
setImage:forState:

值得一读的参考

  • UIView编程指南: 视图和窗口体系结构 – >有效使用视图的提示 – >不要通过embedded子视图来自定义控件

来源: 我的post在这里

不知道这是否在文档之前,但无论如何,这些是+ (id)buttonWithType:(UIButtonType)buttonType

对我来说,只要使用init而不是buttonWithType子类化看起来就OK。 但是我还没有尝试过。

讨论这个方法是一个方便的构造器,用于创build具有特定configuration的button对象。 它是你的子类UIButton,这个方法不会返回你的子类的一个实例。 如果你想创build一个特定的子类的实例,你必须直接分配/初始化button。

当创build一个自定义button – 这是一个types为UIButtonTypeCustom的button时,button的框架最初被设置为(0,0,0,0)。 在将button添加到界面之前,应该将框架更新为更合适的值。

 // // BtnClass.m #import "BtnClass.h" @implementation BtnClass - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } //added custum properities to button -(id)initWithCoder:(NSCoder *)aDecoder { NSLog(@"initWithCoder"); self = [super initWithCoder: aDecoder]; if (self) { // Initialization code _numberOfItems=[[UILabel alloc]initWithFrame:CGRectMake(40, 8, 160, 30)]; _numberOfItems.textAlignment=NSTextAlignmentLeft; _numberOfItems.font = [UIFont boldSystemFontOfSize:18.0]; _numberOfItems.textColor = [UIColor darkGrayColor]; [self addSubview:_numberOfItems]; _leftImage=[[UIImageView alloc]initWithFrame:CGRectMake(10, 10, 25, 25)]; [self addSubview:_leftImage]; _rightImage=[[UIImageView alloc]initWithFrame:CGRectMake(280, 10, 15, 15)]; [self addSubview:_rightImage]; [self setImage:[UIImage imageNamed:@"list-bg2-1.png"] forState:UIControlStateNormal]; [_rightImage setImage:[UIImage imageNamed:@"carat.png"]]; self.backgroundColor=[UIColor blackColor]; if(self.tag==1) { [_leftImage setImage:[UIImage imageNamed:@"notes-icon.png"]]; } if(self.tag==2) { [_leftImage setImage:[UIImage imageNamed:@"photos-icon.png"]]; } if(self.tag==3) { [_leftImage setImage:[UIImage imageNamed:@"videos-icon.png"]]; } } return self; } //selected method of uibutton -(void)setSelected:(BOOL)selected { [super setSelected:selected]; if(selected) { [self setImage:nil forState:UIControlStateNormal]; _numberOfItems.textColor = [UIColor whiteColor]; [_rightImage setImage:[UIImage imageNamed:@"carat-open.png"]]; if(self.tag==1) { [_leftImage setImage:[UIImage imageNamed:@"white-notes-icon.png"]]; } else if(self.tag==2) { [_leftImage setImage:[UIImage imageNamed:@"white-photo-icon.png"]]; } else { [_leftImage setImage:[UIImage imageNamed:@"white-video-icon.png"]]; } } else{ _numberOfItems.textColor = [UIColor darkGrayColor]; if(self.tag==1) { [_leftImage setImage:[UIImage imageNamed:@"notes-icon.png"]]; } if(self.tag==2) { [_leftImage setImage:[UIImage imageNamed:@"photos-icon.png"]]; } if(self.tag==3) { [_leftImage setImage:[UIImage imageNamed:@"videos-icon.png"]]; } [self setImage:[UIImage imageNamed:@"list-bg2-1.png"] forState:UIControlStateNormal]; [_rightImage setImage:[UIImage imageNamed:@"carat.png"]]; } } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end 

如果你想在用户与你的button进行交互的时候得到通知,只需要sublcass UIButton并实现这些方法:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesBegan"); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesEnded"); } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesCancelled"); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"touchesMoved"); } 

不需要init方法。

编辑

这个答案可以追溯到几年,事情已经发生了变化 – 正如苹果公司现在明确提到子类化并给出了一些提示。

所以下面的答案对于当前的发展可能是无关紧要的或错误的,如果你对当前的技术状况感兴趣,可能会被忽略。


UIButton 并不意味着被分类。

你最好做一个类别,并定义一个工厂方法来提供你需要的button(通过调用buttonWithType:initWithFrame:不正确的方式来初始化一个button无论如何。