ios 目标 C:从 UIButton 类的子类创建的按钮不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6443639/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:29:47  来源:igfitidea点击:

objective C: Buttons created from subclass of UIButton class not working

objective-ciosuibutton

提问by Zhen

I am creating a subclass of UIButton in order to create my own customized buttons. My code as follows:

我正在创建 UIButton 的子类以创建我自己的自定义按钮。我的代码如下:

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

I am facing some issues in getting the above code to work. I have 2 problems

我在使上述代码工作时遇到了一些问题。我有两个问题

1) The buttons are not responding to the selector method "buttonPressed"

1)按钮没有响应选择器方法“buttonPressed”

2) I am hitting a runtime error for the lines 'self.answer = ans' and 'self.btnType = type' Stack trace as follows:

2)我遇到了“self.answer = ans”和“self.btnType = type”堆栈跟踪的运行时错误,如下所示:

-[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'

What am I doing wrong here?

我在这里做错了什么?

回答by Felipe Sabino

This is happening because you are creating a UIButtontype object and not a UICustomButtontype inside the init method when you do

发生这种情况是因为您在 init 方法中创建了一个UIButton类型对象而不是一个UICustomButton类型

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

Try replacing your initmethod for

尝试替换您的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;
}

This will cause selfto be a UICustomButtontype object.

这将导致self成为一个UICustomButton类型对象。

Also, you are using a wrong type for the UIControlState parameter when you add the target to your button using the addTarget:action:forControlEvents:method

此外,当您使用该addTarget:action:forControlEvents:方法将目标添加到按钮时,您对 UIControlState 参数使用了错误的类型

You should use value among the ones bellow:

您应该使用以下值:

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel



EDIT: Notes on UIButton subclassing

编辑: 关于 UIButton 子类化的说明

Many references on the web say you should NOT subclass the UIButtonclass, but not only anybody said why but what also deeply annoyed me was that the UIButton Class Referencedoes not say anything about it at all.

网络上的许多参考资料都说你不应该对UIButton类进行子类化,但不仅有人说为什么,而且让我深感恼火的是UIButton 类参考根本没有说明任何关于它的内容。

If you take UIWebView Class Referencefor example, it explicitly states that you should not subclass UIWebView

如果你以UIWebView 类参考为例,它明确指出你不应该子类化UIWebView

Subclassing Notes The UIWebView class should not be subclassed.

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

the big deal with UIButtonis that it inherits from UIControland a good and simple explanation is on the UIControl Class Referenceitself

大不了的UIButton是,它从继承UIControl和良好的和简单的解释是,在UIControl类参考本身

Subclassing Notes You may want to extend a UIControl subclass for either of two reasons:

  • To observe or modify the dispatch of action messages to targets for particular events
  • To provide custom tracking behavior (for example, to change the highlight appearance)

子类化注释您可能出于以下两个原因之一想要扩展 UIControl 子类:

  • 观察或修改对特定事件的目标的动作消息的分派
  • 提供自定义跟踪行为(例如,更改突出显示外观)

So, this means that you CANsubclass a UIButton, but you should be careful on what you are doing. Just subclass it to change its behaviorand notits appearance. To modify a UIButtonappearance you should use the interface methods provided for that, such as:

因此,这意味着你的CAN子类UIButton,但你要小心你在做什么。只要继承它来改变它的行为,并没有外观。要修改UIButton外观,您应该使用为此提供的接口方法,例如:

setTitle:forState:
setBackgroundImage:forState:
setImage:forState:

setTitle:forState:
setBackgroundImage:forState:
setImage:forState:

References worth reading

值得一读的参考资料

Source: my post here

来源:我的帖子在这里

回答by Jonny

Not sure this was in the docs before, but anyway these are the current notes on + (id)buttonWithType:(UIButtonType)buttonType...

不确定这是否在之前的文档中,但无论如何这些是关于+ (id)buttonWithType:(UIButtonType)buttonType...的当前说明

To me it looks like subclassing is OK as long as you use initinstead of buttonWithType. I have yet to try it myself however.

对我来说,只要您使用init而不是buttonWithType. 然而,我还没有亲自尝试过。

Discussion This method is a convenience constructor for creating button objects with specific configurations. It you subclass UIButton, this method does not return an instance of your subclass. If you want to create an instance of a specific subclass, you must alloc/init the button directly.

When creating a custom button—that is a button with the type UIButtonTypeCustom—the frame of the button is set to (0, 0, 0, 0) initially. Before adding the button to your interface, you should update the frame to a more appropriate value.

讨论 此方法是创建具有特定配置的按钮对象的便捷构造函数。如果您对 UIButton 进行子类化,则此方法不会返回您的子类的实例。如果要创建特定子类的实例,则必须直接分配/初始化按钮。

创建自定义按钮(即 UIButtonTypeCustom 类型的按钮)时,按钮的框架最初设置为 (0, 0, 0, 0)。在将按钮添加到您的界面之前,您应该将框架更新为更合适的值。

回答by kanstraktar

If you want to get notifications when the user is interacting with your buttons, just sublcass UIButton and implement these methods:

如果您想在用户与您的按钮交互时收到通知,只需 sublcas 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");
}

No init method required.

不需要 init 方法。

回答by Alok SInha

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

回答by Eiko

Edit

编辑

This answer reaches back several years, and things have changed - as Apple docs now explicitly mention subclassing and gives some hints.

这个答案可以追溯到几年前,事情已经发生了变化——因为 Apple 文档现在明确提到了子类化并给出了一些提示。

So the following answer might be irrelevant or wrong for current developmentand might be ignored if you're interested in the current state of the art.

因此,以下答案可能与当前的开发无关或错误,如果您对当前最先进的技术感兴趣,则可能会被忽略。



UIButton is notmeant to be subclassed.

UIButton并不意味着被子类化。

You are better off making a category and defining a factory method that delivers your needed button (with proper call to buttonWithType:). initWithFrame:is not the correct way to initialize a button anyway.

您最好创建一个类别并定义一个提供所需按钮的工厂方法(正确调用buttonWithType:)。initWithFrame:无论如何都不是初始化按钮的正确方法。