24

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

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

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

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

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

UIButtonの状態変化をリッスンして応答する方法を知っている人はいますか?

ありがとう


アップデート

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

それ以来、私は知っているAppleの人々と話をしましたが、KVOが州の資産で機能しない理由は、 UIKitのどれもKVOに準拠することが保証されていないという事実によるものです。ここで繰り返す価値があると思いました。UIKitフレームワーククラスのプロパティをリッスンしようとしている場合は、機能する可能性はありますが、公式にはサポートされておらず、さまざまなiOSバージョンで機能しない可能性があることに注意してください

4

4 に答える 4

11

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

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

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

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

于 2010-03-23T21:58:28.787 に答える
9

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

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ことでInterface Builderから使用することもできますが、プログラムでイベントをリッスンする必要があります。たとえば、次のようなコントローラクラスから:UIButtonMyButtonUIControlEventStateChangedviewDidLoad

[self.myButton addTarget:self 
                  action:@selector(myButtonStateChanged:) 
        forControlEvents:UIControlEventStateChanged];
于 2012-06-22T22:08:58.713 に答える
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];
}
于 2013-12-05T17:53:54.673 に答える
-2

サブクラスUIButton、オーバーライドsetState:は私のために働くものです。これはおそらく最善の方法ではありませんが、私はそれを成功させました。

上記の答えをお詫びします、それは間違っていました。実際に私のコードを見るべきでした。私の場合、ハイライトに基づいて状態を変更するだけでよいので、setHighlight:必要な値を変更するためにオーバーライドしました。YMMV。

于 2010-03-23T21:22:43.760 に答える