iOS:CGAffineTransformScale移动我的对象

build立在我之前提出的问题上。

试图转换标签的简单button。 我希望它缩小0.5,这是可行的,但由于某种原因,它也会移动对象。 标签向上跳转到左侧,然后转换。

- (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"); } }]; } 

我假设你正在使用自动布局的问题:在自动布局,如果你有一个前导和/或顶部的约束,用CGAffineTransformMakeScale缩放后,领先/顶部约束将被重新应用,你的控制将继续前进你为了确保约束仍然满足。

您可以closures自动布局(这是简单的答案),或者您可以:

  • 等到viewDidAppear (因为在IB中定义的约束被应用,并且控制将被放置在我们想要的地方并且它的center属性将是可靠的);

  • 现在我们已经讨论了控件的center ,用NSLayoutAttributeCenterXNSLayoutAttributeCenterY约束来replace前导约束和NSLayoutAttributeCenterY约束,使用center属性的值来设置NSLayoutConstraintconstant ,如下所示。

从而:

 // 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; } 

你的实现的细节可能会有所不同,这取决于你如何定义你想要扩展的控件的约束(在我的例子中,领先和顶层是基于超级视图,这使得它更容易),但希望能够说明解决scheme,删除这些约束条件,并根据中心添加新的约束条件。

你可以,如果你不想迭代通过寻找约束的问题,像我上面做的那样,定义一个IBOutlet的顶部和领先的约束,而不是大大简化了过程。 这个示例代码来自一个项目,出于各种原因,我不能使用IBOutletNSLayoutConstraint引用。 但是使用IBOutlet引用来约束绝对是一个更简单的方法(如果你坚持使用自动布局)。

例如,如果你进入界面生成器,你可以突出显示有问题的约束和控制 -拖到助理编辑器,使您的IBOutlet

制约IBOutlet

如果你这样做,而不是遍历所有的约束,你现在可以说,例如:

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

坦率地说,我希望Interface Builder能够定义像这样的约束(即,而不是“superview左边的控制引导”约束,“superview左边的控制中心”约束),但是我不要以为它可以在IB中完成,所以我正在以编程的方式改变我的约束。 但是通过这个过程,我现在可以扩大控制范围,而不是因为限制而在我身边移动。


正如0x7fffffff指出的那样,如果将CATransform3DMakeScale应用于图层,则不会自动应用这些约束,因此,如果将CGAffineTransformMakeScale应用于视图,您将看不到它的移动。 但是如果你做任何事情重新应用约束( setNeedsLayout或做任何更改任何UIView对象可以导致约束被重新应用),视图将在你身上移动。 因此,如果在重新应用约束之前将图层的变换恢复为身份,则可能会“偷偷摸摸”,但closures自动布局或仅修复约束可能是最安全的。