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のバージョンが異なると破損する可能性があることに注意してください。
さて、私はうまくいく解決策を見つけました。ボタンのtitleLabelのtextプロパティを聞くことができます。
[self.titleLabel addObserver:self
forKeyPath:@"text"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
変更ごとに2回発生するようです。そのため、渡された変更ディクショナリの@ "old"と@ "new"の値が異なることを確認する必要があります。
注:@ "old"と@ "new"を直接使用しないでください。定数はそれぞれNSKeyValueChangeOldKeyとNSKeyValueChangeNewKeyです。
私は今日これが必要だったので、私は仕事をするこのクラスを書きました:
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];
[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];
}