Autolayout breaks UIView Animation
Asked Answered
W

3

7

Struggling to make my app work on both the iPhone 5 and the smaller iPhone's prior. Would be happy to require iOS6 and use Autolayout because that works great.

However, the app has 4 buttons that regularly swap positions, so I assign each button a different location from an array and then animate the movement with something like this:

[UIView animateWithDuration:0.5 animations:^{
    button1.center = [[locations objectAtIndex:0] CGPointValue];
    button2.center = [[locations objectAtIndex:1] CGPointValue];
    button3.center = [[locations objectAtIndex:2] CGPointValue];
    button4.center = [[locations objectAtIndex:3] CGPointValue];
}];

This doesn't work with Autolayout. Nothing changes. The best I've gotten is that it will animate to a position then immediately snap back.

When I remove Autolayout however all the buttons are scrunched up on the smaller iPhones, and because I'm using points set by the iPhone 5 size they end up lower down, putting the bottom row off the screen. I original had different CGPoint numbers that I got from Interface Builder, but they were "wrong", though I'm thinking they were "wrong" because they were the numbers for Autolayout to use. The array just so you can see:

buttonLocations = [NSArray arrayWithObjects:
        [NSValue valueWithCGPoint:CGPointMake(57, 523)],
        [NSValue valueWithCGPoint:CGPointMake(109, 523)],
        [NSValue valueWithCGPoint:CGPointMake(57, 471)],
        [NSValue valueWithCGPoint:CGPointMake(109, 471)],
        nil];

What should I do to fix this problem? Setting different points for each sized device doesn't seem very efficient.

Wanettawanfried answered 14/12, 2012 at 17:32 Comment(0)
N
12

The solution is that you animate the items transform property, not its position.

The position is going to be set by autolayout and you don't want to fight it. The actual position on the screen, though, is going to be its "correct" (set by auto layout) position, offset by its transform property.

So you can say button.transform = CGTransformMake(x,y) and it will appear x and y off from it's center position.

There are a variety of CGWhatever macros to make these transforms easily, and you can just change them in an animation block to move the items around.

Nahshun answered 6/6, 2013 at 23:28 Comment(2)
I get this issue: Assigning to 'CGAffineTransform' (aka 'struct CGAffineTransform') from incompatible type 'int'?Wanettawanfried
what's the type of button.transform? It shold be CGAffineTransform. You're assigning the output of CGAffineTransformMakeTranslation() or some other function that produces a CGAffineTransform right? Looks like you're trying to pass an int. CGAffineTransform produces a transform.Nahshun
A
2

One way would be to use the auto layout system, and animate the "constant" value of the constraint. In the example code below, I have three buttons in a horizontal row, each with a leading edge constraint to the superview, which is what I animate. side1, side2, and side3 are IBOutlets to those constraints, and button1, button2, and button3 are the outlets to the 3 buttons.

-(void)animateButton {
    [self.view removeConstraint:self.side1];
    [self.view removeConstraint:self.side2];
    [self.view removeConstraint:self.side3];

    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:self.button1 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:114];
    NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:self.button2 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:213];
    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:self.button3 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:20];

    [self.view addConstraints:@[con1,con2,con3]];
    [UIView animateWithDuration:2 animations:^{
        [self.view layoutIfNeeded];
    }];
}
Aixlachapelle answered 14/12, 2012 at 18:3 Comment(4)
if button1, button2 & button 3 are the IBOutlets to the UIButtons in interface builder, how would I set up side1, side2 & side3 in the project?Wanettawanfried
@WilliamRobinson, When you add the buttons to the view, the constraints will be added automatically. You might have to change them though. If the buttons are all lined up vertically and either have explicit sizes set or are set to use intrinsic content size, then the only other constraint they should need would be the leading edge to superview -- if there are any others (like from trailing edge) you can delete them. Once you have the correct constraints, you can connect outlets to them just like any other object.Aixlachapelle
Is this when I click a UIButton and in the Utilities view click the ruler and see long list of things such as: "Constraints" "Height Equals: 50", "Align Leading To: Button -4" etc?Wanettawanfried
@WilliamRobinson, that's one place you see them, but you have to make the connections in the object list on the left side of the workspace. If you click the disclosure triangle for the view that contains these buttons, there should be a constraints entry.Aixlachapelle
P
0

You can fix this problem with very little changes in your code. Instead of swapping the button locations, swap their layout constrains. You can use the cocoapod SBP to swap the layout constrains by importing this category

    #import "UIViewController+SBP.h"

Then using this method

    - (void)switchViewConst:(UIView*)firstView secondView:(UIView*)secondView durationInSeconds:(double)durationInSeconds

Here is a video tutorial.

Plenitude answered 15/11, 2015 at 21:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.