B4A Library SoftOrientation Library for Activitiy and B4XPages based projects

After a lot of searching and unsuccessful attempts to find a method or library that will allow changing the screen orientation without killing the activity, I decided to make the library myself. As is known, in the Android operating system, after changing the orientation of the screen, the activity is killed and all views are redrawn. This can have a very negative impact on certain views that cannot save their current instance (eg WebView, ListView, etc.). The content of these objects must be rewritten and repopulated (refreshed). In some cases this may not be a problem, but in a certain number of cases it is a big problem (e.g. a filled form in a WebView will be deleted, a filled ListView with several hundred rows will return the scroll position to the beginning and lose the complete content that must be filled again, CheckBox will reset its status, also RadioButton etc.)

Also, one of the best features of B4X, B4XPages, is limited to the fact that each B4X page must use the same screen orientation (landscape or portrait) because when the screen orientation is changed, the activity and all its views (like the B4X page Panels) are reset and the whole application restarts.

Using the SoftOrientation library provides the following possibilities:
  • Prevents killing the activity and redrawing all views with their initial instances.
  • Instances of all views remain as they were before the orientation change.
  • Activity_Create and Activity_Resume subs are not called after orientation change
  • Allows defining the screen orientation for each B4X page in the B4XPages project

The working principle of the library is based on the fact that when the screen orientation is changed, the library changes the size of the activity to the size of the free space for displaying the activity in the current orientation. Also, in parallel with changing the size of the activity, an invisible Panel is created whose size is the same as the new size of the activity. After that, the Layout is loaded into the invisible panel in relation to the current orientation. Then each view in the activity is resized to the size of the same view in the invisible Panel. After that the invisible Panel is killed and the activity is adjusted for the current screen orientation. The principle is the same in B4XPages, with the fact that in addition to changing the size of the Activity, the size of the Root panel also changes.

So the library can be used in projects that are based on Activities, and also in projects that are based on B4X pages.

It is necessary to add the following line to the Manifest. For an activity-based project, you need to add a line to the Manifest for each Activity that will use Soft Orientation.
Manifest:
SetActivityAttribute(Main, android:configChanges, "orientation|keyboardHidden|screenSize|screenLayout")

Below are examples of how to use the library:
Activity based project:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
 
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    Private SoftOrientationMain As SoftOrientationForActivities
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
    SoftOrientationMain.Initialize(Me,"SoftOrientationMain",Activity,"Layout")
    SoftOrientationMain.Orientation=SoftOrientationMain.SCREEN_ORIENTATION_SENSOR
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

'This event will be activated when the orientation change procedure is completed.
Private Sub SoftOrientationMain_ActivityConfigurationChanged (NewConfiguration As AndroidContentResConfiguration)
    If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_PORTRAIT Then
        Log("portrait")
    Else if NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_LANDSCAPE Then
        Log("landscape")
    End If
End Sub

'Do not forget to add line in Manifest for your future projects: SetActivityAttribute(Main, android:configChanges, "orientation|keyboardHidden|screenSize|screenLayout")
'Do not forget to create single Layout file for portrait and landscape mode in Designer in your future projects. Recommended to use variants, designer script and anchors.
'********************Copy this part of codes to your future project Main activity, including Java code*********************************
Public Sub onConfigurationChanged (NewConfig As Object)
    SoftOrientationMain.OnConfigurationChanged(NewConfig)
End Sub

#If Java

import android.content.res.Configuration;

@Override
public void onConfigurationChanged (Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    processBA.raiseEvent(null, "onconfigurationchanged", newConfig);
}
#End If
'************************************End of code*********************************************************************************************

B4XPages MainActivity:
Sub Process_Globals
 
End Sub

Sub Globals
 
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Dim pm As B4XPagesManager
    pm.Initialize(Activity)
End Sub

'Template version: B4A-1.0

#Region Delegates

Sub Activity_ActionBarHomeClick
    B4XPages.Delegate.Activity_ActionBarHomeClick
End Sub

Sub Activity_KeyPress (KeyCode As Int) As Boolean
    Return B4XPages.Delegate.Activity_KeyPress(KeyCode)
End Sub

Sub Activity_Resume
    B4XPages.Delegate.Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    B4XPages.Delegate.Activity_Pause
End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
    B4XPages.Delegate.Activity_PermissionResult(Permission, Result)
End Sub

Sub Create_Menu (Menu As Object)
    B4XPages.Delegate.Create_Menu(Menu)
