web-dev-qa-db-fra.com

Existe-t-il un événement de redimensionnement UIView?

J'ai une vue qui contient des rangées et des colonnes de vues d'image.

Si cette vue est redimensionnée, je dois réorganiser les positions des images vues.

Cette vue est une sous-vue d'une autre vue redimensionnée.

Existe-t-il un moyen de détecter le redimensionnement de cette vue?

95
live-love

Comme Uli a commenté ci-dessous, la bonne façon de le faire est de remplacer layoutSubviews et d'y placer l'imageViews.

Si, pour une raison quelconque, vous ne pouvez pas sous-classer ni remplacer layoutSubviews, observer bounds devrait fonctionner, même s'il est en quelque sorte sale. Pire encore, le fait d’observer - Apple ne garantit pas le fonctionnement de KVO sur les classes UIKit. Lisez la discussion avec Apple ingénieur ici: Quand un objet associé est-il libéré?

réponse originale:

Vous pouvez utiliser l'observation clé-valeur:

[yourView addObserver:self forKeyPath:@"bounds" options:0 context:nil];

et mettre en œuvre:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == yourView && [keyPath isEqualToString:@"bounds"]) {
        // do your stuff, or better schedule to run later using performSelector:withObject:afterDuration:
    }
}
92
Michal

Dans une sous-classe UIView, observateurs de propriétés peut être utilisé:

override var bounds: CGRect {
    didSet {
        // ...
    }
}

Sans sous-classement, observation clé-valeur avec chemins-clés intelligents fera:

var boundsObservation: NSKeyValueObservation?

func beginObservingBounds() {
    boundsObservation = observe(\.bounds) { capturedSelf, _ in
        // ...
    }
}
85
Rudolf Adamkovič

Créer une sous-classe d'UIView et substituer layoutSubviews

29
gwang

Assez vieux mais reste une bonne question. Dans l'exemple de code d'Apple et dans certaines de leurs sous-classes privées UIView, ils surchargent setBounds en gros comme ceci:

-(void)setBounds:(CGRect)newBounds {
    BOOL const isResize = !CGSizeEqualToSize(newBounds.size, self.bounds.size);
    if (isResize) [self prepareToResizeTo:newBounds.size]; // probably saves 
    [super setBounds:newBounds];
    if (isResize) [self recoverFromResizing];
}

Remplacement setFrame: n'est PAS une bonne idée. frame est dérivé de center, bounds et transform, de sorte que iOS n'appellera pas nécessairement setFrame:.

7
Adlai Holler

Swift 4 keypath KVO - C’est ainsi que je détecte l’autorotation et le déplacement vers le panneau latéral de l’iPad. Devrait travailler travailler n'importe quelle vue. J'ai dû observer la couche d'UIView.

private var observer: NSKeyValueObservation?

override func viewDidLoad() {
    super.viewDidLoad()
    observer = view.layer.observe(\.bounds) { object, _ in
        print(object.bounds)
    }
    // ...
}
override func viewWillDisappear(_ animated: Bool) {
    observer?.invalidate()
    //...
}
7
Warren Stringer

Vous pouvez créer une sous-classe d’UIView et remplacer le

setFrame: cadre (CGRect)

méthode. C'est la méthode appelée lorsque le cadre (c'est-à-dire la taille) de la vue est modifié. Faites quelque chose comme ça:

- (void) setFrame:(CGRect)frame
{
  // Call the parent class to move the view
  [super setFrame:frame];

  // Do your custom code here.
}
6
rekle