Объект C: Кнопки, созданные из подкласса класса UIButton, не работают

Я создаю подкласс 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;
}

Я столкнулся с некоторыми проблемами при работе над этим кодом. У меня 2 проблемы.

1) Кнопки не реагируют на метод выбора "buttonPressed"

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'

Что я здесь делаю неправильно?

Ответы

Ответ 1

Это происходит потому, что вы создаете объект типа UIButton, а не тип UICustomButton внутри метода init, когда вы делаете

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

Попробуйте заменить метод 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 будет объектом типа UICustomButton.

Кроме того, вы используете неправильный тип для параметра UIControlState, когда вы добавляете цель на свою кнопку, используя метод addTarget:action:forControlEvents:

Вы должны использовать значение среди ниже:

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel


EDIT: Заметки о подклассе UIButton

Многие ссылки в Интернете говорят, что вы НЕ должны подклассифицировать класс UIButton, но не только кто-то сказал, почему, но и то, что меня также глубоко раздражало, было то, что UIButton Class Reference ничего об этом не говорит.

Если вы возьмете ссылку на класс UIWebView, он явно заявляет, что вы не должны подклассы UIWebView

Замечания о подклассе Класс UIWebView не следует подклассифицировать.

большое дело с UIButton заключается в том, что он наследует от UIControl, и хорошее и простое объяснение есть в самом документе класса UIControl

Замечания о подклассе Вы можете захотеть расширить подкласс UIControl для из двух причин:

  • Наблюдение или изменение отправки сообщения о действиях для целей конкретные события
  • Предоставление пользовательских отслеживания (например, для изменить внешний вид)

Итак, это означает, что вы CAN подкласс a UIButton, но вы должны быть осторожны с тем, что вы делаете. Просто подклассируйте его, чтобы изменить его поведение и не его внешний вид . Чтобы изменить внешний вид UIButton, вы должны использовать методы интерфейса, предусмотренные для этого, например:

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

Ссылки, которые стоит прочитать

Источник: мой пост здесь

Ответ 2

Не уверен, что это было в документах раньше, но в любом случае это текущие заметки на + (id)buttonWithType:(UIButtonType)buttonType...

Мне кажется, что подклассы в порядке, пока вы используете init вместо buttonWithType. Мне еще предстоит попробовать это сам.

Обсуждение Этот метод является конструктором удобства для создания с конкретными конфигурациями. Это вы подкласс UIButton, этот метод не возвращает экземпляр вашего подкласса. Если ты хочешь для создания экземпляра определенного подкласса вы должны указать /init напрямую.

При создании настраиваемой кнопки - кнопки с типом UIButtonTypeCustom - рамка кнопки установлена ​​на (0, 0, 0, 0) первоначально. Прежде чем добавлять кнопку в свой интерфейс, вы должны обновите фрейм до более подходящего значения.

Ответ 3

Edit

Этот ответ вернется на несколько лет, и все изменилось - поскольку Apple docs теперь явно упоминает подклассификацию и дает некоторые подсказки.

Таким образом, следующий ответ может быть нерелевантным или неправильным для текущей разработки и может быть проигнорирован, если вы заинтересованы в текущем уровне техники.


UIButton не, который должен быть подклассом.

Вам лучше создать категорию и определить метод factory, который поставляет нужную кнопку (при правильном вызове buttonWithType:). initWithFrame: - это не правильный способ инициализации кнопки.

Ответ 4

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

Ответ 5

Если вы хотите получать уведомления, когда пользователь взаимодействует с вашими кнопками, просто подберите 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.