End Sub

'Do not forget to add line in Manifest for your future projects: SetActivityAttribute(Main, android:configChanges, "orientation|keyboardHidden|screenSize|screenLayout")
'Do not forget to create single Layout file for portrait and landscape mode in Designer for each B4XPage in your future projects. Recommended to use variants, designer script and anchors.
'********************Copy this part of codes to your B4XPages future project Main activity, including Java code*********************************
Public Sub onConfigurationChanged (NewConfig As Object)
    'SoftOrientationMain is variable name for SoftOrientationForB4XPages in B4XMainPage. Change it depending on your variable name in your future projects.
    If B4XPages.MainPage.SoftOrientationMain.IsInitialized Then
        B4XPages.MainPage.SoftOrientationMain.OnConfigurationChanged(NewConfig,B4XPages.GetManager.GetTopPage.Id)
        'Or
        'B4XPages.MainPage.SoftOrientationMain.OnConfigurationChanged(NewConfig,B4XPages.MainPage.SoftOrientationMain.CurrentlyActiveB4XPage.PageID)
        'Or
        'B4XPages.MainPage.SoftOrientationMain.OnConfigurationChanged2(NewConfig,B4XPages.MainPage.SoftOrientationMain.CurrentlyActiveB4XPage)
    End If
End Sub

#If Java

import android.content.res.Configuration;

@Override
public void onConfigurationChanged (Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    processBA.raiseEvent(null, "onconfigurationchanged", newConfig);
}
#End If
'************************************End of code*********************************************************************************************

B4XPages B4XMainPage:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Public txtUser As B4XFloatTextField
    Private btnLogin As B4XView
    Public Page2 As B4XPage2
    Public Page3 As B4XPage3
    Public SoftOrientationMain As SoftOrientationForB4XPages
    Public SoftOrientationMainPage As SoftOrientationB4XPage
End Sub

'You can add more parameters here.
Public Sub Initialize

End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Login")
    Page2.Initialize
    B4XPages.AddPage("Page 2", Page2)
    Page3.Initialize
    B4XPages.AddPage("Page 3", Page3)
 
    SoftOrientationMain.Initialize(B4XPages.GetNativeParent(Me))
    SoftOrientationMainPage.Initialize(Me,"SoftOrientationMainPage",B4XPages.GetPageId(Me),"Login",SoftOrientationMain.SCREEN_ORIENTATION_SENSOR,Root)
    SoftOrientationMain.AddB4XPage2(SoftOrientationMainPage)
End Sub

Sub B4XPage_Appear
    txtUser.Text = ""
 
    SoftOrientationMain.ApplyB4XPageDefaultOrientation(B4XPages.GetPageId(Me))
    'Or
    'SoftOrientationMain.ApplyB4XPageDefaultOrientation2(SoftOrientationMainPage)
End Sub

'This event will be activated when the orientation change procedure is completed.
Sub SoftOrientationMainPage_ActivityConfigurationChanged (NewConfiguration As AndroidContentResConfiguration)
    If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_PORTRAIT Then
        Log("SoftOrientationMainPage orientation PORTRAIT")
    Else If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_LANDSCAPE Then
        Log("SoftOrientationMainPage orientation LANDSCAPE")
    End If
End Sub

Sub btnLogin_Click
    B4XPages.ShowPageAndRemovePreviousPages("Page 2")
End Sub

Sub txtUser_TextChanged (Old As String, New As String)
    btnLogin.Enabled = New.Length > 0
End Sub

Sub txtUser_EnterPressed
    If btnLogin.Enabled Then btnLogin_Click
End Sub

B4XPages Page2:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private lblHello As B4XView
    Private ImageView1 As B4XView
    Private Page3 As B4XPage3
    Public SoftOrientationPage2 As SoftOrientationB4XPage
End Sub

'You can add more parameters here.
Public Sub Initialize

End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Page2")
    Page3 = B4XPages.GetPage("Page 3")
 
    SoftOrientationPage2.Initialize(Me,"SoftOrientationPage2",B4XPages.GetPageId(Me),"Page2",B4XPages.MainPage.SoftOrientationMain.SCREEN_ORIENTATION_PORTRAIT,Root)
    B4XPages.MainPage.SoftOrientationMain.AddB4XPage2(SoftOrientationPage2)
End Sub

