iOS Code Snippet [For iOS before 16] A bit dirty way to give orientation rotation to certain pages in an essentially portrait-only app

Scenario:
  • You have an essentially portrait-only app.
  • You want to give the user the ability (i.e. option), on certain pages, to change from portrait to landscape or vice versa by rotating the phone - typically for displaying videos or webpages.
  • When the user exits the "rotatable" page you want to "snap back" to portrait.
There are any number of posts asking for/bemoaning the lack of a means to do this - the closest Erel has come to fulfilling this need is:

https://www.b4x.com/android/forum/threads/disable-autorotate-on-a-single-view.80699/#post-511594

But this doesn't give the "snap back" capability - if you are in landscape when you exit the "rotatable" page that is the orientation you will stay in.

The following is a variation on the above post which gives the "snap back" capability - with a bit of assistance from the user - the dirty bit.

In your Main module:
B4X:
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
...
...
...
Private Sub Process_Globals
...
    Public Gen_autorotate As Boolean
...
End Sub
...
...
...
Public Sub Main_ShouldAutoRotate As Boolean

    'If auto rotation allowed...
    If Gen_autorotate Then
  
        'Return True to OBJC code below, allowing auto rotation
        Return True
 
    'Otherwise, auto rotation to stop...
    Else
  
        'If still in landscape orientation...
        If GetDeviceLayoutValues.Width > GetDeviceLayoutValues.Height Then
  
            'Return True to OBJC code below, to continue allowing auto rotation
            'and wait for user to reorient to portrait
            Return True
  
        End If
  
        'If got to here must be in portrait orientation and auto rotation not
        'allowed
  
        'Return False to OBJC code below, disallowing auto rotation
        Return False
  
    End If

End Sub

#if OBJC
@end
@interface UINavigationController (B4IResize)

@end
@implementation UINavigationController (B4IResize)
- (BOOL)shouldAutorotate
{
  return [(NSNumber*)[B4IObjectWrapper raiseEvent:self :@"_shouldautorotate" :nil] boolValue];
}

#End If

In your "rotatable" page (this is an excerpt from my Webview code):
B4X:
Private Sub Event_Webview_page_Resize(Width As Int, Height As Int)

    'Clean up
    Webview_page.RootPanel.RemoveAllViews

    'Set up app background
    Webview_page.RootPanel.Color = Colors.White

    'UI_webview is defined and initialized in webviewlayout
    Webview_page.RootPanel.LoadLayout("webviewlayout")
 
    'Set up UI_webview custom view
    UI_webview.BaseView.Top = 0
    UI_webview.BaseView.Left = 0
    UI_webview.BaseView.Width = Webview_page.RootPanel.Width
    UI_webview.BaseView.Height = Webview_page.RootPanel.Height

    'Flag auto rotation allowed
    Main.Gen_autorotate = True
 
    'Load web page
    UI_webview.LoadUrl(Main.Gen_webview_url)
 
    'Set up navigation back
    UI_navigation_back.Initialize("Event_back")
    Webview_page.RootPanel.AddView(UI_navigation_back, 0, 0, Webview_page.RootPanel.Width, Webview_page.RootPanel.Height)
    UI_navigation_back.Text = "< Back "
    UI_navigation_back.TextAlignment = UI_navigation_back.ALIGNMENT_LEFT
    UI_navigation_back.Font = Font.CreateNew2(Main.App_preference_general_typeface_normal, .03 * Max(Webview_page.RootPanel.Height, Webview_page.RootPanel.Width))
    UI_navigation_back.Color = Colors.white
    UI_navigation_back.TextColor = Colors.Black
    UI_navigation_back.Visible = True
    UI_navigation_back.SizeToFit

End Sub

Private Sub Event_back_Click

    'Flag auto rotate to stop
    Main.Gen_autorotate = False

    'Clean up
    Webview_page.RootPanel.RemoveAllViews
 
    'Show status bar, see:
    'https://www.b4x.com/android/forum/threads/full-screen-apps.47866/#content
    Private wrk_no As NativeObject = Main.App
    wrk_no.RunMethod("setStatusBarHidden:animated:", Array(False, False))

    'Return to previous page
    Main.NavControl.RemoveCurrentPage2(False)
      
End Sub

Everything hangs on the global boolean Gen_autorotate:
  • When the Webview code is entered it is set to True, which allows the subsequent rotation of the phone by the user to rotate the orientation at will.
  • When the Webview code is exited it is set to False, which allows subsequent rotation of the phone by the user to rotate the orientation - UNTIL the user rotates to portrait mode, then autorotation is blocked - and portrait mode has been "snapped" back to - sort of.
This all sounds a bit stupid but in practice it actually works quite well - and is superior to the alternatives:
  • Make everything autorotatable.
  • Make nothing autorotatable.
