Как слушать изменения состояния UIButton? - PullRequest
20 голосов
/ 24 марта 2010

Я расширяю UIButton общей функциональностью для изменения определенных атрибутов внешнего вида на основе отображаемого заголовка.

Для этого мне нужно обнаружить и отреагировать на изменения в свойстве "state". Это так, чтобы убедиться, что внешний вид настроен правильно, если пользователь установил разные заголовки для разных состояний. Я предположил, что мне нужно будет использовать какой-то вид KVO, например:

[self addObserver:self 
       forKeyPath:@"state" 
          options:NSKeyValueObservingOptionNew 
          context:nil];

Но, похоже, это не вызывает метода наблюдающийВалюФорФКей: ... для @ "state" или @ "currentTitle". Я предполагаю, что это потому, что UIButton не реализует шаблон KVO для этих свойств.

Я не хочу просто слушать клики. Эти события вызывают изменение состояния, но не являются единственными потенциальными причинами.

Кто-нибудь знает способ прослушивания и реагирования на изменения состояния кнопки UIB?

Спасибо


UPDATE

Просто примечание, поскольку за последние пару лет я кое-чему научился;).

С тех пор я разговаривал с некоторыми людьми из Apple, которые знают, и причина, по которой KVO не работает с государственной собственностью, связана с тем, что NONE UIKit гарантированно соответствует KVO. Мысль, которую стоит повторить здесь - если вы пытаетесь прослушать любое свойство класса инфраструктуры UIKit, имейте в виду, что оно может работать, но официально не поддерживается и может работать на разных версиях iOS.

Ответы [ 4 ]

11 голосов
/ 24 марта 2010

Хорошо, я нашел решение, которое работает. Вы можете прослушать текстовое свойство кнопки titleLabel.

[self.titleLabel addObserver:self 
                  forKeyPath:@"text" 
                     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 
                     context:nil];

Кажется, он срабатывает дважды за изменение, поэтому вам следует проверить, чтобы значения @ "old" и @ "new" в переданном словаре изменений были разными.

ПРИМЕЧАНИЕ. Не используйте @ "old" и @ "new" напрямую. Константами являются NSKeyValueChangeOldKey и NSKeyValueChangeNewKey соответственно.

8 голосов
/ 23 июня 2012

Мне это нужно было сегодня, поэтому я написал этот класс, который выполняет свою работу:

MyButton.h

#import <UIKit/UIKit.h>

// UIControlEventStateChanged uses the first bit from the UIControlEventApplicationReserved group
#define UIControlEventStateChanged  (1 << 24)

@interface MyButton : UIButton
@end

MyButton.m

#import "MyButton.h"

#pragma mark - Private interface
@interface MyButton ()
- (void)checkStateChangedAndSendActions;
@end

#pragma mark - Main class
@implementation MyButton
{
    // Prior state is used to compare the state before
    // and after calls that are likely to change the
    // state. It is an ivar rather than a local in each
    // method so that if one of the methods calls another,
    // the state-changed actions only get called once.
    UIControlState  _priorState;
}

- (void)setEnabled:(BOOL)enabled
{
    _priorState = self.state;
    [super setEnabled:enabled];
    [self checkStateChangedAndSendActions];
}

- (void)setSelected:(BOOL)selected
{
    _priorState = self.state;
    [super setSelected:selected];
    [self checkStateChangedAndSendActions];
}

- (void)setHighlighted:(BOOL)highlighted
{
    _priorState = self.state;
    [super setHighlighted:highlighted];
    [self checkStateChangedAndSendActions];
}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    _priorState = self.state;
    [super touchesBegan:touches withEvent:event];
    [self checkStateChangedAndSendActions];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    _priorState = self.state;
    [super touchesMoved:touches withEvent:event];
    [self checkStateChangedAndSendActions];
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    _priorState = self.state;
    [super touchesEnded:touches withEvent:event];
    [self checkStateChangedAndSendActions];
}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
    _priorState = self.state;
    [super touchesCancelled:touches withEvent:event];
    [self checkStateChangedAndSendActions];
}

#pragma mark - Private interface implementation
- (void)checkStateChangedAndSendActions
{
    if(self.state != _priorState)
    {
        _priorState = self.state;
        [self sendActionsForControlEvents:UIControlEventStateChanged];
    }
}

@end

Вы можете создать его программно, используя метод UIButton init, или использовать его из Интерфейсного Разработчика, добавив обычный UIButton в ваше представление и изменив класс на MyButton, но вы должны слушать UIControlEventStateChanged событие программно. Например, из viewDidLoad в вашем классе контроллера, как это:

[self.myButton addTarget:self 
                  action:@selector(myButtonStateChanged:) 
        forControlEvents:UIControlEventStateChanged];
2 голосов
/ 05 декабря 2013
[self addObserver:self 
       forKeyPath:@"state" 
          options:NSKeyValueObservingOptionNew 
          context:nil];

Работает нормально, если вы проверяете внутри свойства 'selected' наблюдателя

-(void)observeValueForKeyPath:(NSString *)keyPath  
                     ofObject:(id)object 
                       change:(NSDictionary *)change 
                      context:(void *)context
{
    if ([keyPath isEqualToString:@"selected"])
    {
        [self.img setImage:self.selected ? self.activeImg : self.inactiveImg];
    }
    else
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
}
0 голосов
/ 24 марта 2010

Подкласс UIButton, переопределение setState: это то, что работает для меня. Вероятно, это не самый лучший способ, но я сделал это успешно.

Извините за ответ выше, это было неправильно. Должен был на самом деле посмотреть на мой код. В моем случае мне нужно было только изменить состояние на основе выделения, поэтому я переопределил - setHighlight:, чтобы изменить любые нужные мне значения. YMMV.

...