Private Sub B4XPage_Appear
    lblHello.Text = $"Hello ${B4XPages.MainPage.txtUser.Text}!"$
    UpdateImage
 
    B4XPages.MainPage.SoftOrientationMain.ApplyB4XPageDefaultOrientation(B4XPages.GetPageId(Me))
    'Or
    'B4XPages.MainPage.SoftOrientationMain.ApplyB4XPageDefaultOrientation2(SoftOrientationPage2)
End Sub

'This event will be activated when the orientation change procedure is completed.
Sub SoftOrientationPage2_ActivityConfigurationChanged (NewConfiguration As AndroidContentResConfiguration)
    If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_PORTRAIT Then
        Log("SoftOrientationPage2 orientation PORTRAIT")
    Else If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_LANDSCAPE Then
        Log("SoftOrientationPage2 orientation LANDSCAPE")
    End If
End Sub

Sub btnDraw_Click
    B4XPages.ShowPage("Page 3")
End Sub

Sub UpdateImage
    If Page3.Panel1.IsInitialized Then
        ImageView1.SetBitmap(Page3.cvs.CreateBitmap)
    End If
End Sub

Sub btnSignOut_Click
    Page3.ClearImage
    UpdateImage
    B4XPages.ShowPageAndRemovePreviousPages("MainPage")
End Sub

B4XPages Page3:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Public cvs As B4XCanvas
    Public Panel1 As B4XView
    Public SoftOrientationPage3 As SoftOrientationB4XPage
End Sub

'You can add more parameters here.
Public Sub Initialize

End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Page3")
    cvs.Initialize(Panel1)
    B4XPages.SetTitle(Me, "Draw Something")
    #if B4A
    B4XPages.AddMenuItem(Me, "Random Background")
    #End If
 
    SoftOrientationPage3.Initialize(Me,"SoftOrientationPage3",B4XPages.GetPageId(Me),"Page3",B4XPages.MainPage.SoftOrientationMain.SCREEN_ORIENTATION_SENSOR,Root)
    B4XPages.MainPage.SoftOrientationMain.AddB4XPage2(SoftOrientationPage3)
End Sub


Sub B4XPage_Appear
    B4XPages.MainPage.SoftOrientationMain.ApplyB4XPageDefaultOrientation(B4XPages.GetPageId(Me))
    'Or
    'B4XPages.MainPage.SoftOrientationMain.ApplyB4XPageDefaultOrientation2(SoftOrientationPage3)
End Sub

'This event will be activated when the orientation change procedure is completed.
Sub SoftOrientationPage3_ActivityConfigurationChanged (NewConfiguration As AndroidContentResConfiguration)
    cvs.Resize(Root.Width,Root.Height)
    If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_PORTRAIT Then
        Log("SoftOrientationPage3 orientation PORTRAIT")
    Else If NewConfiguration.Orientation=NewConfiguration.Constants.ORIENTATION_LANDSCAPE Then
        Log("SoftOrientationPage3 orientation LANDSCAPE")
    End If
End Sub

Sub Panel1_Touch (Action As Int, X As Float, Y As Float)
    If Action <> Panel1.TOUCH_ACTION_MOVE_NOTOUCH Then
        cvs.DrawCircle(X, Y, 10dip, Rnd(xui.Color_Black, xui.Color_White), True, 0)
        cvs.Invalidate
    End If
End Sub

Private Sub btnClear_Click
    ClearImage
End Sub

Public Sub ClearImage
    If Panel1.IsInitialized Then
        cvs.ClearRect(cvs.TargetRect)
        cvs.Invalidate
    End If
End Sub

Sub btnSet_Click
    B4XPages.ClosePage(Me)
End Sub

Sub B4XPage_Resize (Width As Int, Height As Int)
    ClearImage
    cvs.Resize(Width, Height)
End Sub

Sub B4XPage_MenuClick (Tag As String)
    If Tag = "Random Background" Then
        cvs.DrawRect(cvs.TargetRect, Rnd(xui.Color_Black, xui.Color_White), True, 0)
        cvs.Invalidate
    End If
End Sub

#if B4J
'Delegate the native menu action to B4XPage_MenuClick.
Sub MenuBar1_Action
    Dim mi As MenuItem = Sender
    Dim t As String
    If mi.Tag = Null Then t = mi.Text.Replace("_", "") Else t = mi.Tag
    B4XPage_MenuClick(t)
End Sub
#End If

For the B4XPages example, the ThreePagesExample from @Erel was used.

