Launch Screen that behaves exactly like Launch Image - ios

In order to get iPad Pro to use full resolution at launch, we have to use a Launch Screen File.
I've never used a Launch Screen XIB/Storyboard before, because my app is backwards compatible to iOS 7. Normally I use a LaunchImage asset catalog to define a specific static image for each device dimension and launch orientation.
Now I'm trying to define a Launch Screen File that acts like a LaunchImage asset catalog, but I'm struggling to do it. In particular:
1) I don't see a good way to select a different UIImage depending on the exact size of the device, e.g. show one image to iPhone 4S users and another image to iPhone 5 users.
2) I don't see a way to select a different UIImage for iPad Portrait and iPad Landscape views. Size classes seem to think that both iPad Portrait and iPad Landscape are "Regular" width and "Regular" height, so any UIImage that would show up on iPad Portrait will also show up in iPad Landscape.

The system loads the launch file before launching the app which creates some constraints on what it can contain (some of which may force you back to static image files):
1.The app is not yet loaded so the view hierarchy does not exist and the system can not call any custom view controller setup code you may have in the app (e.g. viewDidLoad)
2.You can only use standard UIKit classes so you can use UIView or UIViewController but not a custom subclass. If you try to set a custom class you will get an Illegal Configuration error in Xcode.
3.The launch file can only use basic UIKit views such as UIImageView and UILabel. You cannot use a UIWebView.
4.If you are using a storyboard you can specify multiple view controllers but there are again some limitations. For example you can embed view controllers in a navigation or tab bar controller but more complex container classes such as UISplitViewController do not work (at least not yet).
5.Localizing the launch file does not currently seem to have any effect. The base localization is always used so you will probably want to avoid text on the launch screen.
6.You cannot specify different launch files for iPad and iPhone. This may be a problem if you have significantly different interfaces for those devices as there is only so much you can do with auto layout and size classes.
Note that if you are deploying to iOS 7 you will still need to include the static launch image files. You can include both a launch image file and static launch images. Devices such as the iPhone 6 running iOS 8 will use the launch image file whilst iOS 7 devices will fallback to the launch images.

