我正在使用通用功能扩展UIButton
,以根据显示的标题更改某些外观属性。
为了做到这一点,我需要检测并响应“state”属性的变化。这样,如果用户为不同的状态设置了不同的标题,我确保正确调整外观。我假设我需要使用某种KVO,如下所示:
[self addObserver:self
forKeyPath:@"state"
options:NSKeyValueObservingOptionNew
context:nil];
但这似乎没有触发@“state”或@“currentTitle”的observeValueForKeyPath:...方法。我认为这是因为UIButton没有为这些属性实现KVO模式。
我不想只听取点击次数。这些事件导致状态改变,但不是唯一的潜在原因。
有没有人知道如何倾听并回应UIButton的状态变化?
由于
因为我在过去几年中学到了一些东西,所以只是一个注释;)。
我已经和一些知道的苹果人谈过了,并且KVO不对国家财产起作用的原因归功于UIKit的 NONE 保证符合KVO。在这里值得重复的思考 - 如果您正在尝试收听UIKit框架类的任何属性,请注意它可能有效,但不受官方支持,可能会在不同的iOS版本上中断。 / p>
答案 0 :(得分:11)
好吧我找到了一个有效的解决方案。您可以收听按钮titleLabel的文本属性。
[self.titleLabel addObserver:self
forKeyPath:@"text"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
每次更改似乎都会被触发两次,因此您应该检查以确保传递的更改字典中@“old”和@“new”的值不同。
注意:请勿直接使用@“old”和@“new”。常量分别是NSKeyValueChangeOldKey和NSKeyValueChangeNewKey。
答案 1 :(得分:8)
我今天需要这个,所以我写了这个完成这项工作的课程:
<强> 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
,从Interface Builder中使用它,但您必须以编程方式监听UIControlEventStateChanged
事件。例如,来自控制器类中的viewDidLoad
,如下所示:
[self.myButton addTarget:self
action:@selector(myButtonStateChanged:)
forControlEvents:UIControlEventStateChanged];
答案 2 :(得分:2)
[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];
}
答案 3 :(得分:-2)
子类UIButton,覆盖setState:对我有用。这可能不是最好的方法,但我已经成功完成了。
对于上述答案道歉,这是错误的。本来应该看看我的代码。在我的情况下,我只需要根据突出显示改变状态,所以我覆盖 - setHighlight:
来改变我需要的任何值。 YMMV。