Android Tutorial [B4X] [DSE] Designer Script Extensions

Status
Not open for further replies.
The soon to be released versions of B4A, B4i and B4J include a new feature named: designer script extensions. The new feature allows calling B4X code from the visual designer scripts.
Note that the B4X code is not executed at design time.
I believe that over time this new feature, with a supportive framework, will change the way we manage complex layouts.

Q: Which subs can be called from the designer script?

1. Subs in classes.
2. The subs signature must be a single DesignerArgs parameter. Example:
B4X:
'Adds a class attribute to one or more views.
'Parameters: ClassName, One or more views.
Private Sub AddClass(DesignerArgs As DesignerArgs)
Calling this method from the script (class name is DDD):
B4X:
DDD.AddClass("small button", Button1, Button3)
As you can see, the script call can include any number of parameters. The DesignerArgs object will hold all the parameters, as well as other useful information about the layout.

Q: How is the class instance created?

It depends. By default a new class instance will be created on the first time it is needed, and it will be cached. The Initialize sub of the class must not include any parameter.
The other option is to use XUI.RegisterDesignerClass to assign a specific instance that will be used.
You can get the cached class instance with XUI.GetRegisteredDesignerClass. It is probably a bit obscure for now, but these two methods are very useful.

Lets start with a silly example.
We want a DS extension that blinks views.

Code in B4XMainPage:
B4X:
'Parameters: Duration, View
Private Sub BlinkView(DesignerArgs As DesignerArgs)
    'In B4i and B4J the script will run multiple times. We want to run this code once.
    If DesignerArgs.FirstRun Then
        Dim duration As Int = DesignerArgs.Arguments.Get(0)
        Dim v As B4XView = DesignerArgs.GetViewFromArgs(1)
        Do While True
            v.SetVisibleAnimated(duration, False)
            Sleep(duration + 10)
            v.SetVisibleAnimated(duration, True)
            Sleep(duration + 10)
        Loop
    End If
End Sub
It is important to document the parameters as there is no other hint for the expected parameters. The documentation will appear in the designer script.

DS:
B4X:
B4XMainPage.BlinkView(500, Button1)
B4XMainPage.BlinkView(1000, Button2)

A new internal library is available named DesignerUtils. It includes a class named DDD with all kinds of useful method. I recommend developers to check it source code (inside the b4xlib = zip).

Example of using DDD:

B4J_ZHyMc7OPeu.gif

B4X:
DDD.SpreadControlsHorizontally(Pane1, 100dip, 10dip)
TextSize = 16
DDD.SetTextAndSize(Button1, TextSize, "Sunday", "Sun", "1")
DDD.SetTextAndSize(Button2, TextSize, "Monday", "Mon", "2")
DDD.SetTextAndSize(Button3, TextSize, "Tuesday", "Tue", "3")
DDD.SetTextAndSize(Button4, TextSize, "Wednesday", "Wed", "4")
DDD.SetTextAndSize(Button5, TextSize, "Thursday", "Thu", "5")
DDD.SetTextAndSize(Button6, TextSize, "Friday", "Fri", "6")
DDD.SetTextAndSize(Button7, TextSize, "Saturday", "Sat", "7")
DDD.SetTextAndSize(Button8, TextSize, "Click here", "Click")

Updates:
v1.04 - Fixes a bug with the classes feature. New Color method.
 

Attachments

  • DSExample.zip
    182.8 KB · Views: 959
  • DSExampleCLV.zip
    187.6 KB · Views: 848
  • DSExampleNumpad.zip
    18.8 KB · Views: 806
  • DSExampleToolbar.zip
    123.2 KB · Views: 811
  • DesignerUtils.b4xlib
    3.7 KB · Views: 713
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
The updated version of the very useful SimpleMediaManager library allows setting the media from the designer. You can use it for example to show an online image.
So instead of adding a (B4X)ImageView, and downloading the image and all the boring code, you can simply add to the designer script:

B4X:
SimpleMediaManager.DesignerSetMedia(Pane2, "https://b4x-4c17.kxcdn.com/android/forum/data/avatars/m/0/1.jpg?1469350209")

In this case, we don't want the designer to create a new SMM instance so we register it ourselves, before the layout is loaded
B4X:
xui.RegisterDesignerClass(MediaManager)
If you are only using SMM with the designer script then the above step is not needed.

Interestingly the sub code also takes care of the parent panel being resized:
B4X:
'Designer script SetMedia. Parameters: Pane(l), Url
Private Sub DesignerSetMedia(DesignerArgs As DesignerArgs)
    Dim Target As B4XView = DesignerArgs.GetViewFromArgs(0)
    Dim url As String = DesignerArgs.Arguments.Get(1)
    If DesignerArgs.FirstRun Then
        SetMedia(Target, url)
    Else
        PanelResized(Target)
    End If
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I've uploaded another DesignerUtils example:

1655890097765.png
1655890118205.png


This example demonstrates the "get by name" and "get by class" features.
Special attention needed with custom views. It is explained in the source comments and also in this tutorial: [B4X] How to get <custom view here> from <CLV or any other container>

In order for the views data to be collected we need to call DDD.CollectViewsData in the designer script.
Later we can get views with:
B4X:
Dim btn As B4XView = dd.GetViewByName(pnl, "Button12")
pnl - the panel that the layour was loaded to.

Or by class:
B4X:
For Each rb As B4XView In dd.GetViewsByClass("radiobutton")
Classes are added in the designer script:
B4X:
DDD.AddClass("label", Label1, Label2) 'any number of views

Note that it is also possible to set name and add classes to views created programmatically, with dd.AddRuntimeView.

The new example depends on DesignerUtils v1.01. The updated library is attached (it will be of course included in the next beta).
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Toolbar creator example:

1655979354620.png


This example is a bit different than the others as it creates new controls and delegates their events using DesignerArgs.LayoutModule. This property returns a reference to the module where the layout was loaded.

Creating a toolbar is done in the DS with:
B4X:
'Parameters: Panel, EventName, [label, tag]+
ToolbarCreator.CreateToolbar(Pane1, "BottomToolbar", DDD.ToChr(0xF015), "home", _
    DDD.ToChr(0xF217) & " abc", "cart", DDD.ToChr(0xF1D9), "send")
DDD.SpreadControlsHorizontally(Pane1, 120dip, 10dip)

1655979520530.png


Each of the toolbar panels holds a single label. The text properties of this label are used when creating the toolbar labels. The stub label is then removed.

The events code:
B4X:
Private Sub BottomToolbar_Click (Tag As String)
    Log(Tag)
    B4XPages.SetTitle(Me, Tag)
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
v1.04 uploaded to first post.
1. It fixes the bug Klaus reported related to classes case sensitivity.
2. It adds several methods to help working with colors:

Designer script:
B4X:
B4XMainPage.SetTextColor(Button1, DDD.Color("small text"))
B4XMainPage.SetTextColor(Button2, DDD.Color("0xFFD776B0"))
B4XMainPage.SetTextColor(Label9, DDD.Color("Red"))

B4X:
B4X:
dd.Initialize
xui.RegisterDesignerClass(dd)
dd.AddColor("small text", xui.Color_Magenta)
Root.LoadLayout("MainPage")

'View, Color
Private Sub SetTextColor(DesignerArgs As DesignerArgs)
    Dim view As B4XView = DesignerArgs.GetViewFromArgs(0)
    Dim clr As Int = DesignerArgs.Arguments.Get(1)
    view.TextColor = clr
End Sub

DDD.Color expects a hex string or a named color. The standard colors are available and you can add your own colors as demonstrated above.
 
Status
Not open for further replies.
Top