I hope this is of value to someone...
 
Last edited:

gregchao

Active Member
Licensed User
Longtime User
Scenario:
  • You have an essentially portrait-only app.
  • You want to give the user the ability (i.e. option), on certain pages, to change from portrait to landscape or vice versa by rotating the phone - typically for displaying videos or webpages.
  • When the user exits the "rotatable" page you want to "snap back" to portrait.
There are any number of posts asking for/bemoaning the lack of a means to do this - the closest Erel has come to fulfilling this need is:

https://www.b4x.com/android/forum/threads/disable-autorotate-on-a-single-view.80699/#post-511594

But this doesn't give the "snap back" capability - if you are in landscape when you exit the "rotatable" page that is the orientation you will stay in.

The following is a variation on the above post which gives the "snap back" capability - with a bit of assistance from the user - the dirty bit.

In your Main module:
B4X:
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
...
...
...
Private Sub Process_Globals
...
    Public Gen_autorotate As Boolean
...
End Sub
...
...
...
Public Sub Main_ShouldAutoRotate As Boolean

    'If auto rotation allowed...
    If Gen_autorotate Then

        'Return True to OBJC code below, allowing auto rotation
        Return True

    'Otherwise, auto rotation to stop...
    Else

        'If still in landscape orientation...
        If GetDeviceLayoutValues.Width > GetDeviceLayoutValues.Height Then

            'Return True to OBJC code below, to continue allowing auto rotation
            'and wait for user to reorient to portrait
            Return True

        End If

        'If got to here must be in portrait orientation and auto rotation not
        'allowed

        'Return False to OBJC code below, disallowing auto rotation
        Return False

    End If

End Sub

#if OBJC
@end
@interface UINavigationController (B4IResize)

@end
@implementation UINavigationController (B4IResize)
- (BOOL)shouldAutorotate
{
  return [(NSNumber*)[B4IObjectWrapper raiseEvent:self :@"_shouldautorotate" :nil] boolValue];
}

#End If

In your "rotatable" page (this is an excerpt from my Webview code):
B4X:
Private Sub Event_Webview_page_Resize(Width As Int, Height As Int)

    'Clean up
    Webview_page.RootPanel.RemoveAllViews

    'Set up app background
    Webview_page.RootPanel.Color = Colors.White

    'UI_webview is defined and initialized in webviewlayout
    Webview_page.RootPanel.LoadLayout("webviewlayout")

    'Set up UI_webview custom view
    UI_webview.BaseView.Top = 0
    UI_webview.BaseView.Left = 0
    UI_webview.BaseView.Width = Webview_page.RootPanel.Width
    UI_webview.BaseView.Height = Webview_page.RootPanel.Height

    'Flag auto rotation allowed
    Main.Gen_autorotate = True

    'Load web page
    UI_webview.LoadUrl(Main.Gen_webview_url)

    'Set up navigation back
    UI_navigation_back.Initialize("Event_back")
    Webview_page.RootPanel.AddView(UI_navigation_back, 0, 0, Webview_page.RootPanel.Width, Webview_page.RootPanel.Height)
    UI_navigation_back.Text = "< Back "
    UI_navigation_back.TextAlignment = UI_navigation_back.ALIGNMENT_LEFT
    UI_navigation_back.Font = Font.CreateNew2(Main.App_preference_general_typeface_normal, .03 * Max(Webview_page.RootPanel.Height, Webview_page.RootPanel.Width))
    UI_navigation_back.Color = Colors.white
    UI_navigation_back.TextColor = Colors.Black
    UI_navigation_back.Visible = True
    UI_navigation_back.SizeToFit

End Sub

Private Sub Event_back_Click

    'Flag auto rotate to stop
    Main.Gen_autorotate = False

    'Clean up
    Webview_page.RootPanel.RemoveAllViews

    'Show status bar, see:
    'https://www.b4x.com/android/forum/threads/full-screen-apps.47866/#content
    Private wrk_no As NativeObject = Main.App
    wrk_no.RunMethod("setStatusBarHidden:animated:", Array(False, False))

    'Return to previous page
    Main.NavControl.RemoveCurrentPage2(False)
    
End Sub

Everything hangs on the global boolean Gen_autorotate:
  • When the Webview code is entered it is set to True, which allows the subsequent rotation of the phone by the user to rotate the orientation at will.
  • When the Webview code is exited it is set to False, which allows subsequent rotation of the phone by the user to rotate the orientation - UNTIL the user rotates to portrait mode, then autorotation is blocked - and portrait mode has been "snapped" back to - sort of.
This all sounds a bit stupid but in practice it actually works quite well - and is superior to the alternatives:
  • Make everything autorotatable.
  • Make nothing autorotatable.
