Android Question AutoScale on views created by code?

Jerryk

Active Member
Licensed User
Longtime User
How to scale views created by code in B4XPages?
I found Klaus's Scale module (from 2012) which works on old Activity. On B4XPages it ends with an error in this module.

B4X:
    Scale.SetReferenceLayout(480, 800, 1.5)
    Scale.ScaleAll(Root, True) - error

Error occurred on line: 641 (Scale)
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference


I am attaching a small project.

Screenshot_2025.07.28_10.03.04.854.png
 

Attachments

  • ScaleLayout.zip
    15.2 KB · Views: 39
Solution
The Scale module is a quite old module and many things have changed since its publication and especially B4XPages.
I added a warning on top of the thread to not use it anymore.

In your example, you are not using the scaling correctly.
You mix layouts from the Designer with layout in code.
In the MainPage layout you have AutoScaleAll.
In the lbl1 layout, no AutoScale.
Then you use this for the scaling:
B4X:
    Scale.SetReferenceLayout(480, 800, 1.5)
    Scale.ScaleAll(Root, True)
The problem is that the MainPage layout has already been scaled in the Designer and you scale it again.
I replaced above two lines by these:
B4X:
    Scale.SetReferenceLayout(320, 480, 1)
    Scale.ScaleAllDS(tilesPanel, False)
Your reference layout or...

klaus

Expert
Licensed User
Longtime User
The Scale module is a quite old module and many things have changed since its publication and especially B4XPages.
I added a warning on top of the thread to not use it anymore.

In your example, you are not using the scaling correctly.
You mix layouts from the Designer with layout in code.
In the MainPage layout you have AutoScaleAll.
In the lbl1 layout, no AutoScale.
Then you use this for the scaling:
B4X:
    Scale.SetReferenceLayout(480, 800, 1.5)
    Scale.ScaleAll(Root, True)
The problem is that the MainPage layout has already been scaled in the Designer and you scale it again.
I replaced above two lines by these:
B4X:
    Scale.SetReferenceLayout(320, 480, 1)
    Scale.ScaleAllDS(tilesPanel, False)
Your reference layout or layout variant in the Designer is 320, 480, 1 and not 480, 800, 1.5.
You should use Scale.ScaleAllDS(tilesPanel, False).
ScaleAll scales differently vertically and horizontally.
ScaleAllDS scales like the DesignerScript.
The second parameter in ScaleAllDS must be False because the ScrollView has already been scaled.
And it works almost as you expect it.
I am not sure if the equation of AutoScaleAll in the Desiger is exactly the same as the one in the Scale module.

Effectively, with B4XPages the call of ScaleAll throws an error.
I have not used the Scale module for a long time.
I do not intend to adapt it, because it would take quite some work to adapt it to B4XPages and i have never tried it with CustomViews.

I suppose that you want to fill ScrollViews with given layouts.
Can you please give some more explanations on what exactly you want to do, to find a concrete solution.
In your example, in the lbl1 layout, maybe you could put the Labels on a Panel and set AutoScaleAll, and then load them and reposition them correctly.
 
Upvote 1
Solution

Jerryk

Active Member
Licensed User
Longtime User
Thanks for the answer.

The example is a mix of code and designer, because the designer is used as a template. In a real project I only need to use views created by code.

Your code works as expected.

Regarding the layout settings for "lbl1", I did some experiments: It doesn't matter if the three Labels are in the Panel or not. It depends on AutoScaleAll - it must not be used, otherwise the scaling is incorrect. (when used the Labels are larger and the third Label is cut off). Probably there is a double scaling, once with AutoScaleAll, the second time with ScaleAllDS.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
In your example, in the lbl1 layout, maybe you could put the Labels on a Panel and set AutoScaleAll, and then load them and reposition them correctly.
This proposal was thought without the Scale module.

Instead of this code:
B4X:
    Dim pnl As Panel
    pnl.Initialize("")
    pnl.Width = 140dip
    pnl.Height = 120dip
    pnl.LoadLayout("lbl1")
    pnl.Color = xui.Color_Cyan
    tilesPanel.AddView(pnl, 0, 0, pnl.Width, pnl.Height)
   
    Dim pnl2 As Panel
    pnl2.Initialize("")
    pnl2.Width = 140dip
    pnl2.Height = 120dip
    pnl2.LoadLayout("lbl1")
    pnl2.Color = xui.Color_Magenta
    tilesPanel.AddView(pnl2, 0, pnl.Height, pnl2.Width, pnl2.Height)

    Scale.SetReferenceLayout(320, 480, 1)
    Scale.ScaleAllDS(tilesPanel, False)

You could have this:
B4X:
    For i = 0 To 5
        Private pnlLables As Panel
        tilesPanel.LoadLayout("lbl2")
        pnlLables = tilesPanel.GetView(i)
        pnlLables.Color = xui.Color_RGB(Rnd(0, 256), Rnd(0, 256), Rnd(0, 256))
        pnlLables.Top = i * pnlLables.Height
    Next
    tilesPanel.Height = i * pnlLables.Height
In the lbl2 layout the three Labels are on a Panel with Width = 140 and Height = 120 and with AutoScalingAll.
I added more than two Panels to show what can be done in a Scrollview.

And how it looks like:

1753781769924.png
 

Attachments

  • ScaleLayoutNew.zip
    16.6 KB · Views: 27
Upvote 0

Jerryk

Active Member
Licensed User
Longtime User
I added code that is independent of the panel dimensions in the designer. I added an invisible reference panel PanelRef with dimensions of 100 x 100 to the Scrollview. Then I adjust the dimensions by calculating the ratio.
B4X:
    For i = 0 To 1
        Private pnlLables As Panel
        tilesPanel.LoadLayout("lbl2")
        pnlLables = tilesPanel.GetView(i)
        pnlLables.Color = xui.Color_RGB(Rnd(0, 256), Rnd(0, 256), Rnd(0, 256))
        pnlLables.Top = i * pnlLables.Height
    Next
    For i = 2 To 3
        Private pnlLables As Panel
        tilesPanel.LoadLayout("_pnl")
        pnlLables = tilesPanel.GetView(i)
        pnlLables.Color = xui.Color_RGB(Rnd(0, 256), Rnd(0, 256), Rnd(0, 256))
    
        Dim x As Float = 140dip  'required dimensions
        Dim y As Float = 120dip  'required dimensions
        Dim xratio As Float = x / 100dip 
        Dim yratio As Float = y / 100dip
        pnlLables.Height = PanelRef.Height * yratio
        pnlLables.Width = PanelRef.Width * xratio
    
        pnlLables.Top = i * pnlLables.Height
    Next
    
    tilesPanel.Height = i * pnlLables.Height
 
Upvote 0

Similar Threads

Top