如何倾听UIButton状态的变化?

Dou*_*ugW 20 iphone cocoa-touch objective-c key-value-observing uibutton

我正在扩展UIButton通用功能,以根据显示的标题更改某些外观属性.

为此,我需要检测并响应"state"属性的变化.这样,如果用户为不同的状态设置了不同的标题,我确保正确调整外观.我以为我需要使用某种KVO,如下所示:

[self addObserver:self 
       forKeyPath:@"state" 
          options:NSKeyValueObservingOptionNew 
          context:nil];
Run Code Online (Sandbox Code Playgroud)

但这似乎没有触发@"state"或@"currentTitle"的observeValueForKeyPath:...方法.我假设这是因为UIButton没有为这些属性实现KVO模式.

我不想只听点击.这些事件导致状态改变,但不是唯一的潜在原因.

有没有人知道如何倾听和回应UIButton的状态变化?

谢谢


UPDATE

因为我在过去几年中学到了一些东西,所以只是一个注释;).

我已经和一些知道的苹果人谈过了,而且KVO没有在国家财产上工作的原因是因为UIKit的NONE肯定是符合KVO的.在这里值得重复的思考 - 如果你试图听取UIKit框架类的任何属性,请注意它可能有效,但是没有得到官方支持,可能会在不同的iOS版本上中断.

Dou*_*ugW 11

好吧,我找到了一个有效的解决方案.您可以收听按钮titleLabel的text属性.

[self.titleLabel addObserver:self 
                  forKeyPath:@"text" 
                     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 
                     context:nil];
Run Code Online (Sandbox Code Playgroud)

似乎每变化两次被炒鱿鱼,所以你应该检查,以确保@在通过改变字典中的值"老" @"新"是不同的.

注意:不要直接使用@"old"和@"new".常量分别是NSKeyValueChangeOldKey和NSKeyValueChangeNewKey.

  • 这让我困惑:(我可以在问题的标题看`如何监听UIButton的状态变化?`但正确的回答说,'你可以听文本property` ..好..爽!但是,在我的具体情况它不可能依靠标题被改变:(如果这是不可能听它志愿的话,我想看到一个对应的答案,或者至少是一个波纹管制造更有意义 (2认同)

jha*_*ott 8

我今天需要这个,所以我写了这个完成工作的课:

MyButton.h

#import <UIKit/UIKit.h>

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

@interface MyButton : UIButton
@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

您可以使用UIButton init方法以编程方式创建它,或者通过向UIButton视图添加法线并将类更改为MyButton,从Interface Builder中使用它,但您必须以UIControlEventStateChanged编程方式侦听事件.例如,viewDidLoad在您的控制器类中,如下所示:

[self.myButton addTarget:self 
                  action:@selector(myButtonStateChanged:) 
        forControlEvents:UIControlEventStateChanged];
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个解决方案,但命名一个自定义事件`UIControlEventStateChanged`就像它是框架的一部分一样令人困惑. (7认同)