6
votes

I have a UILabel, hardWayLabel, inside of a UIView, hardWayView. I need this view (and consequently the label) to animate to a new position on the far left side of the screen. However, while the label goes to the correct position, the view can be seen continuing to move far off of the left side of the screen. I use the following code for the animation (which I use many other times in my app successfully):

        CGRect frame = hardWayView.frame;
        frame.origin.x = painPoint.x;
        frame.origin.y = painPoint.y;
        hardWayView.frame = frame;
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:.25];

I have used NSLog to make sure that painPoint.x and painPoint.y are what they should be 9which is confirmed by the fact that the UILabel ends up in the correct position. I guess the real question is why would the UIView continue to move past the screen boundaries (and only do so in this instance when the UIView is being animated from the screen's center to the left)?

I do have Autolayout enabled, though I do not think that this is the culprit. This problem occurs when I run the app on the iPhone Simulator with iOS 7, and I am unable to get the simulator to run with iOS 6 so am not able to isolate the issue to iOS 7 (though could it be? I began development in an old version of Xcode and the app does not use storyboards).

Here is a screen recording of the issue. As you can see, moving the two views from the left to the right works normally. Though when moving the views back to the left, one of the views (the black background) appears to go off screen through the top left corner while the label (in orange text) goes to the correct location). Explanatory video

Update: Here's some more code. It is near identical to other parts of my application that work flawlessly, which is a bit of a brain blaster.

NSString *stringOfRands = tDict[@"originalRand"];
if ([stringOfRands rangeOfString:@"+"].location != NSNotFound)
{
     NSArray *arrayOfRands = [stringOfRands componentsSeparatedByString:@" + "];

     for (int z=1; z<[arrayOfRands count]; z++)
     {
          NSString *updateValue = arrayOfRands[z];
          NSInteger newHiddenPosition = [self findBlank:leftSpaces];

          NSDictionary *updateStuff = @{@"updateValue": updateValue, @"workingMasterDict":tDict, @"newPos":@(newHiddenPosition), @"newCGPto":@"left", @"@parent":colorV};

          [self revealHidden:updateStuff];

      } 
}

I believe the problem is truly happening during the revealHidden method, where the animation is called.

[leftSpaces replaceObjectAtIndex:[hardWayPos intValue] withObject:[NSString stringWithFormat:@"full"]];
CGPoint painPoint = [[leftPoints objectAtIndex:[hardWayPos intValue]] CGPointValue];    
[UIView animateWithDuration:0.25 animations:^{
        CGRect frame = hardWayView.frame;
        frame.origin.x = painPoint.x;
        frame.origin.y = painPoint.y;
        hardWayView.frame = frame;
    } completion:^(BOOL finished) {
        //
    }];

hardWayView.hidden=0;
hardWayView.backgroundColor = [UIColor blueColor];
hardWayLabel.textColor = [UIColor orangeColor];

I have tried making frame.origin.x and .y actual numbers (versus variables) and the same pattern ensues: the UILabel animates to the correct location and the UIView animates off from the top left corner of the screen

3
Turn off autolayout and test it. It's probably the culprit.Joel
@Joel alas no. The same movement happens with Autolayout turned off.zch
First you are modifying the frame and then you are starting the animation.Exploring
@zch, would you mind sharing your project so I can take a look at it at my end?LuisCien
@LuisCien thank you for your time. I have just added some more code to the original question, but I also just added the viewcontroller.h and .m to a Github repo github.com/zchr/modx (I really apologize for the lack of cleanliness, and I added ERROR HERE comments just above the code snippets in question. One thing worth noting is the amount of repetition. Firstly it means that I need to be making more methods, but secondly I think it's interesting that this same animation code works just fine in other areas of the app.)zch

3 Answers

10
votes

Whooaa! After muuuch debugging I finally found the issue!! :) Let me tell you... you have some interesting code there. Anyway, you'll be surprised to know how silly the issue was; you ready?

Here is the problem:

Around line 540 you have an extra "@" sign, that's why when you try to retrieve the value it can't find it:

//ERROR HERE
NSArray *arrayOfRands = [stringOfRands componentsSeparatedByString:@" + "];

for (int z=1; z<[arrayOfRands count]; z++)
{
    NSString *updateValue = arrayOfRands[z];
    NSInteger newHiddenPosition = [self findBlank:leftSpaces];

    // This is the line with the error!!
    // You have @"@parent" but it should be @"parent"      
    NSDictionary *updateStuff = @{@"updateValue": updateValue, @"workingMasterDict":tDict, @"newPos":@(newHiddenPosition), @"newCGPto":@"left", @"@parent":colorV};

    [self revealHidden:updateStuff];

}

It was very interesting to debug your code!

Cheers :)

6
votes

From the looks of it you are setting hardWayView.frame = frame; before the animation starts so the UIView will change location and then animate. Switching places between

hardWayView.frame = frame;
[UIView beginAnimations:nil context:nil];

should fix it.

Regardless, I would strongly advise moving to animation blocks. The code above should look like this:

[UIView animateWithDuration:0.4 animations:^{
CGRect frame = hardWayView.frame;
frame.origin.x = painPoint.x;
frame.origin.y = painPoint.y;
hardWayView.frame = frame;
} completion:^(BOOL finished) {
    //
}];
1
votes

Wouldn't it be better to have code inside the completion block? (Or before the animateWithDuration block).

[UIView animateWithDuration:0.25 animations:^{
                CGRect frame = hardWayView.frame;
                frame.origin.x = painPoint.x;
                frame.origin.y = painPoint.y;
                hardWayView.frame = frame;
            } completion:^(BOOL finished) {

            hardWayView.hidden=0;
            hardWayView.backgroundColor = [UIColor blueColor];
            hardWayLabel.textColor = [UIColor orangeColor];

            NSDictionary *hardWay = @{@"view": hardWayView, @"label": hardWayLabel, @"intValue":[NSString stringWithFormat: @"%@", hardWayLabel.text], @"hiddenBool":@0, @"position":@([hardWayPos intValue]), @"originalRand": [NSString stringWithFormat: @"%@", hardWayLabel.text]};
            [masterDict replaceObjectAtIndex:[masterDict indexOfObject:miniMaser] withObject:hardWay];

            }];

In addition, if it was me I would use a distinct name for each rect too to aid debugging. e.g. don't always call your rect "frame". Call it centerFrame, leftFrame, rightFrame.

When you log out the frame of the hardWayView at the end of the animation does it report what you expect?

When you log out the frame of the hardWayView at the start of the animation does it report what you expect?

My guess is the frame of hardWayView is not what you think it is.

Does it work as you expect if you set the frame directly without animating it?