showAnnotations when rotation changes - ios

I have a SplitViewController with a mapview on as the detailViewController.
I add multiple annotations to the mapview. After adding them I call the showAnnotations:animated: method to zoom in/out the map so that all the annotations are shown in the visible portion of the map.
mapView.showAnnotations(mapView.annotations, animated: true)
Now I need the map to refocus itself when the orientation changes because the mapview's visible area reduces when you turn the iPad to portrait. So I call the same showAnnotations:animated: method in viewWillTransitionToSize:withTransitionCoordinator: method which fires when the orientation changes. But it doesn't work as expected.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
mapView.showAnnotations(mapView.annotations, animated: true)
}
How do I make it refocus when orientation changes?
Demo project

Calling the showAnnotations within the viewDidLayoutSubviews method works perfectly.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
mapView.showAnnotations(mapView.annotations, animated: true)
}

Related

iPad screen rotation bug. Is there a way to lock rotation until the view has loaded?

Since the problem is hard to explain, here is a video attached.
The behavior above happens when I select a cell on a table view controller and it performs a segue to a tab bar controller. During the transition, I rotate the device to landscape mode and if done fast enough, the tab bar will disappear and the view will load on half of the screen and the other half stays black.
I did this in my app and I thought I was doing something wrong, so I made a new app with the same structure but no view controllers and this happens too.
I noticed, if the perform segue is not animated, this bug won't appear but I want the animation. I believe that delaying the screen rotation until the view has loaded will fix the problem.
Is there a way to lock rotation until the view has loaded?
Yes there is. But before we proceed to that, since I saw your video/issue, usually when needed, a view must be re-layouted. Not sure about the term, but you can adjust its constraints based on the current orientation.
Anyways, for the way to lock the rotation until you want it be unlocked, I've found this utility quite long time ago.
import UIKit
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")
}
}
This has been very helpful to me. Now to use it, it's no brainer.
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Lock immediately the rotation to portrait!
// Use lockOrientationAndRotateTo if it's needed.
AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Then finally, after loading something, enable rotation.
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
// Assuming that the loading takes 5 seconds or so.
AppUtility.lockOrientation(.all)
}
}
}
Good luck! I hope this helps!

viewWillTransitionToSize Calls Wrong ViewController in TabBarController

I have tabBarController application with 4 viewcontrollers. This application is landscape orientation enabled so I have viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator in each viewcontroller.m file to control the orientation changes.
The problem I'm having, is when I change the device orientation while in the 3rd viewcontroller, the viewWillTransitionToSize in the 2nd viewcontroller is called so the wrong code is ran.
How is it possible that the 2nd viewcontroller's viewWillTransitionToSize is even called? Especially, when it hasn't even been loaded yet. I know it hasn't been loaded because I NSLog it's viewDidLoad and it shows when I change orientation from the 3rd viewcontroller.
Additional Info: There is no code in the 3rd viewcontroller's viewWillTransitionToSize, viewWillAppear, viewWillDisappear, etc. that would reference the 2nd viewcontroller.
I'm using Xcode 8.2.1 and Objective-C code. Please help, thanks.
Test to see which UIViewController is the selected UIViewController before handling the transition.
In Swift:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{
guard self == tabBarController?.selectedViewController else { return }
// handle transition here
}
In my situation, the UIViewController was embedded in a UINavigationController so I had to handle it slightly differently:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{
guard self.navigationController == tabBarController?.selectedViewController else { return }
// handle transition here
}
I replaced each instance of
viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator
with
willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
to avoid the aforementioned issue with viewWillTransitionToSize...

IOS viewwilltransitiontosize method call all viewcontroller when rotate

My application has Tabbar and Navigation options. My problem is, when device is rotating to landscape, previous viewcontroller viewwilltransitiontosize is also calling
Let's explain the scenario,
The first screen is AssignmentViewController
The second screen is SubmissionListViewController
Both class I have override viewwilltransitiontosize method. when I rotate to landscape in the 2nd view controller time, it first calls AssignmentViewController's viewwilltransitiontosize method then it calls SubmissionListViewController's viewwilltransitiontosize
here is my piece of code
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("Landscape")
self.navigationController?.setNavigationBarHidden(true, animated: false)
self.landscapeVideo()
self.tabBarController!.tabBar.hidden = true
} else {
print("Portrait")
self.navigationController?.setNavigationBarHidden(false, animated: false)
self.videoinPortraitMode()
self.tabBarController!.tabBar.hidden = false
}
}
any idea or help please?

animating views when orientation changes not working

I have a view controller that i want to animate my views position when orientation changes.
i have some views set in storyboard and some added in the ViewControllers viewDidLoad.
I'm overriding
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({context in
self.myView.frame = CGRectMake(0,0,200,200);
}, completion: nil)
}
the size changes but not in an animation.
I also have a button that is set in storyboard with autolayout.
And it also moves according to its constraints but the change is not animated.
Am i missing something?

UINavigationController doesn't rotate when presenting child view controller

Here is my sample project
I have two view controllers embedded in a UINavigationController. On the first one, there is just a button performing a segue on the 2nd view controller. On the latter, a button dismiss it back to the 1rst view controller.
The 1rst view controller is not allowed to rotate and stays in Portrait while the 2nd is allowed to rotate in Landscape.
To do so, I added this code in the 1rst view controller:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
and added an extension to UINavigationController:
extension UINavigationController {
override public func shouldAutorotate() -> Bool {
if let topViewController = topViewController {
return topViewController.shouldAutorotate()
}
return false
}
override public func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if let topViewController = self.topViewController {
return topViewController.supportedInterfaceOrientations()
}
return .Portrait
}
}
On the 2nd view controller, I add programmatically a label with some autolayout constraints. The label's title show the UIDevice.currentDevice().orientation.
My problem is the following:
When I put the device on landscape when I'm on the 1rst view controller, it's fine, the layout is laid for Portrait but when I tapp the button to present the 2nd view controller, this one stays on Portrait instead of switching to Landscape.
And bigger problem for me as in my real project I set some constraints depending on the device orientation, the UIDevice.currentDevice().orientation return the Landscape position.
What's wrong? Is it a normal behaviour? How can I fix it?
In your sample project, you're not updating the label when the device is rotated. You should override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) Also, Apple recommends that you not use UIDevice orientation but rather just look at the bounds of your view controller's view. For example:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if size.height<size.width {
label.text = "Landscape"
} else {
label.text = "Portrait"
}
}
Calling UIViewController.attemptRotationToDeviceOrientation() in the viewWillAppear of the 2nd view controller did the trick.

Resources