Ich bin von der Frage der Annahme, dass Sie Auto-Layout verwenden: Im Auto-Layout, wenn Sie eine führende und/oder Top-Einschränkung haben, nachdem Sie mit CGAffineTransformMakeScale
, die führenden/top Einschränkung skaliert werden erneut angewendet und Ihre Kontrolle wird auf Sie übertragen, um sicherzustellen, dass die Einschränkung noch erfüllt ist.
können Sie entweder die automatische Layout ausschalten (das ist die einfache Antwort ist) oder Sie können:
warten, bis viewDidAppear
(weil in IB definiert Einschränkungen angewendet werden, und die Kontrolle gestellt werden, wo wir wollen es und seine center
Eigenschaft wird zuverlässig sein);
jetzt, dass wir die center
der Kontrolle in Frage haben, ersetzen Sie die führenden und Top-Einschränkungen mit NSLayoutAttributeCenterX
und NSLayoutAttributeCenterY
Zwänge, die Werte für center
Eigenschaft mit der constant
für die NSLayoutConstraint
wie wie folgt einzustellen.
So:
// 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 centered 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;
}
Die Einzelheiten der Implementierung variieren kann, je nachdem, wie Sie die Einschränkungen der Kontrolle definiert haben Sie (in meinem Fall skalieren möchten, führende und oben beruhten auf der Superview, der es einfacher machte), aber hoffentlich illustriert es die Lösung, diese Beschränkungen zu entfernen und neue basierend auf dem Zentrum hinzuzufügen.
Sie könnten, wenn Sie nicht durch die Suche nach der Einschränkung infrage gehen möchten, wie ich oben, ein IBOutlet
für die Top-und führenden Bedingungen statt, was den Prozess erheblich vereinfacht definieren. Dieser Beispielcode stammt aus einem Projekt, in dem ich aus verschiedenen Gründen die IBOutlet
für die NSLayoutConstraint
Referenzen nicht verwenden konnte. Aber mit den IBOutlet
Referenzen für die Einschränkungen ist definitiv ein einfacher Weg zu gehen (wenn Sie mit Auto-Layout bleiben).
Zum Beispiel, wenn Sie Interface Builder gehen, können Sie die Einschränkung in Frage und Steuer -Ziehen an den Assistenten-Editor markieren, um Ihren IBOutlet
:
Wenn Sie das tun, anstatt durch alle Bedingungen laufen, können Sie jetzt einfach sagen, zum Beispiel:
if (self.imageViewVerticalConstraint)
{
[self.view removeConstraint:self.imageViewVerticalConstraint];
// create the new constraint here, like shown above
}
Ehrlich gesagt, ich Interface Builder die Möglichkeit wünschen t hatte o Einschränkungen wie diese sofort zu definieren (d. h. anstatt einer Einschränkung "Steuerung von links nach Superview", einer Constraint-Mitte "von Control nach links von Superview", aber ich denke nicht, dass es in IB möglich ist, also ändere ich meine Einschränkungen programmgesteuert. Aber indem ich diesen Prozess durchführe, kann ich jetzt die Steuerung skalieren und sie nicht aufgrund von Beschränkungen bewegen.
Wie 0x7fffffff erwähnt, wenn Sie eine CATransform3DMakeScale
auf die Ebene anwenden, wird es nicht automatisch die Einschränkungen gelten, so dass Sie es nicht wie bewegen sehen, wenn Sie CGAffineTransformMakeScale
auf die Ansicht anwenden. Aber wenn Sie etwas tun, um Einschränkungen erneut anzuwenden (setNeedsLayout
oder irgendwelche Änderungen an irgendwelchen UIView
Objekten können dazu führen, dass die Beschränkungen erneut angewendet werden), wird die Ansicht auf Sie weitergehen. Sie können sich also möglicherweise "einschmuggeln", wenn Sie die Transformation des Layers wieder in die Identität zurückversetzen, bevor die Constraints erneut angewendet werden. Am sichersten ist es jedoch, das automatische Layout auszuschalten oder die Einschränkungen zu beheben.
Gibt es einen Grund, warum Sie Core-Animation für die Rotation und Core-Grafiken für die Skala verwenden? Ich würde versuchen, die Skala auch auf der Ebene des Labels durchzuführen und zu sehen, ob das hilft. –
@ 0x7fffffff Ich habe es gerade getestet: Wenn Sie eine 'CATransform3DMakeScale' auf die Ebene anwenden, werden die Abhängigkeiten nicht automatisch angewendet, so dass Sie nicht sehen, dass sie sich bewegt, wenn Sie 'CGAffineTransformMakeScale' auf die Ansicht anwenden. Wenn Sie jedoch etwas tun, um Constraints erneut anzuwenden ('setNeedsLayout' oder irgendwelche Änderungen an irgendwelchen' UIView'-Objekten können dazu führen, dass die Constraints erneut angewendet werden), wird die Ansicht auf Ihnen weiterlaufen. Sie können sich also möglicherweise "einschmuggeln", wenn Sie die Transformation des Layers wieder in die Identität zurückversetzen, bevor die Constraints erneut angewendet werden. Am sichersten ist es jedoch, das automatische Layout auszuschalten oder die Einschränkungen zu beheben. – Rob