1. ホーム
  2. iphone

[解決済み] UIViewのフレームでKey Value Observingを行い、KVOコールバックを取得するにはどうすればよいですか?

2023-08-13 18:52:28

質問

の変化を監視したい。 UIView 's frame , bounds または center というプロパティがあります。これを実現するためにKey-Value Observingをどのように使用すればよいですか?

どのように解決するのですか?

KVOがサポートされていないnotificationやその他の観測可能なイベントがあるのが普通です。ドキュメントによると 'なし' と書かれていても、UIViewをバックアップしているCALayerを監視することは表向きは安全です。CALayerを観察することは、KVOと適切なアクセッサ(ivar操作の代わりに)を広範囲に使用するため、実際にはうまくいきます。将来的に動作することは保証されていません。

とにかく、ビューのフレームは他のプロパティの積に過ぎません。したがって、私たちはそれらを観察する必要があります。

[self.view addObserver:self forKeyPath:@"frame" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"bounds" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"transform" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"position" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"zPosition" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"anchorPoint" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"anchorPointZ" options:0 context:NULL];
[self.view.layer addObserver:self forKeyPath:@"frame" options:0 context:NULL];

全例はこちら https://gist.github.com/hfossli/7234623

注意: これはドキュメントではサポートされていないとされていますが、今日現在、これまでのすべての iOS バージョン (現在 iOS 2 -> iOS 11) で動作しています。

注意:最終的な値に落ち着くまでに、複数のコールバックを受け取ることになるので、注意してください。例えば、ビューやレイヤーのフレームを変更すると、レイヤーが変更されます。 positionbounds (の順番で)。


ReactiveCocoaでできること

RACSignal *signal = [RACSignal merge:@[
  RACObserve(view, frame),
  RACObserve(view, layer.bounds),
  RACObserve(view, layer.transform),
  RACObserve(view, layer.position),
  RACObserve(view, layer.zPosition),
  RACObserve(view, layer.anchorPoint),
  RACObserve(view, layer.anchorPointZ),
  RACObserve(view, layer.frame),
  ]];

[signal subscribeNext:^(id x) {
    NSLog(@"View probably changed its geometry");
}];

そして、もしあなたが bounds が変化したときだけ知りたい場合は

@weakify(view);
RACSignal *boundsChanged = [[signal map:^id(id value) {
    @strongify(view);
    return [NSValue valueWithCGRect:view.bounds];
}] distinctUntilChanged];

[boundsChanged subscribeNext:^(id ignore) {
    NSLog(@"View bounds changed its geometry");
}];

そして、もしあなたが frame が変化したときだけ知りたい場合は

@weakify(view);
RACSignal *frameChanged = [[signal map:^id(id value) {
    @strongify(view);
    return [NSValue valueWithCGRect:view.frame];
}] distinctUntilChanged];

[frameChanged subscribeNext:^(id ignore) {
    NSLog(@"View frame changed its geometry");
}];