iOS: detect for Regular or Compact in Multitasking - ios

in my app I allow the multitasking mode.
But I need to do some action if my view is too restricted.
Watching Apple documentation I saw this image
You can see that in iPad Pro in SplitView, both views are regular, instead in other iPads both views are compact.
I there something that allow me to know if my current view is regular or compact?
Thanks

This is my solution:
if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular){
NSLog(#"REGULAR HORIZONTAL");
return TRUE;
}else{
NSLog(#"COMPACT HORIZONTAL");
return FALSE;
}

If you need to handle it programatically, you can override -traitCollectionDidChange: and look at the self.traitCollection property on that view and make changes depending on the output.
However -viewWillTransitionToSize:withTransitionCoordinator: will get you a more fine grained response to how big the view controller has been resized to.

Related

moving app to background, calls viewDidLayoutSubView and create a lot of warnings with UICollectionView

it's all start from a lot of warnings about the width of collectionView cells,
That was written to console every time I press home button.
I thought it's something with size of the cells and tried to fix it.
Only after some testing, I notice that viewDidLayoutView is called with wrong view.bounds, and that make the collectionView cell bigger(in width) than collection view.
For now, my fix is to check if app is on background state and ignore viewDidLayoutView.
why it's happen only in iPad and not on iPhone ?
it's whirred that only now I saw this happening. it's something new in iOS ?
what is the right way to handle this ? I don't use auto-layout
its calling with wrong bounds and I don't want to calculate all cells frames just for the user to return to the same orientation.
I feel like I'm missing something very basic here OR there is some change on iOS that I'm not aware.
why it's happen only in iPad and not on iPhone ?
Because when you click Home on an iPad and the app goes into the background, the runtime takes two snapshots, one in each orientation, to use in the App Switcher interface (and in preparation for when the app comes back to the front). That means it has to rotate the app, which triggers layout, and so your viewDidLayoutSubviews is called.
it's whirred that only now I saw this happening. it's something new in iOS ?
what is the right way to handle this ? I don't use auto-layout
its calling with wrong bounds and I don't want to calculate all cells frames just for the user to return to the same orientation.
I feed like I'm missing something very basic here OR there is some change on iOS that I'm not aware.
Well, iPads have been behaving like this for quite a long time. It isn't my job to explain why you haven't noticed. Basically you should not be doing anything time-consuming in viewDidLayoutSubviews.
for now, my fix is to check if app is on background state and ignore viewDidLayoutView
That's perfectly reasonable. I do the same sort of thing. For example (this is a different method, but it's the same idea):
override func viewWillTransition(to size: CGSize, with tc: UIViewControllerTransitionCoordinator) {
if UIApplication.shared.applicationState == .background {
return
}
// ...
}
Be warned, however, that if you are doing manual layout and you don't do it when the app when goes into the background, your App Switcher snapshots may look wrong. Also, the fact that you are not using autolayout is a red flag. You should probably use it.

Simple way of pushing view controller on iPhone and presenting as a form sheet on iPad?

Getting back into iPad dev after focusing on iPhone only for a while. I have a checkout view that I want to be pushed into a nav stack on iPhone, but presented in a modal form sheet on iPad. In a iOS 9+ world, is there a way to do this that does not involve doing something like
if ipad {
self.presentViewController()
} else {
self.navigationController?.pushViewController(viewController, animated: true
}
That method is somewhat simple. I mostly want to know if there's something I'm missing in terms of using traitCollections and some of the new adaptive bits iOS has added over the years that I'm missing.
To be clear, I'm not looking for different ways of doing the if statement. I looking if there is one method I can call that will automatically present/push as applicable.
You should consider using size classes to accomplish this. Even on iPad, there are situations in which you would have a skinny view, for which pushing the view on would still make sense. For example, if your app supported slide-over multitasking and you launched it as a slideover app, it would have a width of 300 points.
You can access the horizontalSizeClass through your view or view controller's traitCollection.
if self.traitCollection.horizontalSizeClass == .regular {
// present it
} else {
// push it
}
I would not recommend to do that but you can find a solution with UIUserInterfaceIdiom using it like that :
switch UIDevice.current.userInterfaceIdiom {
case .pad:
break // iPad
case .phone:
break // iPhone
case .carPlay:
break
case .tv:
break
case .unspecified:
break
}

Xamarin.IOS Landscape launch screen

i have a problem with launchscreens. I create a storyboard with image. At designer it looks great, but on simulator happen something terrible, like this. I can't understand how it works. Can somebody explain it ? And one more question: how implement different images at storyboard or xib for different languages, if it is possible?
You need to do a few things.
First you need to tell the app in the Plist file that it will be landscape
Configure your launch screen storyboard with the image you want to show. If you want to show a different image based on the language then you need to localize the image.
In the AppDelegate override the method below to allow the app return to the "normal" orientation when it has finished launching:
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
{
//select the option you need here
//if you only wants portrait use this: UIInterfaceOrientationMask.Portrait
return UIInterfaceOrientationMask.AllButUpsideDown;
}
This should works.

iOS5 Custom Window rotation issue

So I'm creating and showing a custom window in my iOS app because I'm writing a dynamic alert view that also functions like a growl/toast alert. It works AWESOMELY in ios6 (Hopefully I can open source this baby and you can all check it out)
But anyway, when I run this in ios5, the window that my alerts exist on doesn't seem to rotate with the device/simulator. No matter what, my custom window stays in portrait mode.
The UIWindow is just a UIView subclass, so there's no nice 'shouldRotate' delegate method.
I'm kinda stumped on why this is happening in ios5 but not 6. Any help would be GREATLY appreciated ^_^
My window has a rootviewcontroller, which I completely forgot about. I just needed to implement
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
To get it to work.
:-D
It's usually not recommended two use multiple instances of UIWindow in one iOS app. The only valid reason to do so is to support external screens. You should use a UIView instead, ideally managed by a UIViewController.
I assume, (since you didn't provide any code, I can only assume) the reason why your window doesn't 'rotate' is, that it's simply not getting any notifications about device rotation. Only the keyWindow receives them by default.
I would highly recommend to redesign your app to use a properly managed UIView instead. If you desperately don't want that for some reason, you would have to register your instance of UIWindow to receive the UIDeviceOrientationDidChangeNotification and then (in the handler) evaluate what the new orientation is and change the window's frame accordingly (plus maybe other things that need to be done in response to the orientation change)

iPhone app in landscape mode, 2008 systems

Please note that this question is from 2008 and now is of only historic interest.
What's the best way to create an iPhone application that runs in landscape mode from the start, regardless of the position of the device?
Both programmatically and using the Interface Builder.
Historic answer only. Spectacularly out of date.
Please note that this answer is now hugely out of date/
This answer is only a historical curiosity.
Exciting news! As discovered by Andrew below, this problem has been fixed by Apple in 4.0+.
It would appear it is NO longer necessary to force the size of the view on every view, and the specific serious problem of landscape "only working the first time" has been resolved.
As of April 2011, it is not possible to test or even build anything below 4.0, so the question is purely a historic curiosity. It's incredible how much trouble it caused developers for so long!
Here is the original discussion and solution. This is utterly irrelevant now, as these systems are not even operable.
It is EXTREMELY DIFFICULT to make this work fully -- there are at least three problems/bugs at play.
try this .. interface builder landscape design
Note in particular that where it says "and you need to use shouldAutorotateToInterfaceOrientation properly everywhere" it means everywhere, all your fullscreen views.
Hope it helps in this nightmare!
An important reminder of the ADDITIONAL well-known problem at hand here: if you are trying to swap between MORE THAN ONE view (all landscape), IT SIMPLY DOES NOT WORK. It is essential to remember this or you will waste days on the problem. It is literally NOT POSSIBLE. It is the biggest open, known, bug on the iOS platform. There is literally no way to make the hardware make the second view you load, be landscape. The annoying but simple workaround, and what you must do, is have a trivial master UIViewController that does nothing but sit there and let you swap between your views.
In other words, in iOS because of a major know bug:
[window addSubview:happyThing.view];
[window makeKeyAndVisible];
You can do that only once. Later, if you try to remove happyThing.view, and instead put in there newThing.view, IT DOES NOT WORK - AND THAT'S THAT. The machine will never rotate the view to landscape. There is no trick fix, even Apple cannot make it work. The workaround you must adopt is having an overall UIViewController that simply sits there and just holds your various views (happyThing, newThing, etc). Hope it helps!
From the Apple Dev Site:
To start your application in landscape
mode so that the status bar is in the
appropriate position immediately, edit
your Info.plist file to add the
UIInterfaceOrientation key with the
appropriate value
(UIInterfaceOrientationLandscapeRight
or
UIInterfaceOrientationLandscapeLeft),
as shown in Listing 2.
Listing 2: Starting your application
in landscape mode
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>
Summary and integration from all the posts, after testing it myself; check the update for 4.x, 5.x below.
As of 3.2 you cannot change the orientation of a running application from code.
But you can start an application with a fixed orientation, although doing so this is not straightforward.
Try with this recipe:
set your orientation to UISupportedInterfaceOrientations in the Info.plist file
in your window define a 480x320 "base view controller". Every other view will be added as a subview to its view.
in all view controllers set up the shouldAutorotateToInterfaceOrientation: method (to return the same value you defined in the plist, of course)
in all view controllers set a background view with
self.view.frame = CGRectMake(0, 0, 480, 320)
in the viewDidLoad method.
Update (iOS 4.x, 5.x): the Apple iOS App Programming Guide has a "Launching in Landscape Mode" paragraph in the "Advanced App Tricks" chapter.
References:
interface builder landscape design
interface builder landscape design-1
First I set in info.plist
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>
then I put this code in applicationDidFinishLaunching:
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
[window setTransform:rotate];
CGRect contentRect = CGRectMake(0, 0, 480, 320);
window.bounds = contentRect;
[window setCenter:CGPointMake(160.0f, 240.0f)];
This way I can work on the view in Interface Builder in landscape mode.
sasb's and michaelpryor's answer appears to be correct, but if it's not working for you, try this alternative:
- (void)applicationDidFinishLaunchingUIApplication *)application {
application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;
}
Or this one:
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
Or this one:
[application setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO];
You may also have to call window makeKeyAndVisible; first.
A few links: Developing in landscape mode, iPhone SDK: How to force Landscape mode only?
#Robert: please refer to The iPhone SDK, NDA, and Stack Overflow.
I'm surprised no one has come up with this answer yet:
In all my tests when a dismissing a modal view controller the parent view controller's preferred orientation set in shouldAutorotateToInterfaceOrientation is honored even when part of a UINavigationController. So the solution to this is simple:
Create a dummy UIViewController with a UIImageView for a background. Set the image to the default.png image your app uses on startup.
When viewWillAppear gets called in your root view controller, just present the dummy view controller without animation.
when viewDidAppear gets called in your dummy view controller, dismiss the view controller with a nice cross dissolve animation.
Not only does this work, but it looks good! BTW, just for clarification i do the root view controller's viewWillAppear like this:
- (void)viewWillAppear:(BOOL)animated
{
if ( dummy != nil ) {
[dummy setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:dummy animated:NO];
[dummy release];
dummy = nil;
}
...
}
The latest iPhone OS Programming Guide has a full section on this, with sample code. I am sure this is a recent addition, so maybe you missed it. It explains all the conditions you have to comply with; basically...
set the Info.plist properties (this changes the position of the status bar, but not the view)
rotate your view manually around its center, on either your UIViewController viewDidLoad: method or your applicationDidFinishLaunching: method or implement auto rotation ("Autoresizing behaviors", page 124)
Look for "Launching in Landscape Mode", page 102.
See this answer: Landscape Mode ONLY for iPhone or iPad
add orientation to plist
shouldAutorotateToInterfaceOrientation = YES in all files
Although if you're using mixed modes, you might be better off with
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

Resources