iOS: CGAffineTransformScale mueve mi object

Sobre la base de una pregunta que tuve antes .

Botón simple que intenta transformar una label. Quiero que se networkinguzca en 0.5, lo que funciona pero por alguna razón también mueve el object como lo hace. La label salta hacia arriba y hacia la izquierda, luego se transforma.

- (IBAction)btnTest:(id)sender { [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ lblTest.transform = CGAffineTransformScale(lblTest.transform, 0.5f,0.5f); }completion:^(BOOL finished) { if(finished){ NSLog(@"DONE"); } }]; } 

Estoy presumiendo de la pregunta de que está utilizando la function de layout automático: en layout automático, si tiene una restricción principal y / o superior, después de escalar con CGAffineTransformMakeScale , la restricción principal / superior se volverá a aplicar y su control se moverá usted para asegurarse de que la restricción todavía se satisface.

Puede desactivar el layout automático (que es la respuesta fácil) o puede:

  • espere hasta viewDidAppear (porque las restricciones definidas en IB se aplicarán, y el control se colocará donde lo deseamos y su propiedad center será confiable);

  • ahora que tenemos el center del control en cuestión, reemplace las restricciones principales y superiores con las restricciones NSLayoutAttributeCenterX y NSLayoutAttributeCenterY , utilizando los valores de la propiedad center para establecer la constant para NSLayoutConstraint como sigue.

Así:

 // don't try to do this in `viewDidLoad`; do it in `viewDidAppear`, where the constraints // have already been set - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self replaceLeadingAndTopWithCenterConstraints:self.imageView]; } // Because our gesture recognizer scales the UIView, it's quite important to make // sure that we don't have the customary top and leading constraints, but rather // have constraints to the center of the view. Thus, this looks for leading constraint // and if found, removes it, replacing it with a centerX constraint. Likewise if it // finds a top constraint, it replaces it with a centerY constraint. // // Having done that, we can now do `CGAffineTransformMakeScale`, and it will keep the // view centenetworking when that happens, avoiding weird UX if we don't go through this // process. - (void)replaceLeadingAndTopWithCenterConstraints:(UIView *)subview { CGPoint center = subview.center; NSLayoutConstraint *leadingConstraint = [self findConstraintOnItem:subview attribute:NSLayoutAttributeLeading]; if (leadingConstraint) { NSLog(@"Found leading constraint"); [subview.superview removeConstraint:leadingConstraint]; [subview.superview addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:subview.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:center.x]]; } NSLayoutConstraint *topConstraint = [self findConstraintOnItem:subview attribute:NSLayoutAttributeTop]; if (topConstraint) { NSLog(@"Found top constraint"); [subview.superview removeConstraint:topConstraint]; [subview.superview addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:subview.superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:center.y]]; } } - (NSLayoutConstraint *)findConstraintOnItem:(UIView *)item attribute:(NSLayoutAttribute)attribute { // since we're looking for the item's constraints to the superview, let's // iterate through the superview's constraints for (NSLayoutConstraint *constraint in item.superview.constraints) { // I believe that the constraints to a superview generally have the // `firstItem` equal to the subview, so we'll try that first. if (constraint.firstItem == item && constraint.firstAttribute == attribute) return constraint; // While it always appears that the constraint to a superview uses the // subview as the `firstItem`, theoretically it's possible that the two // could be flipped around, so I'll check for that, too: if (constraint.secondItem == item && constraint.secondAttribute == attribute) return constraint; } return nil; } 

Los detalles de su implementación pueden variar dependiendo de cómo haya definido las restricciones del control que desea escalar (en mi caso, el líder y el superior se basaron en la supervisión, lo que lo hizo más fácil), pero es de esperar que ilustre la solución, para eliminar esas restricciones y agregar nuevas basadas en el centro.

Podría, si no desea repetir la búsqueda de la restricción en cuestión, como hago arriba, defina un IBOutlet para las restricciones principales y principales, lo que simplifica enormemente el process. Este código de ejemplo se tomó de un proyecto donde, por una variedad de razones, no pude usar el IBOutlet para las references NSLayoutConstraint . Pero usar las references de IBOutlet para las restricciones es definitivamente una manera más fácil de seguir (si te atenas con la distribución automática).

Por ejemplo, si va a Interface Builder, puede resaltar la restricción en cuestión y controlar -drag al editor asistente para hacer que su IBOutlet :

make constraint IBOutlet

Si haces eso, en lugar de recorrer todas las restricciones, ahora puedes decir, por ejemplo:

 if (self.imageViewVerticalConstraint) { [self.view removeConstraint:self.imageViewVerticalConstraint]; // create the new constraint here, like shown above } 

Francamente, deseo que Interface Builder tuviera la capacidad de definir restricciones como estas directamente (es decir, en lugar de una restricción de "liderazgo de control a la izquierda de supervisión", una restricción de "centro de control a la izquierda de supervisión"), pero yo No creo que se pueda hacer en IB, por lo que estoy alterando mis restricciones programáticamente. Pero al pasar por este process, ahora puedo escalar el control y no tener que moverse sobre mí debido a las limitaciones.


Como se observa 0x7fffffff, si aplica una CATransform3DMakeScale a la capa, no aplicará automáticamente las restricciones, por lo que no la verá moverse como si aplica CGAffineTransformMakeScale a la vista. Pero si haces cualquier cosa para volver a aplicar restricciones ( setNeedsLayout o hacer cualquier cambio en cualquier object UIView puede hacer que se UIView las restricciones), la vista se moverá sobre ti. Por lo que podría "queuerlo" si restaura la transformación de la capa a identidad antes de que las restricciones se vuelvan a aplicar, pero probablemente sea lo más seguro para desactivar la reproducción automática o simplemente para corregir las restricciones.