5

I'm having some trouble with UIView animations on iPad.

I'm working on a project in which I have implemented a "facebook style" menu on the left, using the JTRevealSidebar framework.

This framework works perfectly, however, instead of "pushing" the right side view off the screen, I would like to resize it, so the user can still see the whole content of the right-side view.

I have managed to do this by changing the view's frame as well as doing the offset.

This is what it looks like with the sidebar open:

enter image description here

And when it's closed:

enter image description here

This right-side view contains a navigation bar with two buttons (one button on the left to toggle the left sidebar, and another button on the right to dismiss the controller), and the content itself is a simple UIWebView.

The problem I am facing is during the animation (from the full-screen state to the sidebar open state):

When I change the view's frame, even after doing the translate, the view resizes before the animation starts, which gives a weird effect like this:

enter image description here

I would like to keep the right side of the webview anchored to the right side of the screen and only have the left side change position when animating (basicaly so that the "done" button is always in the same position).

Here is the animation code:

- (void)revealSidebar:(BOOL)shouldReveal {

    if (shouldReveal) {

        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.3];

        // Push the view to the right
        contentView.transform = CGAffineTransformTranslate(contentView.transform, CGRectGetWidth(sidebarView.frame), 0);

        // Resize the view so it fits on remaining part of the screen
        contentView.frame = CGRectMake(contentView.frame.origin.x, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);


        // The problem is here: the view's frame is changed before the
        // Translate transformation actualy starts...
        //
        // Is there a way to change the x origin and the width simultaneously ?

        [UIView commitAnimations];


    } else {
        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.3];

        // Reset the frame so that it takes up whole screen
        contentView.frame = CGRectMake(contentView.bounds.origin.x,contentView.bounds.origin.y,contentView.frame.size.width+sidebarView.frame.size.width,contentView.frame.size.height);

        [UIView commitAnimations];
    }

    _state.isShowing = shouldReveal ? 1 : 0;
}

I've had no luck so far, and was wandering if anyone had any ideas as to how I could achieve this.

Thank you

Mutix
  • 4,196
  • 1
  • 27
  • 39

1 Answers1

2

EDIT 2:

It seems that the subviews are being immediately resized dueto translations being used. So maybe you could just animate the move to the right and then when that has finished set the width:

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    contentView.frame = CGRectMake(CGRectGetWidth(sidebarView.frame), 0,     contentView.frame.size.width-CGRectGetWidth(sidebarView.frame),     contentView.frame.size.height);
}

- (void)animationDidStopBack:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {   
    contentView.frame = contentView.bounds;
}

- (void)revealSidebar:(BOOL)shouldReveal {     
    if (shouldReveal) {
        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.1];
        [UIView setAnimationDelegate:self];
        contentView.frame = CGRectOffset(contentView.bounds, CGRectGetWidth(sidebarView.frame), 0);
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
        [UIView commitAnimations];
    } else {
        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationDelegate:self];
    contentView.frame = CGRectMake(0, 0, contentView.frame.size.width+CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
        [UIView setAnimationDidStopSelector:@selector(animationDidStopBack:finished:context:)];
        [UIView commitAnimations];
    }
    _state.isShowing = shouldReveal ? 1 : 0;
}

It's not perfect but does avoid the blank space on the right and I feel looks better because of that. Particularly if you speed up the animation.

EDIT 1:

try:

[UIView beginAnimations:@"" context:nil];
[UIView setAnimationDuration:0.3];
if (shouldReveal) {
    contentView.frame = CGRectMake(CGRectGetWidth(sidebarView.frame), 0, contentView.frame.size.width-CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
} else {
    contentView.frame = CGRectMake(0, 0, contentView.frame.size.width+CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
}
[UIView commitAnimations];

Old Answer:

sounds /looks like you just need your x position modifying to always be at the edge of the sidebar. untested code assuming your contentview's origin is at far left:

- (void)revealSidebar:(BOOL)shouldReveal {

    if (shouldReveal) {

        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.3];

        // Push the view to the right
        contentView.transform = CGAffineTransformTranslate(contentView.transform, CGRectGetWidth(sidebarView.frame), 0);

        // Resize the view so it fits on remaining part of the screen
        contentView.frame = CGRectMake(contentView.frame.origin.x, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);

        [UIView commitAnimations];

    } else {
        [UIView beginAnimations:@"" context:nil];
        [UIView setAnimationDuration:0.3];

        // Resize the view so it fits on full screen
        contentView.frame = CGRectMake(sidebarView.frame.size.width, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);

        [UIView commitAnimations];
    }

    _state.isShowing = shouldReveal ? 1 : 0;
}

if the origin is actually centred then:

contentView.frame = CGRectMake(sidebarView.frame.size.width+(contentView.frame.size.width/2), contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);
ader
  • 5,403
  • 1
  • 21
  • 26
  • Thanks for your answer. The sidebarView itself actually never moves. All we do is move the contentView right/left to cover/uncover the underlying sidebarView. The problem is that when animating this, the change in width is happening before the change in x origin. I have edited my question to be more precise: is there a way to change the origin and width of the contentView simultaneously ? – Mutix Dec 12 '11 at 16:32
  • ah. It now sounds like I would take a two-pronged approach. First I would try to modify it so that the origin of contentView is at the far right and make sure normal functionality works okay. Then all you should need to do is animate the width. – ader Dec 12 '11 at 17:10
  • I am saying to not animate the origin. Make it always be at the right hand side. Instead of animating the origin, just set it. contentView.frame.origin = CGPointMake(contentView.frame.size.width, 0); Then animate the width change as and when you want to. – ader Dec 13 '11 at 10:36
  • When you create the contentview, move it's origin to far right and position it so that it IS on screen (which is what I meant by "make sure normal functionality works okay"). – ader Dec 13 '11 at 11:20
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5810/discussion-between-mutix-and-ade) – Mutix Dec 13 '11 at 12:05