I am able to take MKMapView snapshot in portrait mode, but not in landscape mode. I automatically rotate my UIView to landscape using the functions given below. I can see the map-view as rotated to landscape. But, when I take snapshot using MKMapSnapshotter, I get an image with map in portrait mode again.
override var shouldAutorotate: Bool {
return true
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
My hunch is it has something to do with setting MKMapSnapshotOptions to landscape, but I am not sure how to do that.
let mapSnapshotOptions = MKMapSnapshotOptions()
mapSnapshotOptions.region = mapView.region
mapSnapshotOptions.scale = UIScreen.main.scale
mapSnapshotOptions.size = mapView.frame.size
I expect that above code should have handled it since map-view is already rotated to landscape, but it does not.
mapView.frame.size = (375.0, 647.0)
I observe the same value of mapView frame for both cases: portrait and landscape.
I tried using CLLocationManagerDelegate. But to no gain. The below function gets called when snapshot options are already set.
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
// heading is updated for delegates only after any transition has ended
// therefore, snapshot properties are set already by the time program reaches this function
mapView.camera.heading = newHeading.magneticHeading
mapView.setCamera(mapView.camera, animated: true)
}
Please suggest what more can be done?
Related
I want to know how to rotate a device even when a user turns on the portrait orientation lock in iPhone.
Like the amazon prime video app, normally I see the app is in portrait mode, but when I start watching a movie, the app changes its rotation to horizontal even when I turn on the portrait orientation lock.
When I googled it, I only found this article, but using CoreMotion is the only way to achieve what I want to do??
I was using the following code to rotate the device from this article,
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")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
But the app doesn't rotate from portrait to landscape automatically (from landscape to portrait works...), but when I rotate the device from portrait to landscape by my hand, the app's view rotates.
So, how can I make the device rotation to landscape when I'm into a specific view controller? (like the prime video app automatically turns the orientation to landscape when I start watching movie)
in AppDelegate following variable to lock all the controllers with given orientation
var orientationLock = UIInterfaceOrientationMask.portrait
Now implement following method in AppDelegate
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
Write these methods in separate Helper file
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: LocalizedKey.orientation.string)
}
Call this method in your specific controller's viewWillAppear()
override func viewWillAppear(_ animated: Bool) {
Helpers.lockOrientation(UIInterfaceOrientationMask.landscape,
andRotateTo: UIInterfaceOrientation.landscapeLeft)
}
NOTE: LocalizedKey.orientation.rawValue is string in separate file which have the value of "orientation"
I have a view controller, embedded in a tab bar controller, that, among other things, presents a AVCaptureVideoPreviewLayer in a UIView.
When the device is rotated, I want the view controller to rotate with it- except for the aforementioned UIView.
Unlike this related question, however, I am not just rotating/transforming my other views in the view controller. The other views need to use their configured autolayout rotation behavior.
I've tried several things, including simply setting the video orientation to portrait:
previewLayer.connection.videoOrientation = .portrait
to extracting the UIView to a separate view controller, embedding that view controller into the original view controller, and setting its autoRotation properties
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
but then I learned here that iOS only looks at the top-level view controller for those properties.
With everything I have tried, the video preview is rotating with the rest of the view controller- ending up sideways.
The only thing that works, but is hacky and sometimes causes the video preview to become misaligned, is this
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if let videoPreviewLayerConnection = previewLayer.connection {
if let newVideoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) {
videoPreviewLayerConnection.videoOrientation = newVideoOrientation
}
}
}
}
I basically need the opposite of this question.
How can I force the video preview to not rotate but also allow the rest of the view controller to rotate normally? (Same behavior as iOS Camera app except that the other UI elements rotate normally instead of the 90° rotation transform)
The following is possibly as hacky as your solution but it looks cleaner visually.
In viewWillTransition I set the affine transform of the previewView to counteract the orientation set by rotating the phone. It looks cleaner than just setting the videoOrientation as the affine transform animates at the same speed as the orientation change. It is done as follows.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let orientation = UIDevice.current.orientation
var rotation : CGFloat = self.previewView.transform.rotation
switch(orientation) {
case .portrait:
rotation = 0.0
case .portraitUpsideDown:
rotation = CGFloat.pi
case .landscapeLeft:
rotation = -CGFloat.pi/2.0
case .landscapeRight:
rotation = CGFloat.pi/2.0
default:
break
}
let xScale = self.previewView.transform.xScale
let yScale = self.previewView.transform.yScale
self.previewView.transform = CGAffineTransform(scaleX:xScale, y:yScale).rotated(by:rotation)
self.view.layoutIfNeeded()
}
Here is the extension to CGAffineTransform the code above uses
extension CGAffineTransform {
public var xScale: CGFloat {
get {return sqrt(self.a * self.a + self.c * self.c) }
}
public var yScale: CGFloat {
get {return sqrt(self.b * self.b + self.d * self.d) }
}
public var rotation: CGFloat {
get {return CGFloat(atan2f(Float(self.b), Float(self.a))) }
}
}
I'm trying to change orientation with just one view, the rest are anchored to Portrait. I've set a method in my AppDelegate as below
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if globalVariables.gIsDosageView == "Y" {
if UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight {
return UIInterfaceOrientationMask.all;
} else {
return UIInterfaceOrientationMask.portrait;
}
} else {
return UIInterfaceOrientationMask.portrait;
}
}
The global variable gIsDosageView is set to "Y" when the Dosage view is selected. I've created two separate views, portraitView (375x812) and landscapeView (812x375). I've used the viewWillTransition method to catch each change in orientation as below
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if size.width < 400 {
self.userImg.isHidden = false
self.deviceImg.isHidden = false
self.portraitView.isHidden = false
self.landscapeView.isHidden = true
}
else {
self.userImg.isHidden = true
self.deviceImg.isHidden = true
self.portraitView.isHidden = true
self.landscapeView.isHidden = false
}
}
When I go from the main screen to Dosage it displays the correct screen and will toggle between both orientation views without issue. However, if I go to another screen and come back to the Dosage screen it only shows the screen that was first loaded in both orientation screens. I've stepped through the code and it hides the right screens but this is not reflected in the resulting view. If I select the screen in portrait first, it will toggle successfully between portrait and landscape but if I go to the next screen and return to Dosage, it will only show the Portrait screen regardless of orientation and appears to ignore the code in viewWillTransition().
Why is this and what have I missed?
viewWillTransition is only called when the device is rotated. When you switch between open views without rotating, it won't get called, so won't set the view up how you want it. Try putting the test in viewWillAppear instead.
I need to a way to constantly monitor if the user has rotated the iPad.
UserDidRotate() {
if(orientation = portrait.upsideDown){
//
//Code that will Present View upside down...
//
}
else if(orientation = portrait){
//
//Code that will Present View right side up...
//
}
}
How can I check for orientation change and also manually present the view upside down for my Swift 3 app?
EDIT:
I have tried:
override func viewWillTransition(to size: CGSize, with coordinator:
UIViewControllerTransitionCoordinator){}
and that method is never hit.
Try:
self.view.transform = self.view.transform.rotated(by: CGFloat(M_PI))
I tried this code for scanning barcode:
https://www.hackingwithswift.com/example-code/media/how-to-scan-a-barcode
but it have a bug, when i change orientation of device, camera always has a Protrait orientation...
Any ideas how to fix this ?
I tried to change orientations in this method:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return .Portrait
}
But it not helps.
For a camera to change the orientation you don't want to use that function. Do this instead...
previewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.Portrait
What this does is when the camera layer is created it sets the orientation.