0
votes

I have a series of (say) boxes on the screen in a row, all subviews of my main view. Each is a UIView. I want to shift them all left and have a new view also enter the screen from the right in lockstep. Here's what I'm doing:

// First add a dummy view offscreen
UIView * stagingView = /* make this view, which sets up its width/height */
CGRect frame = [stagingView frame];
frame.origin.x = /* just off the right side of the screen */;
[stagingView setFrame:frame];
[self addSubview:stagingView];

And then I set up animations in one block for all of my subviews (which includes the one I just added):

[UIView beginAnimations:@"shiftLeft" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(_animationDidStop:context:)];        
[UIView setAnimationDuration:0.3];
for (UIView * view in [self subviews]) {
    CGRect frame = [view frame];
    frame.origin.x -= (frame.size.width + viewPadding);
    [view setFrame:frame];
}
[UIView commitAnimations];        

Here's what I expect: The (three) views already on screen get shifted left and the newly staged view marches in from the right at the same time.

Here's what happens: The newly staged view animates in exactly as expected, and the views already on the screen do not appear to move at all! (Or possibly they jump without animation to their end locations).

And! If I comment out the whole business of creating the new subview offscreen... the ones onscreen do animate correctly!

Huh?

UPDATE: After some more poking around, I found something amazing: I can fix the problem by making my custom subclass of layoutSubviews return without doing any work if it's called between the time the animation is set up, and the time it completes. That method needs to be doing some work to tweak the position of these subviews during orientation changes. But I don't really understand the interplay of the animations with this method-- I would think it would get called eventually perhaps at the end, which would make sense and which should essentially be a no-op after the animation. Can anyone explain the interaction to me? It seems like I'm close to enlightenment but not quite there yet. Thanks!

1
I see your problem - you're using comments where your view initialization and frame.origin.x declaration should be! :) But seriously, that last line in the add-view block: is that supposed to be [self stagingView];, or are you missing something (like a call to addSubview:)?Tim
What does [self stagingView]; do? Where do you add stagingView as a subview? "Or possibly they jump without animation to their end locations" could you clarify? Do they move or not?pheelicks
Er, yeah, typo fixed. :) That is, of course, a call to addSubview: that got mangled in my copy/paste/edit-for-clarity.Ben Zotto

1 Answers

1
votes

As with the commenters, I am curious why you would call

[self stagingView];

I imagine it is because you are trying to trigger drawRect:. I also wonder why you haven't added it as a subview in the example code, though I imagine you have done it somewhere.

I have 2 things that might help:

1.Don't animate the "boxes" individually. Create a container view for them, then just animate the container view. Simple!

OR

2.Don't rely on [view subviews] to work properly. Keep your own array of the boxes you want to move (an ivar) and iterate over that instead.