Android Tutorial Designer Scripts Tutorial

Background

One of the most common issues that Android developers face is the need to adopt the user interface to devices with different screen sizes.
As described in the visual designer tutorial, you can create multiple layout variants to match different screens.
However it is not feasible nor recommended to create many layout variants.

Basic4android v1.9 introduces a new tool named "designer scripts" that will help you fine tune your layout and easily adjust it to different screens and resolutions.

The idea is to combine the usefulness of the visual designer with the flexibility and power of programming code.

You can write a simple script to adjust the layout based on the dimensions of the current device and immediately see the results. No need to compile and install the full program each time.

You can also immediately see the results on the abstract designer. This allows you to test your layout on many different screen sizes.

How to

Every layout file can include script code. The script is written inside the visual designer under the new Designer Scripts tab:

SS-2012-03-20_12.55.44.png


Their are two types of scripts: the general script that will be applied to all variants, and a script specific to the current variant.

Once you press on the Run Script button (or F5), the script is executed and the connected device / emulator and abstract designer will show the updated layout.

The same thing happens when you run your compiled program. The (now compiled) script is executed after the layout is loaded.

The general script is first executed followed by the variant specific script.

The script language is very simple and is optimized for managing the layout.

Lets start with an example.

Example

In this example we will build the following layout:
SS-2012-03-20_13.08.05.png


btnLeft and btnRight should be located in the top corners.
btnDown should be located at the bottom and fill the entire width.
ListView1 should fill the entire available area.
ToggleButton1 should be located exactly in the center.

The first step is to add the views and position them with the visual designer (you do not need to be 100% accurate).
Now we will select the designer scripts tab and add the code.
Note that the views are locked when the designer scripts tab is selected.

The code in this case is:
B4X:
'All variants script
btnRight.Right = 100%x

btnDown.Bottom = 100%y
btnDown.Width = 100%x

EditText1.Width = 100%x
EditText1.Bottom = btnDown.Top - 5dip

ListView1.Width = 100%x
ListView1.SetTopAndBottom(btnLeft.Bottom, EditText1.Top)

ToggleButton1.HorizontalCenter = 50%x
ToggleButton1.VerticalCenter = 50%y

The result:

SS-2012-03-20_15.10.06.png


10'' tablet:
SS-2012-03-20_15.11.16.png


SS-2012-03-20_15.35.16.png


Reference

The following properties are supported:

- Left / Right / Top / Bottom / HorizontalCenter / VerticalCenter - Gets or sets the view's position. The view's width or height will not be changed.

- Width / Height - Gets or Sets the view's width or height.

- TextSize - Gets or sets the text size. You should not used 'dip' units with this value as it is already measured in physical units.

- Text - Gets or sets the view's text.
TextSize and Text properties are only available to views that show text.

- Image - Sets the image file (write-only). Only supported by ImageView.

- Visible - Gets or sets the view's visible property.

Methods:

- SetLeftAndRight (Left, Right) - Sets the view's left and right properties. This method changes the width of the view based on the two values.

- SetTopAndBottom (Top, Bottom) - Sets the view's top and bottom properties. This method changes the height of the view based on the two values.

Keywords:

- Min / Max - Same as the standard Min / Max keywords.
- AutoScale - Autoscales a view based on the device physical size.
Example:
B4X:
AutoScale(Button1)
- AutoScaleAll - Autoscales all layout views.
Example:
B4X:
AutoScaleAll
- AutoScaleRate - Sets the scaling rate, a value between 0 to 1. The default value is 0.3
Example:
B4X:
AutoScaleRate(0.2)

- ActivitySize - Returns the approximate activity size measured in inches.

- If ... Then condition blocks - Both single line and multiline statements are supported. The syntax is the same as the regular If blocks.

- Landscape (v3.20) - Returns True if the current orientation is landscape.
- Portrait (v3.20) - Returns True if the current orientation is portrait.

Notes and tips

- %x and %y values are relative to the view that loads the layout.
Usually it will be the activity. However it you use Panel.LoadLayout then it will be relative to this panel.
Note that ScrollView inner panel width is set to -1. This is a special value that causes the panel to fill its parent available size.
If you want to load a layout file (with a script) to the inner panel then you will need to first set the panel width: ScrollView.Panel.Width = ScrollView.Width.

- Use 'dip' units for all specified sizes (except of TextSize). By using 'dip' units the values will be scaled correctly on devices with higher or lower resolution.

