iOS: How to run a function after Device has Rotated (Swift) - ios

I have one UIView which is not using Auto-Layout and some components are displayed based on their percent of X and Y co-ordinates from the main view.
Previously I would have run a function to update their positions in didRotateFromInterfaceOrientation however I see this is now deprecated in iOS8.
I've taken a look at viewWillTransitionToSize but it's giving weird results, and there doesn't appear to be a viewDidtransitionToSize function.
Is there an easy way (in Swift) to run a function after a device rotation?

The viewWillTransitionToSize delegate method gets called with a UIViewControllerTransitionCoordinator conforming object. A method that protocol declares is animateAlongsideTransition(_:animation, completion:). You can use that to have code execute after the transition is complete.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: nil) { _ in
// Your code here
}
}

Although not asked for here Objective C version:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
// change any properties on your views
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
if( UIDeviceOrientationIsPortrait(orientation) ) {
NSLog(#"portrait");
} else {
NSLog(#"landscape");
}
}];
}

Related

How can I set the same transformation for all the cells in a collection view? [duplicate]

I have one UIView which is not using Auto-Layout and some components are displayed based on their percent of X and Y co-ordinates from the main view.
Previously I would have run a function to update their positions in didRotateFromInterfaceOrientation however I see this is now deprecated in iOS8.
I've taken a look at viewWillTransitionToSize but it's giving weird results, and there doesn't appear to be a viewDidtransitionToSize function.
Is there an easy way (in Swift) to run a function after a device rotation?
The viewWillTransitionToSize delegate method gets called with a UIViewControllerTransitionCoordinator conforming object. A method that protocol declares is animateAlongsideTransition(_:animation, completion:). You can use that to have code execute after the transition is complete.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: nil) { _ in
// Your code here
}
}
Although not asked for here Objective C version:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
// change any properties on your views
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
if( UIDeviceOrientationIsPortrait(orientation) ) {
NSLog(#"portrait");
} else {
NSLog(#"landscape");
}
}];
}

Swift 3 -Flip entire screen/view On Orientation change

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))

Weird frame calculation for UITabBar

Sometimes the app shrinks the width of the UITabBar, the 4 icons in the screenshot are usually distributed across the whole width.
Is anyone experiencing this and knows why it happens or even better how to fix/avoid it? I think it started happening with Swift, so maybe another of their awesome optimizations?
Also not sure how to reproduce it, happens around twice a week, maybe rotation, segue or app switch.
This screenshot is from an iPhone6 in portrait mode, but happens on other devices too.
I found the same behavior on iOS9 in two cases:
1) while immediate rotation during the pop-navigation in UINavigationController;
2) on rotation from landscape to portrait while watching full-screen video player and closing player after that.
To solve the problem on iOS8+ you should subclass UITabBarController and implement method from UIContentContainer protocol as follows:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
if (!self.tabBar.window) return;
[coordinator animateAlongsideTransition: ^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
CGRect newBounds = self.tabBar.bounds;
newBounds.size.width = size.width;
self.tabBar.bounds = newBounds;
[self.view.superview setNeedsLayout];
}
completion: nil];
}
If you don't write return string you won't fix the 2nd issue.
Adding same in Swift:
extension UITabBarController {
public override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
if let _ = self.tabBar.window {
coordinator.animateAlongsideTransition( { (context) in
self.tabBar.bounds.size.width = size.width
self.view.superview?.setNeedsLayout()
}, completion: nil)
}
}
}

iOS 9 Today Widget not calling viewDidLoad

The today widget is drawn correctly when it is added to the today view. But if you user comes back to it later, the viewDidLoad function is not called and it is showing stale data. Should viewDidLoad be called everytime? Is there an iOS 9 / Xcode 7 beta 6 bug?
Edit:
Added that widgetPerformUpdateWithCompletionHandler not called either. I have breakpoints set and print functions
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
print("in widgetPerformUpdateWithCompletionHandler")
fetch()
completionHandler(NCUpdateResult.NewData)
}
When you scroll a widget off and back on screen, the same controller instance will be reused for a short amount of time (appears to be ~30 seconds in my testing), and viewDidLoad and widgetPerformUpdateWithCompletionHandler: will not be called.
However, viewWillAppear and viewDidAppear will be called every time your widget is displayed.
Posting my own answer, but would like discussion on this code - should it be there or how to properly do it?. We had in this method, and by removing it the widget began to work correctly
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
if let safeCoordinator = coordinator as UIViewControllerTransitionCoordinator?
{
print("coordinator != nil")
safeCoordinator.animateAlongsideTransition({ context in
self.tableView.frame = CGRectMake(0, 0, size.width, size.height)
}, completion: nil)
}
else
{
print("coordinator == nil")
}
}

iOS viewWillTransitionToSize and device orientation

I'm using viewWillTransitionToSize to detect when a device is rotating to landscape. Depending on the target size, I can detect if heading for landscape and adjust my traits as required...
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if size.width > size.height {
self.setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: UIUserInterfaceSizeClass.Regular), forChildViewController: viewController)
}
else{
self.setOverrideTraitCollection(nil, forChildViewController: viewController)
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
However, I want to be able to detect whether my device is transitioning to landscape-left or landscape-right. This will allow me to create different behaviours or views, depending on specific orientation of device. (left or right).
Is this possible without using any deprecated functions?
I thought of using status-bar orientation...
let orientation = UIApplication.sharedApplication().statusBarOrientation;
if( orientation == UIInterfaceOrientation.LandscapeLeft )
{
// Do something
}
else if( orientation == UIInterfaceOrientation.LandscapeRight )
{
// Do something else
}
...but that doesn't help because this appears to give the 'old' status orientation.
How can I get the specific target orientation?
You can get orientation while rotating use UIViewControllerTransitionCoordinator as follows:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// will execute before rotation
coordinator.animate(alongsideTransition: { (context: UIViewControllerTransitionCoordinatorContext) in
// will execute during rotation
let orientation = UIApplication.shared.statusBarOrientation
if orientation == .landscapeLeft
{
// Do something
}
else if orientation == .landscapeRight
{
// Do something else
}
}) { (context: UIViewControllerTransitionCoordinatorContext) in
// will execute after rotation
}
}
Use [UIDevice currentDevice].orientation

Resources