First create all your images. Then, open up your asset catalog and right click -> App Icons & Launch Images -> New iOS Launch Image. This will create an file to drag all your files into. Do that. Name the asset "Launch."
Create a new launch screen storyboard with command-n. Choose iOS -> User Interface -> Launch Screen. Call the file "Launch Screen."
In your Launch Screen storyboard, select the view controller's view
[.
Find the UIImageView placeholder from the object library in the bottom corner of the right side ba, and drag it into the launch screen view.
Now, select the image view in the storyboard, and type in the name of the image from your asset catalog.
Control drag from the UIImageView to it's container view to set up auto layout constraints as follows :
Optional... if you want it to look nice in your storyboard, select the view and do option-cmd-= to update the frame of the UIImageView.
Go to your info.plist, and type the name of your storyboard ("Launch
Screen") for the key "Launch screen interface file base name"
Clean and run.
Hope that helps and that I didn't forget anything!

You can use Size Classes to specify different images for different screen sizes, but this not help you handle cases of iPhone 4S and iPhone 5 screens

A different approach is using spacer views that position the correct image in the visible area and move the other one off screen (see my original answer to a similar question here).
You can't provide different images for different screen sizes (iPhone 4, iPhone X, ...), but if you want different images for iPhone and iPad and different images for portrait and landscape this solution is for you.
I created an example project on github if you want to try it out.
It works on iPad and iPhone.
The important constraints are
PortraitSpacer.width ≤ 5 × view.width
PortraitSpacer.width ≤ 5 × view.height
LandscapeSpacer.width ≥ 5 × view.width
LandscapeSpacer.width ≥ 5 × view.height
PositionSpacer.width = 5 × view.width
where view.width and view.height are the main view's width and height.
The PortraitSpacer positions the portrait image at 5 × min(view.width, view.height),
the LandscapeSpacer positions the landscape image at 5 × max(view.width, view.height),
and the PositionSpacer has the same width as PortraitSpacer in portrait mode and the same width as LandscapeSpacer in landscape mode.
We multiply everything with 5 so the two images do not overlap. This works for all devices where the following is true
5 × min(view.width, view.height) + max(view.width, view.height) ≤ 5 × max(view.width, view.height)
In landscape mode this would mean
5 / 4 ≤ view.width / view.height
which is the case for all current devices: iPad has the lowest aspect ratio with 4:3 which is still greater than 5:4.
You can then of course configure images per device (iPhone, iPad) in the asset catalog.

This is a solution for iPad that can work,
for iPhone you can use size classes and I am not posting that solution here.
The solution is to break up your splash screen image into components and to use constraints to manipulate the image for Portrait vs Landscape.
Here is an example of how I did it.
Create a launch storyboard for iPad
UILaunchStoryboardName~ipad (UILaunchStoryboardName~iphone )
Take your landscape image in my case 2048x1536
I took the landscape image and cut it into three
Center 1536x1536
Left 256x1536
Right 256x1536
On the launch storyboard I created 3 image views with the following constraints
Center Piece:
Pin to Top and bottom,
center in superview,
maintain aspect ratio
Left & Right Piece:
0 Trailing/Leading to Center,
Align Top,
Equal Height
Then for the Mode of the view for the left and right I changed it from aspect fill to bottom right and bottom left (worked best for me)
I know this seems like overkill for something that should be simple. My reason for using the launch storyboard over launch images was to cut down on app size. I needed fewer launch images and I could use jpeg rather than png

Related

Possible with launch storyboard?

The height of the upper toolbar of my photo app varies from one screen size to another...
On 4" screens, the height is 40 points
On 4.7" and 5.5", it's 30% of the screen height
On other screens, it's 77 points
Considering those specifications, would it be possible to use a launch storyboard?
In a Launch Screen storyboard you can use variations that are based on size classes. Unfortunately in your case that does not work because in portrait mode all iOS Devices share the same height size class (Regular). So size classes are of no help here.
If the Launch Screen would be a "normal" UIViewController you could update the height constraint of your upper toolbar programmatically. This does not work for a Launch Screen because it is displayed before you app is even running. You cannot change anything programmatically in a Launch Screen. So this does not work either.
What you could do is to set different Launch Images (depending on screen size) using your app's asset catalogue:
Select your Asset catalogue in the Project navigator.
Press the "+" and select "App Icons & LaunchImages" → "New iOS Launch Image"
Now you can add different Launch Images for different Devices:
I'm afraid this is the only way that you can address the different devices screen sizes.

How do you set up 'image sets' to match launchImage files for all devices?

NOTE: This question is NOT related to launch image storyboards.
INFO: BG Buddy is a landscape only app. The launch screen uses images in a launchImage.xcassets file.
The launch image transitions to a UIViewController containing a full screen UIImageView with the same BG Buddy Background image as used in the launch image, and some textual UIButtons. This gives the impression that the buttons appear on top of the background image after a short time when the app has loaded.
Here is how the BG Buddy Background image set has been set up since the app’s release. Transitions from Launch Image to UIViewController work perfectly on iPad, iPhones 5,6,7,8 and 6,7,8 Plus.
The iPhone X and the iPhone Plus both seem to use the iPhone 3x image slot but both have very different dimensions. I’ve opened up the other size classes slots and tried to find a place with much confusion and no success. NOTE: All iPhones apart from the iPhone Plus use compact width/compact height size classes when in landscape. The iPhone Plus uses regular width/ compact height in landscape orientation.
So how do you set up 'image set' files to match launchImage files for all devices?
At the moment I can either have a good iPhone X transition or a good iPhone Plus transition but not both.
Is my only option to try to detect if it’s an iPhone X (or iPhone Plus) and swap the images programatically?
So here's the solution for a landscape only app. Hopefully it will help a little for portrait orientations too. Landscape bespoke launch images should be placed as shown with these width/height class settings.
Use the launchImage.xcassets screenshot at the top of the question to set up your launchImage.xcassets.

Set images for different iphones and debug

I am currently developing an ios app and the scope is limited to iPhones only and portrait mode only.
In each screen there are images, buttons, labels and textFields. The question here is, how do I render appropriate image for device from the Images.xcassets?
What I am doing now, written below -
From Sketch design application, exporting my images for 1x, 2x and 3x (Screens designed by a UI designer)
Adding them to Xcode project (drag and drop from finder to xcode)
Add new image set in Images.xcassets (naming it as "MyImages") and drag drop my images for 1x, 2x, 3x.
In the storyboard, on a viewcontroller, adding an ImageView
For the image view, selecting Image as "MyImages" from Attribute Inspector.
Once the above steps are complete, when I test the app on simulators starting from iphone4s, iphone5, iphone5s, iphone6 and so on.. (all the simulators available on Xcode 7.3), I don't see the appropriate image is being rendered.
Is my approach correct?
Also, how do I debug a UI element on the screens? Like, how/where do I check for what image is rendered? Its size (W X H)?
Added Screenshot
#Lohith Korupolu:
The screen shot you provided is for universal size (iPhone/iPad). From the additional information provided in comments, this would lead to issues with AutoLayout constraints that would stop the image showing on screens of a smaller size than that shown in your StoryBoard.
E.g. I have replicated your issue on storyboard...
This results in the following in Simulator for iPhone 4s....
i.e. Text is there but NO IMAGE.
REASON: The autoLayout Constraints set for the larger "Universal" Screen on any of two opposite sides would make the image invisible/ disappear when viewed on a smaller screen.
SOLUTION:
1. Clear the Autolayout constraints for this selected Image in Storyboard. See next picture...
2. Add AutoLayout constraints as below x2 pictures. (Top constraint, Height + Width) (horizontally in container). Remembering to tick "Items of new constraints" for both.
3. Run Simulator for iPhone 4s... E.g.
** The same situation is occuring with the other iPhone size simulator Runs. **
****** All Working ******
They should all be 2x images for iPhones apart from the plus size iPhones which should be 3x. Is that not what you are seeing?
In terms of debugging / checking this - you can put place holder images in your assets with labels or different colour tints to distinguish them from each other and then replace them later with images that give the desired final appearance once you know that everything is working as expected.
Using 2x images for iPhones approach works fine, however, there is another more straight forward way without having to resort to multiple image files for 1x, 2x, 3x in Xcode, by use of good large quality PDF (vector).
1. Create a Large PDF of the image/Graphic image you want to use
2. Import it into 'Assets.xcassets' - drag and drop (Into Xcode)
3. Go to the utilities panel on the right for the 'Attributes Inspector' (when the image is selected)
See Screen shot (a)
Under 'Scale Factors' the selection from 'Multiple' to 'Single Vector'
Now when you got to 'StoryBoard' and add the image - Simply select the PDF's name.
Xcode will automatically render it to correct size etc at run time for you. All the work is done by Xcode.
Exceptions:
It does not work well with images for icons inside the TabBar or Navigation Bar Items.
Note:
Vector graphics are sharp and ideal for High Definition (HD), but although Xcode accepts the Image Asset as a vector from the PDF, it doesn't seem to keep the vector but converts it into an actual image with pixelation problems when zoomed in, from a HD perspective.

Launch screen.storyboard for Portrait and Landscape vs split screen

I have to implement split screen functionality for the new iPad and I got a workaround from Apple's doc to support the same in my app: https://developer.apple.com/library/prerelease/ios/documentation/WindowsViews/Conceptual/AdoptingMultitaskingOniPad/QuickStartForSlideOverAndSplitView.html#//apple_ref/doc/uid/TP40015145-CH13-SW1
In this doc, check the 2nd point:
Provide a LaunchScreen.storyboard file (instead of a .png image file
as you did in iOS 7 and earlier)
This is why I have to use Launch screen.storyboard. Now, the split over works perfect but for my app I have separate Launch screens, Default-Portrait and Default-Landscape. But now I have taken storyboard, I am unable to customise launch screens for different orientations. And even I can't code for the same in Launch screen or it gives me error.
Further, I have tried using size classes to provide separate imageviews for both orientations but I got no success.
It would be great help if anyone suggests me how to implement Launch screen.storyboard for Landscape and Portrait with different images.
You can add a UIImage to your launch screen. Once you've done that and set the constraints to fill the width and height then add an image to your asset catalogue.
On the properties of the image within the catalogue set the 'width class' and 'height class' to 'Any & compact'. Then you'll have spaces for images for Any and compact height (landscape) and Any and compact width (portrait). The just put your artwork in to the appropriate artwork placeholders and use that image on your storyboard.
I believe that will then choose the appropriate artwork for you depending on how the device is held when the app launches.

Adaptive launch screen storyboards: is there a way to differentiate iPad orientations?

I'm investigating the use of a storyboard for launch images for my app. The app has always used a large photo for the launch image, which is also used as the background for the first view. However the image is different when the app is launched in landscape on an iPad.
So is there any way to differentiate between an iPad in portrait and an iPad in landscape when using a an Adaptive storyboard for a launch screen? Because it's a launch screen I can't run any code, it would have to be done completely through the storyboard.
I found a solution using spacer views that position the correct image in the visible area and move the other one off screen (as suggested by David H).
You can't provide different images for different screen sizes (iPhone 4, iPhone X, ...), but if you want different images for iPhone and iPad and different images for portrait and landscape this solution is for you.
I created an example project on github if you want to try it out.
It works on iPad and iPhone.
The important constraints are
PortraitSpacer.width ≤ 5 × view.width
PortraitSpacer.width ≤ 5 × view.height
LandscapeSpacer.width ≥ 5 × view.width
LandscapeSpacer.width ≥ 5 × view.height
PositionSpacer.width = 5 × view.width
where view.width and view.height are the main view's width and height.
The PortraitSpacer positions the portrait image at 5 × min(view.width, view.height),
the LandscapeSpacer positions the landscape image at 5 × max(view.width, view.height),
and the PositionSpacer has the same width as PortraitSpacer in portrait mode and the same width as LandscapeSpacer in landscape mode.
We multiply everything with 5 so the two images do not overlap. This works for all devices where the following is true
5 × min(view.width, view.height) + max(view.width, view.height) ≤ 5 × max(view.width, view.height)
In landscape mode this would mean
5 / 4 ≤ view.width / view.height
which is the case for all current devices: iPad has the lowest aspect ratio with 4:3 which is still greater than 5:4.
You can then of course configure images per device (iPhone, iPad) in the asset catalog.
Apple these days encourages you to think of rotation not in terms of device orientation, but just as an animated bounds change (sometimes with a semantic hint).
We saw why with the iPhone 6 Plus — what used to be a "phone, portrait" interface becomes a sidebar interface in landscape on certain phones.
The more your view controllers assume about devices and their orientation, the harder is is to adapt to new devices that offer new ways of reusing view controllers.
Also, UIDeviceOrientation is not the same as UIInterfaceOrientation. If you use the former to make UI decisions, you'll be stymied when the device is face-up or face-down, and (IIRC) your users will be frustrated when your app doesn't respect Orientation Lock.
So what's the difference between a landscape and portrait iPad? Both are Regular x Regular in traits... But one has bounds that are taller than they are wide, and vice versa. It's totally okay to make high-level layout decisions based on aspect ratio (and use auto layout for the details).
You actually can specify different launch screen images from inside of your LaunchScreen.storyboard with Xcode8. Using a LaunchScreen.storyboard is the preferred way of specifying a launch screen when targeting devices running iOS8 and above.
Here’s a quick step-by-step example of how to specify landscape images for the devices that support landscape launch screens:
First add your your “splash screen” images to your projects Assets.xcassets. You should only need two separate Image Sets: one for portrait and one for landscape. Name them something like splash (this is the portrait image set) and splash-landscape (this is the landscape one).
Now that you have your images in your projects assets go to your LaunchScreen.storyboard file. (I’m assuming you already have your launch screen view controller set up with the image and it’s constraints set up in the LaunchScreen.storyboard.)
Select the ImageView that is in you launch screen’s viewcontroller.
Go to the Assets Inspector for the ImageView.
Add the “splash” image to the Image source field. This is your portrait image source.
Click the + button next to the Image source field that you set up in step 5.
From the pop-up that is now displayed select Regular for both the Width and Height selectors. This is specifying a new adaptive set for iPads that are in landscape. A new image source field will appear with the title wR hR. Add the “splash-landscape” image to the wR hR Image source field so the storyboard knows to use a different image when in landscape.
Now we need to add support for the “iphone plus” devices when in landscape. So click the + button next to the Image source field again.
This time select compact for the height and regular for the width selectors. This is specifying a new adaptive set for “iPhone plus” devices that are in landscape. A new image source field will appear with the title wR hC.
Add the “splash-landscape” image to the wR hC Image source field so the storyboard knows to use a different image when in landscape on an “iphone plus device”.
By following these steps you won’t have to write any code, do anything weird, or rely on the old launchScreen image sets. The LaunchScreen.storyboard will handle everything for you! It’s pretty neat.
For more information on Size Classes and the Interface Builder check out the awesome article: https://medium.com/#craiggrummitt/size-classes-in-interface-builder-in-xcode-8-74f20a541195
Edit: This is just a brief contrived example of what I think I did to get the SplashScreen images to work using separate image sets, adaptive sets, and constraints. It took a lot of messing around with to get it to work (pretty much a whole night and then some). It’s tough to explain the Interface Builder and all the different aspects of it in a step by step post. So use this answer and example as a guide to get to where you need to be. Also, the link above is very helpful. Also, who knows, maybe I’m just wrong or misunderstanding something...
Hope someone will find this helpful.
The device orientation is pretty straightforward to check on the fly, and also receive notifications for orientation changes.
(Everything here is in Objective-C)
Head over to your App Delegate, and in your applicationDidFinishLaunchingMethod
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//
//then call this, what we're telling the device is, "Hey, let me know when you change orientations!"
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
//Not done yet, now we have to register a method to call on the notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}
Now, you'll want to define the method that is called when the device is oriented.
so, somewhere in your app delegate...
- (void) deviceOrientationDidChange {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait) {
//do something if portrait
}
else {
//do another thing if landscape
}
}
And that's really all there is to it. You can then change your background image in that method!

Resources