Как слушать изменение состояния UIButton?
Я не продлю UIButton
С общей функциональностью для изменения определенных атрибутов внешнего вида на основе отображаемого заголовка.
для этого мне нужно обнаружить и отреагировать на изменения в свойстве "состояние". Поэтому я удостоверяюсь, что внешний вид правильно настроен, если пользователь установил разные названия для разных состояний. Я предположил, что мне нужно будет использовать какой-то KVO, например:
[self addObserver:self
forKeyPath:@"state"
options:NSKeyValueObservingOptionNew
context:nil];
но это, похоже, не увольняет observeValueForKeyPath:... метод для @ "state"или @"currentTitle". Я предполагаю, что это связано с тем, что UIButton не реализует шаблон KVO для этих свойств.
Я не хочу просто слушать щелчки. Эти события вызывают изменение состояния, но не единственные возможные причины.
кто-нибудь знает способ слушать и реагировать на изменения состояния UIButton?
спасибо
обновление
просто к сведению так как я узнал несколько вещей за последние пару лет ;).
С тех пор я разговаривал с некоторыми людьми Apple, которые знают, и причина, по которой KVO не работает на государственной собственности, связана с тем, что нет UIKit гарантированно будет KVO уступчивым. Подумал, что стоит повторить здесь-Если вы пытаетесь слушать любой свойство класса UIKit framework, имейте в виду, что он может работать, но официально не поддерживается и может сломаться на разных iOS версии.
4 ответов
хорошо, я нашел решение, которое работает. Вы можете прослушать свойство text titleLabel кнопки.
[self.titleLabel addObserver:self
forKeyPath:@"text"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
Кажется, что он увольняется дважды за изменение, поэтому вы должны проверить, чтобы убедиться, что значения @"old" и @"new" в переданном словаре изменений отличаются.
примечание: не используйте @"старый" и @"новый" напрямую. Константами являются nskeyvaluechangeoldkey и nskeyvaluechangenewkey соответственно.
мне это нужно было сегодня, поэтому я написал этот класс, который выполняет эту работу:
моя кнопка.h
#import <UIKit/UIKit.h>
// UIControlEventStateChanged uses the first bit from the UIControlEventApplicationReserved group
#define UIControlEventStateChanged (1 << 24)
@interface MyButton : UIButton
@end
моя кнопка.м
#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
метод, или использовать его из Interface Builder, добавив нормальный UIButton
на ваш взгляд и изменение класса на MyButton
, но вы должны слушать для UIControlEventStateChanged
событие программно. Например,viewDidLoad
в вашем классе контроллера, как это:
[self.myButton addTarget:self
action:@selector(myButtonStateChanged:)
forControlEvents:UIControlEventStateChanged];
[self addObserver:self
forKeyPath:@"state"
options:NSKeyValueObservingOptionNew
context:nil];
отлично работает, если вы проверяете внутри наблюдателя "выбранное" свойство
-(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];
}
подкласс UIButton, override setState: это то, что работает для меня. Это, вероятно, не лучший способ, но я сделал это успешно.
извинения за приведенный выше ответ, это было неправильно. Надо было взглянуть на мой код. В моем случае мне нужно было только изменить состояние на основе выделения, поэтому я перешел -setHighlight:
чтобы изменить любые значения, которые мне нужны. YMMV.