web-dev-qa-db-ja.com

UIButtonの状態変化をどのようにリッスンしますか?

UIButtonを汎用機能で拡張して、表示されたタイトルに基づいて特定の外観属性を変更します。

これを行うには、「状態」プロパティの変更を検出して応答する必要があります。これは、ユーザーが州ごとに異なるタイトルを設定した場合に、外観が適切に調整されるようにするためです。次のようなKVOを使用する必要があると思いました。

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

しかし、これは@ "state"または@ "currentTitle"のobserveValueForKeyPath:...メソッドを起動しないようです。これは、UIButtonがこれらのプロパティのKVOパターンを実装していないためだと思います。

クリックだけを聞きたくない。これらのイベントは状態の変化を引き起こしますが、潜在的な原因はそれだけではありません。

UIButtonの状態変化を聞いて応答する方法を知っている人はいますか?

ありがとう


[〜#〜]更新[〜#〜]

ここ数年でいくつかのことを学んだので、ちょっと注意してください;)。

それ以来、私は何人かのApple知っている人々と話をしました、そしてKVOが州のプロパティで機能しない理由は、[〜#〜] none [〜 #〜]のUIKitはKVOに準拠していることが保証されています。ここで繰り返す価値があると思いました-anyプロパティを聴こうとしている場合UIKitフレームワーククラスの場合、動作する可能性はありますが、公式にはサポートされておらず、iOSのバージョンが異なると破損する可能性があることに注意してください。

21
DougW

さて、私はうまくいく解決策を見つけました。ボタンのtitleLabelのtextプロパティを聞くことができます。

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

変更ごとに2回発生するようです。そのため、渡された変更ディクショナリの@ "old"と@ "new"の値が異なることを確認する必要があります。

注:@ "old"と@ "new"を直接使用しないでください。定数はそれぞれNSKeyValueChangeOldKeyとNSKeyValueChangeNewKeyです。

11
DougW

私は今日これが必要だったので、私は仕事をするこのクラスを書きました:

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

UIButtoninitメソッドを使用してプログラムで作成するか、ビューに通常のUIButtonを追加してクラスをMyButtonに変更することで、Interface Builderから使用できますが、プログラムでUIControlEventStateChangedイベントをリッスンする必要があります。たとえば、次のようにコントローラクラスのviewDidLoadから:

[self.myButton addTarget:self 
                  action:@selector(myButtonStateChanged:) 
        forControlEvents:UIControlEventStateChanged];
8
jhabbott
[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];
}
2
user2403596