iOS:CGAffineTransformScale移动我的对象 [英] iOS: CGAffineTransformScale moves my object

查看:105
本文介绍了iOS:CGAffineTransformScale移动我的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据我的问题,我较早

尝试转换标签的简单按钮。我希望它收缩0.5,这是工作,但由于某种原因,它也移动对象,因为它。标签向上跳到左边,然后转换。

Simple button trying to transform a label. I want it to shrink by 0.5, which works but for some reason it also moves the object as it does it. The label jumps up and to the left, then transforms.

- (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 ,领先/顶部约束将是重新应用,您的控制将移动,以确保约束仍然满足。

I'm presuming from the question that you're using auto layout: In auto layout, if you have a leading and/or top constraint, after you scale with CGAffineTransformMakeScale, the leading/top constraint will be reapplied and your control will move on you in order to ensure that the constraint is still satisfied.

您可以关闭自动布局(这是很容易的答案),或者您可以:

You can either turn off auto layout (which is the easy answer) or you can:


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

  • wait until viewDidAppear (because constraints defined in IB be applied, and the control will be placed where we want it and its center property will be reliable);

现在我们有 c>,使用 NSLayoutAttributeCenterX NSLayoutAttributeCenterY 约束替换前导和上限制,使用 center 属性为 NSLayoutConstraint 设置常数

now that we have the center of the control in question, replace the leading and top constraints with NSLayoutAttributeCenterX and NSLayoutAttributeCenterY constraints, using the values for center property to set the constant for the NSLayoutConstraint as as follows.

因此:

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

实现的细节可能会因您如何定义约束(在我的例子中,leading和top是基于superview,这使它更容易),但希望它说明了解决方案,删除这些约束,并添加新的基于中心的控制。

The particulars of your implementation may vary depending upon how you've defined the constraints of the control you want to scale (in my case, leading and top were based upon the superview, which made it easier), but hopefully it illustrates the solution, to remove those constraints and add new ones based upon the center.

你可以,如果你不想迭代查找有问题的约束,像我上面所做的,定义一个 IBOutlet 代替顶部和前导约束,这极大地简化了过程。这个示例代码是从一个项目,其中,由于种种原因,我不能使用 IBOutlet NSLayoutConstraint 引用。但是使用 IBOutlet 引用的约束肯定是一个更简单的方法(如果你坚持使用自动布局)。

You could, if you didn't want to iterate through looking for the constraint in question, like I do above, define an IBOutlet for the top and leading constraints instead, which greatly simplifies the process. This sample code was taken from a project where, for a variety of reasons, I couldn't use the IBOutlet for the NSLayoutConstraint references. But using the IBOutlet references for the constraints is definitely an easier way to go (if you stick with auto layout).

例如,如果您转到Interface Builder,您可以突出显示有问题的约束,并将 control -drag拖到助理编辑器中,使您的 IBOutlet

For example, if you go to Interface Builder, you can highlight the constraint in question and control-drag to the assistant editor to make your IBOutlet:

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

If you do that, rather than iterating through all of the constraints, you now can just say, for example:

if (self.imageViewVerticalConstraint)
{
    [self.view removeConstraint:self.imageViewVerticalConstraint];

    // create the new constraint here, like shown above
}



坦白地说,我希望Interface Builder有能力定义像这样的约束,即开箱即用(即,而不是超级左侧控制的领先约束,超级左侧的控制中心约束) ,但我不认为它可以在IB中完成,所以我改变了我的约束程序。但通过这个过程,我现在可以扩展控制,而不是因为限制移动我。

Frankly, I wish Interface Builder had the ability to define constraints like these right out of the box (i.e. rather than a "leading of control to left of superview" constraint, a "center of control to left of superview" constraint), but I don't think it can be done in IB, so I'm altering my constraints programmatically. But by going through this process, I can now scale the control and not have it move around on me because of constraints.

As 0x7fffffff指出,如果你应用 CATransform3DMakeScale 到图层,它不会自动应用约束,所以你不会看到它移动,如果你应用 CGAffineTransformMakeScale 到视图。但是如果你重新应用约束( setNeedsLayout 或对任何 UIView 对象进行任何更改都可能导致约束重新应用),视图将移动你。因此,如果您在重新应用约束之前将图层的转换还原为标识,那么您可能可以偷窥,但最好是关闭自动布局或仅修复约束。

As 0x7fffffff noted, if you apply a CATransform3DMakeScale to the layer, it will not automatically apply the constraints, so you won't see it move like if you apply CGAffineTransformMakeScale to the view. But if you do anything to reapply constraints (setNeedsLayout or do any changes to any UIView objects can cause the constraints to be reapplied), the view will move on you. So you might be able to "sneak it in" if you restore the layer's transform back to identity before constraints are reapplied, but it's probably safest to turn off autolayout or just fix the constraints.

这篇关于iOS:CGAffineTransformScale移动我的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