UI for dismissing View Controller presented by UIPopoverPresentationController regardless of Size Class - ios

I have a Universal app, Xcode 7 Beta, targeting iOS 8.
I am presenting a View Controller using UIPopoverPresentationController.
When presented in any Regular Size Class (e.g. Full screen iPad in any orientation), the View Controller appears as a popover, at the size I have set in the preferredContentSize property. A tap outside the bounds of the View Controller will dismiss the popover.
When presented in Compact Width Size Class (e.g. any iPhone in portrait orientation), the "popover" will become a full screen view, sliding in from the bottom to the top.
The Problem
While an iPad popover has built-in dismissal behaviour (i.e. tap outside of the popover), "popovers" presented full-screen do not. And thus need some UI in order to provide the user with a way to dismiss the popover.
Question
What is the best (recommended?) way to present a UI such that it only appears for the Compact Width Size Class, in order to give the user an option to dismiss the (full screen) "popover" View Controller?
Discussion
One approach I have seen is to embed the [View Controller to be presented] in a UINavigationController. A bar button is added to the Navigation Bar, though whose outlet we can tell the presenting View Controller to dismiss the presentation.
However, not only does this require an extra, unwanted hierarchy for the otherwise simple presented View Controller on the iPad, but it requires environment checking (idiom? size class?) in viewDidLoad to programmatically hide the NavigationBar if a Regular Width Size Class (e.g. iPad) is being used. This strikes me as... fragile.
Another option is to do the above, but use Size Classes within Interface Builder to Install/Uninstall the Navigation elements, non-programmatically.
Thoughts?
Related link, discussing the detection of popover mode

Look at Interface Builder, you can make available any view depending on the Size Class currently running on your app :) If i remember well (because I can't check for now as I'm in a bus) you can specify a view to be available in a specific Size Class in the Property Inspector tab of the selected view. That way you just have to add a button or a navigation bar with items in your view and make it available only for Compact widths :) I'll check more specificaly today to take you some screenshots :)

Related

xcode and iPhone simulations show weird top grey bar behind views after navigation, how to remove them?

I am trying to update an old Storyboard and viewControllers. in Interface Builder, my viewControllers has the following grey bar that I do not know how and why they are appearing, they were not there previously:
These are also visible when I try to simulate my apps in the iPhone simulator as follow:
When I start my app, the views are stretched with a tiny view of this space as follow:
However, when I start navigating to other viewControllers the space is visible as shown in the previous screenshot.
Any idea of how to stretch my views all the way to cover these areas?
I am currently using swift. The navigation is being done using Storyboard Segue.
Thank you.
This is just the storyboard showing the way the screen will be presented, that grey bar represents the view that will be behind that view controller. This kind of presentation is called modal (page sheet or form sheet) the two have different effects on iPad
Code Fix
To fix this, change the modalPresentationStyle to overCurrentContext on the view controller you're going to present. So in code do viewControllerToPresent.modalPresentationStyle = .overCurrentContext
Storyboard Fix
in storyboard select the segue (the line linking the two screens) and then on the far right menu select the item 3rd in from the right, you should see a section called presentation, change it to Current Context.

How to know when a view controller is presented using a 'form sheet' modal presentation style

