So I'm working on an iOS 10 app using Swift 3 and Xcode 8.3.3.
In my app I have to take successively 8 pictures with indicators on the camera.
So I'm using AVCaptureVideoPreviewLayer for the custom camera and I need to set the view displaying the camera on landscape mode.
I did it using this extension that I found on stackoverflow while searching for the problem.
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
and in the viewDidLoad() of the customCameraView, I'm setting the locking the orientation to .landscapeLeft :
AppUtility.lockOrientation(.landscapeLeft)
before leaving the view I'm setting this in my viewWillDissapear method in order to unlock the orientation:
AppUtility.lockOrientation(.all)
The problem is that landscape mode in the customCameraView works only when the auto-rotation of the device is enabled (not locked) and when I get back to the previous view controller, it is initially displayed in landscapeLeft so I have to turn the device to put it portrait mode. this view is locked in portrait method using the AppUtility extension.
So I thought about always activate the auto-rotation by overriding the shouldAutoRotate var but it didn't work when the device auto-rotation is locked.
Then I thought about making sure that the auto-rotation is enabled before opening the camera but 100 of people on stackoverflow are saying that this is not possible.
So the perfect solution for me would be to always make the customCameraView in landscapeLeft mode and the previous view in portrait no matter if the rotate is activated or not.
I'm struggling on this bug for days now and a little help would be great.
iOS encourages developers to support both portrait and landscape, so it can be difficult to restrict one part of the app to be landscape while the other is portrait.
One option that works pretty well is to restrict the entire app to portrait mode in the project settings, and apply a rotation transform to any view controllers that need to be landscape. This way, the view will look and behave like it is landscape, and you have full control over the rotation of your views.
Can you apply below code on the required customCameraView Controller :
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeLeft
}
Related
I have read a lot on this topic but am not satisfied with my current solution.
I am creating a capture app that is primarily in portrait mode but I would like to force the camera view to be in landscape.
I've been using these simple functions to force the orientation to change in viewWillAppear in my capture view controller.
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
One issue is that the view controller still initially visibly loads in portrait and then rotates itself into landscape.
How do I force it to appear in landscape so that it never appears in portrait?
In the future, I may like to use portrait capture as well with behavior much like the default camera app (icons rotate but the capture button and preview remain the same. photos come out in the correct orientation). I'd like to design this interface in the storyboard so I can see both portrait and landscape views in storyboard by changing the device orientation.
How can I make the camera screen handle genuine device orientation change in the storyboard? I have found no clean solutions to doing this.
first time posting, so forgive me if I'm not giving the right info in my question...
I'm creating an app (in swift), and I want to support all screen orientations for all screens (and have set in Xcode general tab accordingly). There's a login / launch screen, and then the root controller for the rest of the app is a UINavigationController.
My problem - The screen keeps rotating back to portrait on any segue, even though the device is in landscape orientation, and the screens all support landscape! Is this the standard behaviour on a segue? And if so, can I prevent it somehow?
To be clear - I just want the screen rotation to continue to reflect the device orientation following a segue - and all screens currently support all orientations.
I've tried setting shouldAutorotate to return false for a given screen / view controller, and extended UINavigationController to refer to the visible view controller's shouldautorotate() function, as follows:
extension UINavigationController {
public override func shouldAutorotate() -> Bool {
return visibleViewController!.shouldAutorotate()
}
}
This prevents the rotation away from the (landscape) device orientation on segue, but of course then if the user rotates back to portrait the screen remains landscape...
It seems like this should be really straightforward, but I couldn't find any info or other questions on it, just questions about restricting allowed orientations (I just want the screen orientation to reflect the device orientation at all times)...
One thought - is there a way to detect whether the shouldAutorotate function is being called following a segue? And return false in this instance, but true otherwise?
Any help would be gratefully received!
Thanks
Dan
Add these 2 methods into your view controller:
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
I have an issue in one of my applications that I just discovered once I got the app onto an actual iPad, it isn't possible to see in the simulator. The issue is when I hold the iPad in landscape orientation, if I tip the iPad back to a certain angle the iPad stays in landscape mode but the view switches to my portraitView while still in landscape mode. In my code I have a function called screenRotated() that is an observer of UIDeviceOrientationDidChangeNotification. My function screenRotated() has the following code:
let interfaceOrientation: UIDeviceOrientation = UIDevice.currentDevice().orientation
if UIDeviceOrientationIsLandscape(interfaceOrientation) {
//does some stuff and then sets self.view = landscapeView
} else {
//does some stuff and then sets self.view = portraitView
}
How do I keep my app from going into the wrong view when in landscape orientation?
You issue will be that you are not handling device orientation notifications for orientations UIDeviceOrientationFaceUp and UIDeviceOrietationFaceDown. These are neither Portrait or Landscape and your code always picks Portrait when the orientation is not Landscape.
Hence as you are tipping back, it goes to orientation face up and your code picks Portrait as it is not landscape but face up.
So add code to detect faceup/down and ideally keep to the orientation last set until you see it actually go from Portrait to Landscape or the other way around.
The following should work:
if UIDeviceOrientationIsLandscape(interfaceOrientation) {
//does some stuff and then sets self.view = landscapeView
} else if UIDeviceOrientationIsPortrait(interfaceOrientation) {
//does some stuff and then sets self.view = portraitView
}
else{
// Do nothing
}
This topic has come up before (iPad modal view controller acting in portrait even though it's landscape) but I haven't found a clear answer - so I don't know if this is a duplicate or not.
In new single view project, I set the main view to landscape in xcode:
And the Property Inspector confirms this (as well as how the view is displayed in the storyboard):
And the ViewController orientation property is set to landscape:
Yet when I check the view frame in 'viewDidLoad' it reports portrait mode:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect theRect = self.view.frame;
NSLog(#" frame %f %f %f %f", theRect.origin.x,
theRect.origin.y,
theRect.size.width,
theRect.size.height);
}
2012-08-26 16:42:45.045 Test[2320:f803] cell 0.000000 20.000000
768.000000 1004.000000
I also force landscape in shouldAutorotateToInterfaceOrientation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
I've encountered this many times before and have had to set the frame explicitly to landscape but I have never understood why all the storyboard settings have no effect.
Am I missing something basic here?
Every application in iOS starts in portrait mode inititally, even if you specified the supported device orientations and give the right "answers" at shouldAutorotateToInterfaceOrientation:. It will always start in portrait and will the rotate to landscape if the device. The user maybe won't see it cause its so fast.
Because of this your app has to be able to rotate via shouldAutorotateToInterfaceOrientation even if your only supported orientations are landscape ones.
So to get a landscape orientation after start you should:
set the supported interface orientations in Xcodes Interface Builder
overide shouldAutorotateToInterfaceOrientation:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io {
return (io == UIInterfaceOrientationLandscapeRight);
}
give the interface a chance to rotate and do your view configuration afterwards
Regarding your question about the Xcode configuration of the the viewcontroller to landscape: Notice the title of the menu in the storyboard - it says: Simulated Metrics
This means that every modification you do there is just for the purpose to simulate it in the storyboard. But unless you do the necessary modifications to get to this state in the code it will have no effect.
Add below code in your view controller with swift 4.2
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeRight
}
I've created a view controller and set the orientation of the view to Landscape in XCode 4.2 (Interface Builder). However, when I add the view, the view is displayed in Portrait orientation. I've overriden ShouldAutorotateToInterfaceOrientation in all view controllers to return true, and I've attempted to rotate the view manually using the following code:
this.View.Transform.Rotate (3.14f * .5f);
I have also tried to set the frame to a landscape frame (i.e. 480 X 320), though the frame of the view is already set correctly.
Just to clarify, the vast majority of my views are in Portrait. I would like to load the landscape view in a landscape orientation, irrespective of what orientation the device is actually in. Is this possible? If so, what am I missing?
Thanks in advance for any assistance on this matter!
UPDATE: I'm noticing that ShouldAutorotateToInterfaceOrientation is only called once when the view is loaded. It is not called when the device is rotated. Is this normal behavior?
ShouldAutorotateToInterfaceOrientation is called every time the device orientation changes.
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
Console.Out.WriteLine(toInterfaceOrientation.ToString());
// Return true for supported orientations
// This particular screen is landscape only!
return (toInterfaceOrientation == UIInterfaceOrientation.LandscapeLeft || toInterfaceOrientation == UIInterfaceOrientation.LandscapeRight);
}
this code will only allow the view to orient itself in either landscapeleft or landscaperight mode, and writes the new device orientation to the console every time.
when you load the view, and push it onto (for instance) a UINavigationController however, it's still in portrait mode (and ShouldAutorotateToInterfaceOrientation is not called.)
From Objective-C, it's fairly easy to force a device orientation, but in MonoTouch, there appears to be no direct mapping.
the solution ;
Send a message to the objective-c runtime, specifying which orientation we want.
you can easily do this by adding the following to a view controller:
Selector orientationSetter;
private void SetOrientation (UIInterfaceOrientation toOrientation)
{
if (orientationSetter == null)
{
orientationSetter = new Selector ("setOrientation:");
}
Messaging.void_objc_msgSend_int (UIDevice.CurrentDevice.Handle,
orientationSetter.Handle, (int)toOrientation);
}
you can now manually change the orientation of the entire device.
What's more, is that if you use a UINavigationController, the orientation will return back to normal once this view is popped off the stack.
I think that for the Landscape view that you always want to display in Landscape Orientation, you need to return False within ShouldAutorotateToInterfaceOrientation or remove the override altogether. This will prevent the view from auto-rotating when the device is in portrait mode.