如何倾听UIButton状态的变化?

时间:2010-03-23 21:21:29

标签: iphone objective-c cocoa-touch uibutton key-value-observing

我正在使用通用功能扩展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>

4 个答案:

答案 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。