When presenting a view controller modally, we can set the modalPresentationStyle to .formSheet:
In a horizontally regular environment, the view controller is sized so that its content area is smaller than the screen size and a dimming view is placed underneath the content...
In a horizontally compact environment, this option behaves the same as UIModalPresentationStyle.fullScreen.
I would like my modally presented view controller to update its layout based on whether it is being presented in this reduced-width form style, or as a full screen presentation. But The modal's horizontal size class is always compact, even when full screen on an iPad Pro in landscape.
The horizontal size class of the presenting view controller can tell me what I need to know (as Apple's docs mention above). But that means observing changes in traitCollection in every view controller than can present my modal, just so they pass them on to the modal view controller.
Is there some way for the modal view controller itself to know which style it is using, and be alerted when it changes so it can respond?
One slightly-gross way to at least know the applications size class:
UIApplication.shared.delegate?.window??.rootViewController?.traitCollection

Present UIActivityViewController in a way that Adapts Correctly to Size Class Changes

The documentation of UIActivityViewController says the following:
On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
This does not make too much sense since we have Size Classes, and modally presented viewcontrollers adapt their appearance automatically to it (e.g. when we present something as a popover, it will by default be presented as a popover in Size Class Regular, and fullscreen in Size Class Compact).
Presenting the UIActivityViewController in a popover for current Size Class Compact (which should automatically show fullscreen) does not work, the system complains. Presenting it as a popover for current Size Class Regular, and then changing the Size Class via Split Mode / Multitasking results in an empty nav bar and I cannot dismiss the viewcontroller. I should notice that I embedded the UIActivityViewController in a navigation controller.
Any suggestions how to make this responsive?
You must not embed the UIActivityViewController in a UINavigationController. I know it doesn't say so in the docs, but that's the only way I got it to work. And then you can actually present it the same way as you would do with any other popover/modal view. And it adapts correctly when you active Split Mode while it is being presented.

iPad Modal "Log In" View

I've never developed for the iPad before (just iPhone) and there are some views you see on an iPad that you cannot do on an iPhone. Specifically, I'm trying to create a modal 'login/register' type view and I'd like it to mimic the look and feel of the Log In view in the Zillow iPad app.
In Zillow when you press 'Log In' (or Settings for that matter), the background darkens and a window appears in the middle of the screen modally with a flip animation about it's horizontal axis. Here you are given a view containing buttons, text fields, toggle switches, etc.
Is there a cocoa class for this type of view on the iPad? Can you have a regular UIViewController not take up the entire screen and display 'on top' of the root view controller?
EDIT: Just discovered in the View Controller Attributes Inspector, under Simulated Metrics for Size, there is the Form Sheet option which looks similar to what I am going for. These will display on-top of root views?
You present the view modally, or in a storyboard, do a modal segue. In the inspector for the segue, you can change the presentation from default to "form sheet".
If you're doing the modal presentation in code, you can set the modalPresentationStyle property of the controller you're presenting to UIModalPresentationFormSheet.
As you said in your edit, in the storyboard, you can change the size of the view you want to present by setting the size in Simulated Metrics to "form sheet". However, this has no effect on what size the view will appear at run time. It's only used so you can properly layout your view visually. You need to use one of the ways I mentioned above to get the view to appear at the form sheet size.

Show a translucent/transparent modal view with support for device rotation

I want to show a translucent/transparent modal view that should cover the entire screen except status bar. Also, I shall be having different layouts for portrait and landscape orientation (in that modal view). I have done thorough googling and found some solutions. Below, i am summarizing them as well with their problems:
Add a view directly to the window: This works nice, but the problem
is device rotation. If I go by whatever I have experimented/learnt
so far, the UIWindow bounds do not change on rotating
the device. This poses a problem - I can't have my landscape modal
view unless until I do some sort of transformation on my view -
something which I am reluctant to. I am also not sure, whether it
will work, as I may have a webview of 1/3rd of the screen height and
full device width in portrait (rest area is translucent), and 1/4th of the screen width, full device
height (minus status bar) in landscape. I read that window changes the bounds (size and coordinate space orientation as well) of Root View controller's view bounds - can't I ask it to change the bounds of my modal view as well? After all Root controller view is also added to the window as a subview only.
Adding the modal view to the root controller
view: This is working fine for me so far with my custom root
controller based app. The problem is, I have to write my code as a
generic module, so that it can be used with different types of
applications. So, if the application root controller is one of the
out of the box container root controller ( like
UINavigationController, UITableViewController, etc ), then, is it
allowed to add a subview directly to their view ? i.e. is is not against the
Apple guidelines? While reading documentation, I read somewhere that
we should not play with standard UI controls, like Buttons.
While reading documentation, I also read it somewhere that UIAlertViews are
shown using another Window. How do we do that? is it normal to add
another window to the app? If things are as per the Apple
guidelines, I can try this approach - I shall make my modal view
the root view of another window and display that window.
What I am trying to achieve is very similar to showing UIAlertView, only in my case, I want my view to be fully customizable.
Thanks,

Resources