- In most cases it is not recommended to create variants with scales other than 1.0. When you add such a variant you will be given an option to add a normalized variant instead with a scale of 1.0.

- Variables - You can use variables in the script. You do not need to declare the variables before using them (there is no Dim keyword in the script).

- Activity.RerunDesignerScript (LayoutFile As String, Width As Int, Height As Int) - In some cases it is desirable to run the script code again during the program. For example you may want to update the layout when the soft keyboard becomes visible. Activity.RerunDesignerScript method allows you to run the script again and specify the width and height that will represent 100%x and 100%y. In order for this method to work all the views referenced in the script must be declared in Sub Globals.
Note that this method should not be used to handle screen orientation changes. In that case the activity will be recreated and the script will run during the Activity.LoadLayout call.

It is recommended to continue to this tutorial: http://www.basic4ppc.com/forum/basi...ing-multiple-screens-tips-best-practices.html
 
Last edited:

johnaaronrose

Active Member
Licensed User
Newbie questions

I have a layout (named main) with 2 views on it, both occupying the full width of the standard 320x480 scale=1 variant, the app only being allowed to run as portrait, and IncludeTitle set to True in the Activity of main. The top panel is named pnlMap with top of 0 & height of 370; the bottom panel is named pnlButtons (which contains buttons) with top of 370 & height of 50: thus, the 2 panels occupy the whole of the screen and do not overlap. I have an 'All variants script' (and no scripts for specific variants) of:
AutoScaleRate(0.5)
AutoScaleAll
pnlButtons.HorizontalCenter = 50%x
pnlButtons.Bottom = 100%y
pnlMap.SetTopAndBottom(0, pnlButtons.Top)

However, when I "Send to UI Cloud", the display in the Browser shows that the bottom of pnlButtons (as shown by the buttons) is not aligned with the bottom of the various devices in the web page. Could someone explain this & what I have to do to correct it?

Also, when I install the app & run it on a 480x800 scale 1.5 phone, pnlMap's area (the Activity has code to load a geographical map into pnlMap's area) covers the buttons.
 

johnaaronrose

Active Member
Licensed User
Panel Dimensions

Setting the Bottom property will only move the view. You should use a "fill" method
B4X:
pnlButtons.SetTopAndBottom(pnlButtons.Top, 100%y)

After above change, still didn't work as I wanted: namely pnlMap & pnlButtons to take up whole of 480x800scale=1.5 device's screen (excluding title) without overlapping. I put in a Msgbox to display the panels' dimensions at runtime on the above device. It showed pnlMap (from Width & Height properties) as 496width x 574height; it showed pnlButtons as 496width x 150height. Thus, combined height is 724 (presumably in pixels). So if title on above device is 75 pixels (due to scaling up from 50 pixels), this would seem reasonable. However, I don't understand how width of 496 (rather than 480) is obtained. Also, I don't understand how the heights of 574 & 150 are obtained, given that the Designer showed them originally as 370 & 60: by my calculations they should have become
623 & 101 (e.g. 623=370*(800-75)/(480-50))
 

klaus

Expert
Licensed User
Your original code in the Abstract Designer works well.
For the buttons you must set pnlButtons as the Parent view and not Activity !
pnlButtons was positioned correctly but as your buttons are not on the panel they are not moved.

Best regards.
 

Attachments

  • main.bal
    3.2 KB · Views: 171

johnaaronrose

Active Member
Licensed User
Panel & Button Sizes & Positions

Your original code in the Abstract Designer works well.
For the buttons you must set pnlButtons as the Parent view and not Activity !
pnlButtons was positioned correctly but as your buttons are not on the panel they are not moved.

Best regards.

After above change, still didn't work as I wanted: namely pnlMap & pnlButtons to take up whole of 480x800scale=1.5 device's screen (excluding title) without overlapping. I put in a Msgbox to display the panels' dimensions at runtime on the above device. It showed pnlMap (from Width & Height properties) as 496width x 574height; it showed pnlButtons as 496width x 150height. Thus, combined height is 724 (presumably in pixels). So if title on above device is 83 pixels (due to scaling up from 480 to 800 pixels for height of the 50 pixels Activity.Title), this is only 7 pixels inaccurate from the runtime value of 800-574-150=76. I don't understand how width of 496 (rather than 480) is obtained. Also, I don't understand how the heights of 574 & 150 are obtained, given that the Designer showed them originally as 370 & 60 (the sum of these 2 numbers being 430 i.e. the height of a 320x480scale=1.0 device less 50 pixels for the Activity.Title): by my calculations they should have become
616 & 100 i.e. 370*(800-83)/(480-50) & 60*(800-83)/(480-50).
 

