Custom UIViewController not receiving orientation change notifications on device rotation - ios

So, I have a custom UIWindow, a custom UIViewController, and a custom UIImageView.
private class CoachingWindow : UIWindow
{
public CoachingWindow(...)
{
RootViewController = new CoachingOverlayViewController(...);
}
private class CoachingOverlayViewController : UIViewController
{
public CoachingOverlayViewController(...)
{
View = new CoachingOverlayView(...);
}
public override void DidRotate (UIInterfaceOrientation fromInterfaceOrientation)
{
...
}
public override bool ShouldAutorotate()
{
return true;
}
private class CoachingOverlayView : UIImageView
{
public CoachingOverlayView(...)
{
...
}
}
}
}
The window, view controller, and view all display properly when first called: the custom UIWindow appears as an overlay over the rest of the existing UIWindows, the view controller is properly assigned as the RootViewController, the view is assigned to the View property of the view controller. So, it all renders correctly.
However, the overridden DidRotate() and ShouldAutorotate() methods never get get called when I physically rotate the device or simulator.
I'm thinking it may have something do with the fact that I'm using a custom UIWindow. Perhaps the window isn;t receiving notifications of orientation change from iOS? Or does iOS send these notifications directly to view controllers? Maybe I have to somehow make the view controller subscribe to these events because it's a custom view controller???
I'm using MonoTouch and iOS 6.
Any suggestions would be great. I'm beating my head against the wall here.

in iOS 6 you can use
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{ ... }

Figured it out. I had override ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) instead of ShouldAutorotate(). But this is actually deprecated in iOS6. Still have to figure out how to do it the iOS6 way, but this will do for now.
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
...
}

Related

programmatically change orientation from Landscape to Portrait Mode xamarin IOS

I am developing an app with Xamarin MVVMCross technology and would like to ask a question about InterfaceOrientation option: all view controllers of application support all orientations but one should use only Portrait mode.
When I go to that ViewController from others in Portrait mode, I am able to keep my portrait viewcontroller in Portrait mode due to method in my AppDelegate.cs :
[Export("application:supportedInterfaceOrientationsForWindow:")]
public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, IntPtr forWindow)
{
if (this.RestrictRotation)
return UIInterfaceOrientationMask.All;
else
return UIInterfaceOrientationMask.Portrait;
}
But when I go to my portraitview controller when device in LandscapeLeft(LandscapeRight) orientations, GetSupportedInterfaceOrientations from AppDelegate.cs method is not called and that view controller is opened in Landscape mode.
Is there a way to programmatically change orientation from Landscape to Portrait Mode just for one view controller in Xamarin IOS?
Thank you
In your helper class;
public static void LockOrientation(UIInterfaceOrientationMask uIInterfaceOrientationMask, UIInterfaceOrientation uIInterfaceOrientation)
{
if (UIApplication.SharedApplication.Delegate != null)
{
CommonUtils.LockOrientation(uIInterfaceOrientationMask);
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)uIInterfaceOrientation), new NSString("orientation"));
}
}
In AppDelegate.cs
//Set the orientation for rest of the app
public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All;
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
{
return OrientationLock;
}
Now simply call the LockOrientation method wherever you would like to lock/change orientation.
Example:
CommonUtils.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait);
If you want to control the orientation of a single ViewController don't use the AppDelegate GetSupportedInterfaceOrientations method instead use the one in the ViewController you want to control.
These lines will prevent the ViewController you implement this method to get any other orientation but Portrait.
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations ()
{
return UIInterfaceOrientationMask.Portrait;
}
Note: You will need to repeat the same for every ViewController in case you want to force the orientation to more than one.
i hope that work..
put in your controller class
public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
{
base.DidRotate(fromInterfaceOrientation);
UIAlertView alert = new UIAlertView();
alert.Title = UIDevice.CurrentDevice.Orientation + "";
alert.AddButton("ok");
alert.Show();
}

Restricting portrait orientation to collectionview in iOS doesn't seem to work

