33

What I'm doing:

In my app, I'm presenting a modal view controller (containing app settings) using the following code:

    optionsViewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
    [self presentModalViewController:optionsViewController animated:YES];

This transition just curls up the bottom part of the view to expose a few settings. (See the 'Maps' app for an example.) When you tap on the top half of the page, where the original view is still there but grayed out, the modal view controller is automatically dismissed (handled by the OS, I didn't code for this).

-

What's not working:

This is working fine in iOS 4 (my app is currently on the App Store in fact). But in iOS 5, it looks like Apple have changed the behavior of this transition, and the view controller no longer dismisses itself. I'm trying to replicate the behavior that was handled by the OS before, but can't figure out how to.

-

What I've tried:

Adding an invisible button to the top of the options view doesn't work. The page then curls up the full way, which I don't want.

Apart from this, I'm stuck. How should I replicate how this worked originally (or was I doing it the wrong way from the start!). Any help is much appreciated!

Jordan Smith
  • 10,310
  • 7
  • 68
  • 114
  • iOS 5 is under NDA. You can't discuss it. Remember it is still a beta and therefore things can change between now and when it is released. – Nick Bull Jul 02 '11 at 17:49
  • @Nick I understand that. But given that other transitions of the same type seem to work ok in other apps, it's possible that I may have been doing it the wrong way all along. – Jordan Smith Jul 03 '11 at 00:45
  • This was a problem on older versions of iOS 5 beta, it should be fixed on 5 beta 7 – aryaxt Sep 26 '11 at 20:30
  • this question doesn't appear to be answered in my mind. isn't the question why the page curl won't dismiss when you click on the top part of the screen? –  Oct 30 '11 at 21:46
  • @iradik Yes that's the question. It seems to have been fixed in the final release of iOS 5. I accepted the answer with the most upvotes, as the same problem (although a slightly different implementation than mine) seems to be fixed by this answer. It is also the answer that others will find most helpful, as the other issue has been fixed by Apple. – Jordan Smith Oct 30 '11 at 23:16
  • It's not fixed in iOS 5. It only dismisses the modal view if you click the curly part of the view. Otherwise, it won't dismiss. I had to add a tap gesture recognizer to the underlying view to get the same behavior. –  Oct 31 '11 at 23:03
  • @iradik it's still fixed as opposed to not doing anything at all though - that's the main thing. I guess you're right really, seeing as your solution replicates the original behavior - so if you post an answer with your solution I'll accept it. Maybe include the alternate (currently accepted) solution too, as it seems to be the most helpful to users as they implement their modal view controller a different way. – Jordan Smith Oct 31 '11 at 23:10
  • ok i did what you have asked. let me know if the solution makes sense. seems weird to insert my solution to the accepted answer, but i went ahead and did that since you asked me to. –  Nov 01 '11 at 00:41
  • @iradik ok thanks. I actually just meant you to do a seperate answer with the current answer included too - but what you did instead is fine. I think it makes more sense to leave the accepted answer as it is now though, but with your addition too. Thanks :) – Jordan Smith Nov 01 '11 at 09:30

6 Answers6

71

Dude, I ran into the same problem.. and here is what I found about using parentViewController:

Note that as of 5.0 this no longer will return the presenting view controller.

This was written in the header file of UIViewController...

I am using ShareKit, and the modalViewController was working perfectly in iOS4, but in iOS5, it just won't dismiss itself! This is because in their code, they are using:

    [[currentView parentViewController] dismissModalViewControllerAnimated:animated];

and parentViewController will return nil, since this is a modal presented view controller...

By searching for a solution, I found your question.. So, I decided to fix it myself :P

I changed the previous line to this:

    [currentView dismissModalViewControllerAnimated:YES];

Works like a charm.


EDIT: Depending on how you interpret the original question, there are two answers. Here's the second:

In iOS5 it seems that the modal controller only dismisses itself when you click the curl, but not above the curl or the backgound. In iOS5, in order to actually get the modal view to dismiss itself when tapping the background or above the curl I added the following code to the controller, to listen to taps on the modal view, but ignore taps to buttons. This should mimic the behavior in previous version of iOS when working with a modal controller with page curl.

- (void)viewDidLoad
{
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    tap.numberOfTapsRequired = 1;
    tap.numberOfTouchesRequired = 1;
    tap.delegate = self;          
    [backgroundView addGestureRecognizer:tap];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    //change it to your condition    
    if ([touch.view isKindOfClass:[UIButton class]]) {      
       return NO;
    }
    return YES;
}