klaus

Expert
Licensed User
Sorry, I didn't look carefuly enough.

The problem is AutoScale.
Look in the Beginner's Guide
at chapter 8.10 AutoScale
and especially 8.10.3 AutoScale more advanced examples
In this chapter your problem is explained more in detail.

Best regards.
 

johnaaronrose

Active Member
Licensed User
Thanks

Sorry, I didn't look carefuly enough.

The problem is AutoScale.
Look in the Beginner's Guide
at chapter 8.10 AutoScale
and especially 8.10.3 AutoScale more advanced examples
In this chapter your problem is explained more in detail.

Best regards.

Thanks for that info. It looks to me like Designer Scripts are no good to me. I'll revert back to using the Spreadsheet method whcih repositions & resizes views separately for horizontally & vertically.
 

cmartins

Member
Licensed User
I need to read some global var and create in script designer the folowing situation:


If varGlobal = 0 Then
lbHod.TextSize = (lbHodCalculado.TextSize * scale) * .9
Else
lbHod.TextSize = (lbHodCalculado.TextSize * scale) * .4
End If

Whe I trie to run the script I got an error. Unassigned variable: varGlobal
How to implement it?
 

klaus

Expert
Licensed User
You could put the code in the Activity_Create routine.
If varGlobal depends on the device size, you have the ActivitySize keyword in the DesignerScript.
From the tutorial:
ActivitySize - Returns the approximate activity size measured in inches.

Best regards.
 

Avansys

Member
Licensed User
How to resize automatically the text in a label or edittext.?

I assumed that the text size will automatically change with the size of the label or the EditText, but I have the following code:

lblWelc.Left = 10dip
lblWelc.Width = 95%x
lblWelc.Height = 10%y

lblData.Left = 10dip
lblData.Width = 95%x
lblData.Height = 10%y


but the text looks the same size at any percentage of the label or the EditText.

Someone can help me?

thanks
 

moster67

Expert
Licensed User
Using design-scripts, I am wondering if variables are re-usable when a different layout-variant is being loaded?

Let's say I have the following script in the standard all variant 320x480,scale=1 :

B4X:
'All variants script
AutoScaleAll 'uncomment to scale all views based on the device physical size.

VertIconWidth=25%x
VertFreeSpace=100%x-(VertIconWidth*3)
VertDistance=VertFreeSpace/4

pad=0%x
btnServices.SetLeftAndRight(pad+VertDistance,(pad+VertDistance+VertIconWidth))
pad=btnServices.Right
btnMovies.SetLeftAndRight(pad+VertDistance,(pad+VertDistance+VertIconWidth))
pad=btnMovies.Right
btnTimer.SetLeftAndRight(pad+VertDistance,(pad+VertDistance+VertIconWidth))
lblServices.SetLeftAndRight(btnServices.Left,btnServices.right)
lblMovies.SetLeftAndRight(btnMovies.Left,btnMovies.right)
lblTimer.SetLeftAndRight(btnTimer.Left,btnTimer.right)

Now I have another variant (let's say: 800x1280,scale=1) which will be detected:

For this variant (800x1280,scale=1), I would like to slightly increase my variable VertIconWidth from 25%x to 27%x but I noted that if I write

B4X:
VertIconWidth=27%x

in the variant specific script: 800x1280,scale=1, there is no change and it seems like this variable is being ignored.

I would have thought that variables from the "All variants script" would have been taken into consideration too, just like if I would have changed a "left-property" of a view (which works).

If this is not possible, I will simply copy my script into the specific variant-script adjusting my VertIconWidth-variable but to me it would have been nice to just copy the line
B4X:
VertIconWidth=27%x
into the specific variant-script without copying the whole script. Could this be implemented?
 

Erel

Administrator
Staff member
Licensed User
Variables are not copied between the variants / general script.

As I see it in most cases you do not need to write any variant specific code. You should instead use a condition (with ActivitySize most probably) and do whatever you need to do in the general script.

The variant scripts feature was introduced before conditions were available.
 
Top