As @Erel has mentioned several times, and it is also Google's recommendation that the onConfigurationChanged principle should not be used if it is not necessary. So, if the use of this library is not necessary for your project, do not use it. Use the library if you really need it.

The library and the htm file with methods and properties are packed in the zip file SoftOrientation_Lib.zip. There are also two example projects, one for an Activity-based project, the other for B4XPages.

The following libraries are necessary for the library to work:

If this library makes your work easier and saves time in creating your application, please make a donation.
 

Attachments

  • SoftOrientationActivityExample.zip
    10.2 KB · Views: 222
  • SoftOrientationB4XPagesExample.zip
    15.6 KB · Views: 217
  • SoftOrientation_1.2_Lib.zip
    18.1 KB · Views: 200
Last edited:

smederevodi

New Member
What is activity launch mode in android?
This is the default launch mode of activity (If not specified). It launches a new instance of an activity in the task from which it was launched. Numerous instances of the activity can be generated, and multiple instances of the activity can be assigned to the same or separate tasks.
 

Ivica Golubovic

Active Member
Licensed User
What is activity launch mode in android?
This is the default launch mode of activity (If not specified). It launches a new instance of an activity in the task from which it was launched. Numerous instances of the activity can be generated, and multiple instances of the activity can be assigned to the same or separate tasks.
I dont understand what you mean.
 

Ivica Golubovic

Active Member
Licensed User

alcaraz73

Member
Thanks, invalidate works.

Now, I tested using a Panel, with label and button inside.

The location is not as expected, Do you recommend using script variants?


Regards
 

Attachments

  • SoftOrientationB4XPagesExamplewithPanel.zip
    11.3 KB · Views: 132

Ivica Golubovic

Active Member
Licensed User
Thanks, invalidate works.

Now, I tested using a Panel, with label and button inside.

The location is not as expected, Do you recommend using script variants?


Regards
You have to make a little effort on your own to come up with an acceptable solution to the problem that arises. This library, like all others, does not solve all problems.

All views added via the designer should be automatically placed in the position defined by variants, designer scripts and anchors. However, certain custom views may behave strangely because the automatic positioning of child views in case of changing the size or position of the parent is not done (It is not done in the custom view library itself). In that case, setting the custom view layout must be done manually via the ActivityConfigurationChanged event.

All views that have been added programmatically, their layout must also be adjusted programmatically in case of orientation change. This is where the ActivityConfigurationChanged event is used again.

This library is just a starting point that allows you to change the orientation without deleting and redraw all the views.
 

Ivica Golubovic

Active Member
Licensed User
SoftOrientation version 1.2 realised. Download library from first post

Changes:
  1. Added property RotationInDegrees as Int in SoftOrientationForActivities and SoftOrientationForB4XPages
  2. From version 1.2 library XUI is not necessary for library functionality.
  3. Fixed wrong Activity size bug when Activity full screen is active.
  4. Improved view resizing process in case of orientation change.
  5. Fixed bug when B4XPage or Activity view hierarchy change.
IMPORTANT:
Do not add any views before initializing the SoftOrientationForActivity, or in the case of B4XPages projects, before initializing the SoftOrientationB4XPage for the selected page to avoid accidentally misreading the view hierarchy. Examples:
Activity project:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
    SoftOrientationMain.Initialize(Me,"SoftOrientationMain",Activity,"Layout")
    
    'Here you can continue to adding views programatically or fill custom views with content
End Sub
B4XPages MainPage:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Layout")
    SoftOrientationMain.Initialize(B4XPages.GetNativeParent(Me))
    SoftOrientationMainPage.Initialize(Me,"SoftOrientationMainPage","mainpage","Layout",SoftOrientationMain.SCREEN_ORIENTATION_SENSOR,Root.As(Panel))
    SoftOrientationMain.AddB4XPage2(SoftOrientationMainPage)

    'Here you can continue to adding views programatically or fill custom views with content
End Sub
B4XPage2:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Page2")
    SoftOrientationPage2.Initialize(Me,"SoftOrientationPage2",B4XPages.GetPageId(Me),"Page2",B4XPages.MainPage.SoftOrientationMain.SCREEN_ORIENTATION_SENSOR,Root)
    B4XPages.MainPage.SoftOrientationMain.AddB4XPage2(SoftOrientationPage2)
    
    'Here you can continue to adding views programatically or fill custom views with content
End Sub
 
Top