- (void)handleTap:(UITapGestureRecognizer *)sender {
    [self dismissModalViewControllerAnimated:YES];
}
Jordan Smith
  • 10,310
  • 7
  • 68
  • 114
Mazyod
  • 22,319
  • 10
  • 92
  • 157
  • 1
    Awesome! This isn't exactly the same as the problem I had, although pretty close. I'd say the new change in behavior is the same problem I've got - so should be able to work out a solution from this. Thanks! – Jordan Smith Jul 08 '11 at 00:38
  • Looks like the exact issue I was having has been fixed in the latest beta - however, the issue was likely to be due to this cause. This subtle difference is likely to lead to other iOS 5 compatibility problems, so take note! – Jordan Smith Jul 31 '11 at 13:31
  • 1
    how do I ensure this is backwards-compatible with devices running iOS 4? – jowie Oct 20 '11 at 09:38
  • 1
    Wish I could offer more than one upboat on this one. Nice – thanks for the clear code examples. Spared me a good bit of puttering around, I'm sure. – Danilo Campos Dec 18 '11 at 00:10
  • Note: In iOS 6, dismissModalViewControllerAnimated: is deprecated. Use dismissViewControllerAnimated:completion: instead. – Matt Becker Aug 22 '13 at 13:19
15

What's the code you're using to dismiss the modal view controller? I've seen code like this:

[self.parentViewController dismissModalViewControllerAnimated: YES];

that doesn't work on all versions of the OS. However, this:

[self dismissModalViewControllerAnimated: YES];

should.

Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • 2
    In iOS 4, I don't need to do anything - the operating system handles it. In iOS 5, this seems to have changed (at least for now). The code above is what I would use, but I don't know how to receive touches on the top half of the view (where this code woud then be run). See the 'maps' app for how it should work. – Jordan Smith Jul 03 '11 at 00:39
  • 1
    This is deprecated in iOS 6. Use `dismissViewControllerAnimated:completion` instead. – Dan Dyer Jan 21 '14 at 13:39
1

I had the same problem, also affects those who use:

 [self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];

I fix it with a Observer, adding this where you had the dismiss:

[[NSNotificationCenter defaultCenter] postNotificationName:@"yourObserverName" object:self];

And this in the parent parent view controller:

// add in viewDidLoad for example
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalVCFromParent:) name:@"yourObserverName" object: nil];

//The function
- (void) dismissModalVCFromParent:(NSNotification *)notif
{
   [self dismissModalViewControllerAnimated:YES];
}

// Don't forget remove
[[NSNotificationCenter defaultCenter] removeObserver:self];
Luis Ascorbe
  • 1,985
  • 1
  • 22
  • 36
0

This seems to work on the (now final version of) ios 5.

I notice that you have to tap is a specific region to dismiss the page curl - tapping near the edges of the top portion of the screen does not seem to do anything, but the center, blurred section above the page curl graphic consistently results in dismissing the modal view.

I'm not sure whether that narrow tap region behavior is new to ios 5 or already existed and I never noticed before. Hopefully that is helpful!

benvolioT
  • 4,507
  • 2
  • 36
  • 30
0

Thanks guys, this saved me a lot of time. I just noticed that the presentModalViewController and dismissModalViewController methods are deprecated according to the source code for UIViewControoler.h. There are alternative presentViewController and dismissViewController methods.

lhan
  • 4,585
  • 11
  • 60
  • 105
0

In iOS5 it seems that the modal controller only dismisses itself when you click the curl, but not above the curl or the backgound. In iOS5, in order to actually get the modal view to dismiss itself when tapping the background or above the curl I added the following code to the controller, to listen to taps on the modal view, but ignore taps to buttons. This should mimic the behavior in previous version of iOS when working with a modal controller with page curl.

- (void)viewDidLoad
{
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    tap.numberOfTapsRequired = 1;
    tap.numberOfTouchesRequired = 1;
    tap.delegate = self;          
    [backgroundView addGestureRecognizer:tap];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    //change it to your condition    
    if ([touch.view isKindOfClass:[UIButton class]]) {      
       return NO;
    }
    return YES;
}

- (void)handleTap:(UITapGestureRecognizer *)sender {
    [self dismissModalViewControllerAnimated:YES];
}