Problem after dismissing a modal view used in conjunction with a uisplitviewcontroller

为君一笑 提交于 2019-12-08 05:53:47

问题


I'm having a hard time understanding why the following is happening (and how to fix it).

I've created an application using the split-view based application.

I've added a UiBarButtonItem called showTheModal which calls this method found in RootViewController.m:

- (IBAction)showTheModal:(id)sender {
theModalController.modalPresentationStyle = UIModalPresentationFullScreen;
theModalController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:theModalController animated:YES];

if ([detailViewController popoverController] != nil)
    [[detailViewController popoverController] dismissPopoverAnimated:YES];

The BarButtonItem of course, is shown at the bottom of the Default Root Controller (left side of the of the split view in landscape) or at the bottom of the popup (if in landscape).

The modal view is dismissed by a button placed in a toolbar. It calls the following:

[self dismissModalViewControllerAnimated: YES];

The problem I'm having is if rotate the screen, while the modal is up. Here is what happens in different scenarios (start refers to the orientation when the showTheModal button is hit, end refers to the orientation when I hit the dismissModal button).

1)Start landscape, end landscape: Everything appears fine. willHideViewController and willShowViewController methods are not called in the RootViewController (as expected)

2) Start landscape, end portrait: UI appears fine. willHideViewController is run TWICE (WHY?)

3) Start portrait, end portrait: UI appears fine. willHideViewController is run once (as expected)

4) Start portrait, end landscape: The 'Root List' button remains in the detail view (right side of the split view. Neither willHideViewController and willShowViewController are invoked (WHY??)

Any thoughts as to why #2 and #4 don't behave quite the expected way?


回答1:


I've had exactly the same problem (#4, above). I worked around it using viewDidAppear:animated, and then checking the height of the view to see if it is in landscape vs. portrait. (Yuck, gag, etc.) I'm not satisfied at all with that "solution".

Possibly related: I've noticed that the button in portrait mode is slow to disappear after rotating to landscape, i.e. the button appears for a second after the rotation finishes. However, in Mail.app, the "Inbox" button disappears as soon as the rotation starts. Is Apple doing things differently than they recommend in their docs? Perhaps there is a more efficient way to show/hide the master view button?




回答2:


Unfortunately this is not a bug. It appears to be an expected behavior.

I found this in iOS Release Notes for iOS 5.0, in "Notes and Known Issues" section:

Rotation callbacks in iOS 5 are not applied to view controllers that are presented over a full screen. What this means is that if your code presents a view controller over another view controller, and then the user subsequently rotates the device to a different orientation, upon dismissal, the underlying controller (i.e. presenting controller) will not receive any rotation callbacks. Note however that the presenting controller will receive a viewWillLayoutSubviews call when it is redisplayed, and the interfaceOrientation property can be queried from this method and used to lay out the controller correctly.




回答3:


For diagnostics, have you tried dismissing the popover view first? Or logging who is calling the method by printing (id) sender?




回答4:


I was having the same exact problem.

In answer to (2), it appears to be a bug. I noticed that when a modal view is pushed over a splitview, the orientation messages are queued up somewhere and not processed until the modal view is dismissed and the splitview is visible but I would still expect to only get one callback.

For (4), this too appears to be a bug. Fortunately, the didRotate... events still get through, so my solution was to subclass UISplitViewController and explicitly call the delegate's willShowViewController method in this case:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

    //Work around a bug where UISplitViewController does not send 
    //willShowViewController after a modal is presented in portrait
    //but dismissed in landscape.
    UIInterfaceOrientation orientation = self.interfaceOrientation;
    if ( (orientation == UIInterfaceOrientationLandscapeLeft )
        || (orientation == UIInterfaceOrientationLandscapeRight) )
    {
        UINavigationItem* item = [detail.navigationBar.items objectAtIndex:0];
        UIBarButtonItem* barButtonItem = [item leftBarButtonItem];
        [super.delegate splitViewController:self willShowViewController:master invalidatingBarButtonItem:barButtonItem];
    }
}

Here, "master" is an IBOutlet that refers to the master view controller (left hand side) of the splitview and "detail" is an IBOutlet for the detail view controller (right hand size).

Note that in my case, the detail view is a UINavigationController. You may require different code to get the barButtonItem from your view controller.

Also, this has the side-effect of calling willShowViewController twice for normal rotation, but that is not an issue in my case.




回答5:


I think that this is a bug that needs to be reported to Apple Development.

I worked around part of this issue by presenting my modal view using the UIModalPresentationPageSheet format.



来源:https://stackoverflow.com/questions/2795665/problem-after-dismissing-a-modal-view-used-in-conjunction-with-a-uisplitviewcont

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!