I have multiple viewControllers in my app and I would like to restrict certain views only to portrait orientation. I have achieved this by overriding shouldAutoRotate and supportedInterfaceOrientations like below
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientation.Portrait.rawValue)
}
I have followed the same for a UICollectionView but it doesn't seem to work. I would like to know if this is the right way to achieve it. Help on this would be much appreciated. Thanks in advance!
In iOS 8 or later, if you want to control the allowed orientations per view controller:
Make sure the "Supported interface orientations" in the Info.plist allows all orientations you want the app to be able to use. (Or just check the correct "Device Orientations" in the Xcode UI interface to the Info.plistfile)
Per view controller, implement (example restricting to portrait):
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
A problem you can run in to is if your view controller is embedded in another view controller (like an UINavigationController or a UITabBarController, or both).
I suspect this is the situation you are describing.
If so, all view controllers involved need to implement the supportedInterfaceOrientations() method. AFAIK, if you for example have a UINavigationController above your view controller, you need to sub class and create your own navigation controller with the method implemented.

How to disable and enable auto rotate on swift?

On general settings I allow portrait and landscapeleft , landscaperight modes. I want to turn off landscape modes. On viewController I write this code:
override func shouldAutorotate() -> Bool {
return false
}
However, the auto rotation works ignoring this function. How do I disable and enable autorotation on swift? IOS programming
It might be the right code, but not in the right View Controller. For example, if the View Controller is embedded in a UINavigationController, the navigation controller can still rotate, causing the View Controller to still rotate. It really depends on your specific situation.
I had the same problem, i have fixed that.
Follow-
info --> custom ios target properties --> Support Interface Orinetations. and delete ![Delete - Landscape (left home button), Landscape (right home button), Landscape (top home button)][1]
This will help you 😊
You can do it by creating a subclass of UINavigationController and inside that, override the should AutoRotate function,then
return false for the viewControllers in which you want to disable autorotation
return true for the viewControllers in which you want autorotation
import UIKit
class CustomNavigationController: UINavigationController {
override func shouldAutorotate() -> Bool {
if !viewControllers.isEmpty {
// Check if this ViewController is the one you want to disable roration on
if topViewController!.isKindOfClass(ViewController) { //ViewController is the name of the topmost viewcontroller
// If true return false to disable it
return false
}
}
// Else normal rotation enabled
return true
}
}
If you want to disable autorotation throughout the navigation controller, remove the if condition and return false always
Extending Josh Gafni's answer and user3655266, the concept also extends to view controllers.
If we have a UIViewController that is a child of another UIViewController in the view hierarchy, overriding the child's shouldAutorotate() to false might still rotate since it parent's controller might still be returning true. It is also important to know that even though the child VC is being displayed, the parent's shouldAutoRotate function are still called. Hence the control should lie there.
Swift 5
class ParentViewController:UIViewController{
override func shouldAutorotate() -> Bool {
// Return an array of ViewControllers that are children of the parent
let childViewControllersArray = self.children
if childViewControllersArray.count > 0 {
// Assume childVC is the ViewController you are interested in NOT allowing to rotate
let childVC = childViewControllersArray.first
if childVC is ChildViewController {
return false
}
}
return true
}
}
** The same can also be done to only allow certain phone orientation **
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
// This function is called on the parent's controller whenever the child of this parent is trying to rotate
let childrenVCArray = self.children
if childrenVCArray.count > 0 {
// assuming the array of the first element is the current childVC
let topMostVC = childrenVCArray[0]
if topMostVC is ChildViewController {
// Assuming only allowing landscape mode
return .landscape
}
}
// Return portrait otherwise
return .portrait
}
I am not sure if shouldAutorotate() function is still enabled in swift 5 for year 2021. However I recommend calling one of the following functions as part of standard procedure for managing rotation of ViewControllers. ("Handling View Rotations" part in apple developer webside For example preferredInterfaceOrientationForPresentation

Best practice for programmatically showing UIView in correct orientation

I am building an monoTouch-iPad application and I am stumbling around because of the start-interface-orientation.
One problem is, when the app starts UIDevice.CurrentDevice.Orientation always returns Unknown. How can you decide in which orientation your app starts? All properties that I found by now just return portrait-mode, unknown or the frame-size of portrait mode - even if it's landscape mode.
I also created two UIViews (one for landscape, one for portrait) and changing them by now in the WillRotate method of the UIViewController. But my code:
if(toInterfaceOrientation==UIInterfaceOrientation.LandscapeLeft || toInterfaceOrientation==UIInterfaceOrientation.LandscapeRight){
_scrollView.RemoveFromSuperview();
this.View.Add (_scrollViewLandscape);
}else{
_scrollViewLandscape.RemoveFromSuperview();
this.View.Add (_scrollView);
}
produces a short and ugly "flickering" when rotating the screen - at least in the simulator.
Is there a best practice for laying out your Views? And I know about ShouldAutorotateToInterfaceOrientationbut this doesn't work for me, as I am doing much owner drawn stuff, which gets broken when autoresized (see my other question).
I would really appreciate a solution without using the Interface-Builder, as I am doing everything in code by now.
UPDATE: Short-Descripton what I want to achieve:
AppStart -> knowing the correct Framsize (1024,748 or 768,1004) -> Adding my custom view in correct framesize
UPDATE2: simple and basic code-snippet
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
Console.WriteLine (this.InterfaceOrientation);
}
returns portrait. Even if the simulator is in landscape-mode.
inside your UIViewController can just check the InterfaceOrientation
public override void ViewDidLoad ()
{
if (this.InterfaceOrientation == UIInterfaceOrientation.Portrait
|| this.InterfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown)
{
// portrait
}
else
{
// landsacpe
}
}
but i would really recommend using View.AutoresizingMask or overriding LayoutSubviews, both makes the all the transitions really smooth
UPDATE: using AutoresizingMask
public override void ViewDidLoad ()
{
UIView view = new CustomView(View.Bounds);
view.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth;
View.AddSubview(view);
}
UPDATE: overriding LayoutSubviews
LayoutSubviews is called everytime the Size changes
public class CustomView : UIView
{
public override void LayoutSubviews ()
{
//layout your view with your own logic using the new values of Bounds.Width and Bounds.Height
}
}