I hope this is of value to someone...
Scenario:
  • You have an essentially portrait-only app.
  • You want to give the user the ability (i.e. option), on certain pages, to change from portrait to landscape or vice versa by rotating the phone - typically for displaying videos or webpages.
  • When the user exits the "rotatable" page you want to "snap back" to portrait.
There are any number of posts asking for/bemoaning the lack of a means to do this - the closest Erel has come to fulfilling this need is:

https://www.b4x.com/android/forum/threads/disable-autorotate-on-a-single-view.80699/#post-511594

But this doesn't give the "snap back" capability - if you are in landscape when you exit the "rotatable" page that is the orientation you will stay in.

The following is a variation on the above post which gives the "snap back" capability - with a bit of assistance from the user - the dirty bit.

In your Main module:
B4X:
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
...
...
...
Private Sub Process_Globals
...
    Public Gen_autorotate As Boolean
...
End Sub
...
...
...
Public Sub Main_ShouldAutoRotate As Boolean

    'If auto rotation allowed...
    If Gen_autorotate Then
 
        'Return True to OBJC code below, allowing auto rotation
        Return True

    'Otherwise, auto rotation to stop...
    Else
 
        'If still in landscape orientation...
        If GetDeviceLayoutValues.Width > GetDeviceLayoutValues.Height Then
 
            'Return True to OBJC code below, to continue allowing auto rotation
            'and wait for user to reorient to portrait
            Return True
 
        End If
 
        'If got to here must be in portrait orientation and auto rotation not
        'allowed
 
        'Return False to OBJC code below, disallowing auto rotation
        Return False
 
    End If

End Sub

#if OBJC
@end
@interface UINavigationController (B4IResize)

@end
@implementation UINavigationController (B4IResize)
- (BOOL)shouldAutorotate
{
  return [(NSNumber*)[B4IObjectWrapper raiseEvent:self :@"_shouldautorotate" :nil] boolValue];
}

#End If

In your "rotatable" page (this is an excerpt from my Webview code):
B4X:
Private Sub Event_Webview_page_Resize(Width As Int, Height As Int)

    'Clean up
    Webview_page.RootPanel.RemoveAllViews

    'Set up app background
    Webview_page.RootPanel.Color = Colors.White

    'UI_webview is defined and initialized in webviewlayout
    Webview_page.RootPanel.LoadLayout("webviewlayout")

    'Set up UI_webview custom view
    UI_webview.BaseView.Top = 0
    UI_webview.BaseView.Left = 0
    UI_webview.BaseView.Width = Webview_page.RootPanel.Width
    UI_webview.BaseView.Height = Webview_page.RootPanel.Height

    'Flag auto rotation allowed
    Main.Gen_autorotate = True

    'Load web page
    UI_webview.LoadUrl(Main.Gen_webview_url)

    'Set up navigation back
    UI_navigation_back.Initialize("Event_back")
    Webview_page.RootPanel.AddView(UI_navigation_back, 0, 0, Webview_page.RootPanel.Width, Webview_page.RootPanel.Height)
    UI_navigation_back.Text = "< Back "
    UI_navigation_back.TextAlignment = UI_navigation_back.ALIGNMENT_LEFT
    UI_navigation_back.Font = Font.CreateNew2(Main.App_preference_general_typeface_normal, .03 * Max(Webview_page.RootPanel.Height, Webview_page.RootPanel.Width))
    UI_navigation_back.Color = Colors.white
    UI_navigation_back.TextColor = Colors.Black
    UI_navigation_back.Visible = True
    UI_navigation_back.SizeToFit

End Sub

Private Sub Event_back_Click

    'Flag auto rotate to stop
    Main.Gen_autorotate = False

    'Clean up
    Webview_page.RootPanel.RemoveAllViews

    'Show status bar, see:
    'https://www.b4x.com/android/forum/threads/full-screen-apps.47866/#content
    Private wrk_no As NativeObject = Main.App
    wrk_no.RunMethod("setStatusBarHidden:animated:", Array(False, False))

    'Return to previous page
    Main.NavControl.RemoveCurrentPage2(False)
     
End Sub

Everything hangs on the global boolean Gen_autorotate:
  • When the Webview code is entered it is set to True, which allows the subsequent rotation of the phone by the user to rotate the orientation at will.
  • When the Webview code is exited it is set to False, which allows subsequent rotation of the phone by the user to rotate the orientation - UNTIL the user rotates to portrait mode, then autorotation is blocked - and portrait mode has been "snapped" back to - sort of.
This all sounds a bit stupid but in practice it actually works quite well - and is superior to the alternatives:
  • Make everything autorotatable.
  • Make nothing autorotatable.
I hope this is of value to someone...
I got this to work on my project. Just what I needed.
 
Top