BeginAnimations and CommitAnimations with NavigationController.PushViewController

I'm trying to get a basic flip animation transition working when I push a controller inside a navigation. The code below flips the view, however the view appears first (each element fades in), and then the flip occurs. Is it possible to do a flip animation with a UINavigationController?
Any pointers would be great, the examples I've found for Monotouch are performing animations on Views inside another view.
void ToolbarButtonClick()
{
InformationController controller = new InformationController();
NavigationController.PushViewController(controller,true);
}
public class InformationController : UIViewController
{
public override void ViewDidLoad ()
{
UIView.BeginAnimations("Flip");
UIView.SetAnimationDuration(1.0);
UIView.SetAnimationTransition(UIViewAnimationTransition.FlipFromRight,View,true);
base.ViewDidLoad ();
Title = "Information";
}
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
UIView.CommitAnimations();
}
}
I was sort of there, but the View needs to be taken from the NavigationController:
// Push the controller first or the Title doesn't animate
NavigationController.PushViewController(controller,false);
UIView.BeginAnimations(null,IntPtr.Zero);
UIView.SetAnimationDuration(1);
UIView.SetAnimationTransition(UIViewAnimationTransition.FlipFromLeft,
NavigationController.View,true);
UIView.CommitAnimations();
I'm not an expert, but I'm wondering about that TRUE on the PushViewcontroller which indicates that it is going to be animated. It has me wondering if that is making the NavigationController do the initial amount of animation work, which is then followed by yours. When you set it to false, what happens? I know we tend to automatically put the TRUE in there without thinking.

Resources