Android Tutorial [B4XDaisyUIKit] A curious Native DeclarativeUI Experiment

Hi gang

@Maxcfgos post about DeclarativeUI really impressed something in me, less code with great impact and no worries about left, top, height, width, addview when placing components and designing your UI.

And yes, this is code friendly and abstract designer unfriendly... he he he... for AI Engineering, and those who love writing code it becomes some kind of a soft spot. Anyway after some careful research, I discovered that there are some things that Android does very well, like calculating view dimensions and layouts automatically without one having to think imperatively

1791469266483.png


So how was this possible?

Columns & Rows


Internal to the definition, we have some interesting code and more...

B4X:
#If B4A
Private Sub EnsureNativeLayout
    If joLayout.IsInitialized Then Return
    Try
        Dim joContext As JavaObject
        joContext.InitializeContext
        joLayout.InitializeNewInstance("android.widget.LinearLayout", Array(joContext))
        joLayout.RunMethod("setOrientation", Array(1)) ' 1 = VERTICAL
        
        Dim joParams As JavaObject
        joParams.InitializeNewInstance("android.widget.FrameLayout$LayoutParams", Array(-1, -1))
        
        If mBase.IsInitialized Then
            Dim vwBase As View = mBase
            Dim joBase As JavaObject = vwBase
            joBase.RunMethod("addView", Array(joLayout, joParams))
        End If
        
        ApplyPadding
        ApplyGravity
        If miBackgroundColor <> 0 Then joLayout.RunMethod("setBackgroundColor", Array(miBackgroundColor))
    Catch
        If B4XDaisyApp.DebugLogs Then Log("B4XDaisyColumn.EnsureNativeLayout: " & LastException.Message)
    End Try
End Sub
 

Mashiane

Expert
Licensed User
Longtime User
So lets look at this page's design...

B4X:
#IgnoreWarnings:12,9

'/**
' * @class B4XPageDeclarativeDemo
' * @description
' * Demonstrates the DeclarativeUI Architecture for B4XDaisyUIKit:
' * - Zero-coordinate screen layout via B4XDaisyScaffold.
' * - Automatic vertical stacking & spacing via B4XDaisyColumn (zero manual Y-math).
' * - Proportional flex distribution via B4XDaisyRow with layout weights.
' * - Coordinated TopBar, Bottom Dock, and Floating Action Button.
' */

Sub Class_Globals
    Private xui As XUI
    Private Root As B4XView

    Private scaffold As B4XDaisyScaffold
    Private dock As B4XDaisyDock
    Private fab As B4XDaisyFab

    ' Controls
    Private inpName As B4XDaisyInput
    Private inpEmail As B4XDaisyInput
    Private inpPassword As B4XDaisyInput
    Private inpCity As B4XDaisyInput
    Private inpZip As B4XDaisyInput
    Private selCountry As B4XDaisySelect
    Private tglNotify As B4XDaisyToggle
    Private chkTerms As B4XDaisyCheckbox
    Private btnSave As B4XDaisyButton
    Private btnCancel As B4XDaisyButton
    Private btnDelete As B4XDaisyButton
End Sub

Public Sub Initialize As Object
    Return Me
End Sub

Private Sub B4XPage_Created(vRoot As B4XView)
    Root = vRoot
    BuildDeclarativeUI
End Sub

Private Sub BuildDeclarativeUI
    Try
    ' Declarative UI: describe WHAT goes on screen. Mounting, stacking,
    ' spacing, scrolling and resizing are handled internally by
    ' Scaffold/Column/Row (ZERO coordinate math, ZERO AddToParent calls).
    ' 1. Initialize master scaffold.
    scaffold.Initialize(Me, "scaffold")
    scaffold.Create(Root)
    scaffold.Title("Declarative Scaffold")
    scaffold.Variant("primary")
    scaffold.WithBackNavigation(True)
    scaffold.BodyPadding(16dip)
    scaffold.Spacing(14dip)

    ' 2. Bottom dock.
    dock.Initialize(Me, "dock")
    dock.Size = "md"
    dock.ActiveIndex = 0
    dock.AddItem("home", "Home", "dock-home.svg")
    dock.AddItem("explore", "Explore", "dock-inbox.svg")
    dock.AddItem("settings", "Settings", "dock-settings.svg")
    scaffold.BottomDock(dock)

    ' 3. Floating Action Button.
    fab.Initialize(Me, "fab")
    fab.TriggerText = "+"
    fab.TriggerVariant = "secondary"
    fab.TriggerCircle = True
    scaffold.FAB(fab)

    ' 4. Auto-layout body column.
    Dim col As B4XDaisyColumn = scaffold.BodyColumn

    ' Text Inputs
    inpName.Initialize(Me, "inpName")
    inpName.LabelAbove = "Full Name"
    inpName.Placeholder = "Jane Doe"
    col.Add(inpName)

    inpEmail.Initialize(Me, "inpEmail")
    inpEmail.LabelAbove = "Email Address"
    inpEmail.Placeholder = "[email protected]"
    inpEmail.InputType = "email"
    col.Add(inpEmail)

    inpPassword.Initialize(Me, "inpPassword")
    inpPassword.LabelAbove = "Password"
    inpPassword.Placeholder = "••••••••"
    inpPassword.InputType = "password"
    col.Add(inpPassword)

    ' Two-column horizontal flex row (City & Postal Code).
    Dim rowAddress As B4XDaisyRow
    rowAddress.Initialize(Me, "rowAddress")
    rowAddress.Spacing = 12dip

    inpCity.Initialize(Me, "inpCity")
    inpCity.LabelAbove = "City"
    inpCity.Placeholder = "Johannesburg"
    rowAddress.AddWithWeight(inpCity, 1.0)

    inpZip.Initialize(Me, "inpZip")
    inpZip.LabelAbove = "Postal Code"
    inpZip.Placeholder = "2000"
    rowAddress.AddWithWeight(inpZip, 1.0)

    col.Add(rowAddress)

    ' Dropdown Select
    selCountry.Initialize(Me, "selCountry")
    selCountry.LabelAbove = "Country"
    selCountry.Placeholder = "Select a country..."
    selCountry.Items = CreateMap("za": "South Africa", "us": "United States", "gb": "United Kingdom", "de": "Germany")
    col.Add(selCountry)

    ' Toggle & Checkbox
    tglNotify.Initialize(Me, "tglNotify")
    tglNotify.Text = "Enable Push Notifications"
    tglNotify.Checked = True
    col.Add(tglNotify)

    chkTerms.Initialize(Me, "chkTerms")
    chkTerms.Text = "I agree to the terms and privacy policy"
    col.Add(chkTerms)

    ' Horizontal button action row (Save & Cancel 50/50 flex).
    ' FlexFill makes buttons fill their share instead of sizing to content.
    Dim rowActions As B4XDaisyRow
    rowActions.Initialize(Me, "rowActions")
    rowActions.Spacing = 12dip

    btnSave.Initialize(Me, "btnSave")
    btnSave.Text = "Save Changes"
    btnSave.Variant = "primary"
    btnSave.FlexFill = True
    rowActions.AddWithWeight(btnSave, 1.0)

    btnCancel.Initialize(Me, "btnCancel")
    btnCancel.Text = "Cancel"
    btnCancel.Variant = "secondary"
    btnCancel.FlexFill = True
    rowActions.AddWithWeight(btnCancel, 1.0)

    col.Add(rowActions)

    ' Full-width delete button
    btnDelete.Initialize(Me, "btnDelete")
    btnDelete.Text = "Delete Account"
    btnDelete.Variant = "error"
    btnDelete.FlexFill = True
    col.Add(btnDelete)

    ' 5. Build and mount scaffold
    scaffold.Build
    Log("DeclarativeDemo mounted: bodyChildren=" & scaffold.BodyChildCount)
    Catch
        Log("DeclarativeDemo BuildDeclarativeUI: " & LastException.Message)
        #If B4A
        Try
            Dim joEx As JavaObject = LastException
            joEx.RunMethod("printStackTrace", Null)
        Catch
        End Try
        ToastMessageShow("Declarative demo failed: " & LastException.Message, True)
        #End If
    End Try
End Sub

Private Sub B4XPage_Resize(iWidth As Int, iHeight As Int)
    If scaffold.IsInitialized Then
        scaffold.Resize(iWidth, iHeight)
    End If
End Sub

Private Sub B4XPage_Appear
    CallSubDelayed(B4XPages.MainPage, "Page_Ready")
End Sub

#If B4A
Public Sub IME_HeightChanged(iNewHeight As Int, iOldHeight As Int)
    If scaffold.IsInitialized Then
        scaffold.IME_HeightChanged(iNewHeight, iOldHeight)
    End If
End Sub
#End If

#Region Event Handlers

Private Sub scaffold_Back(oTag As Object)
    B4XPages.MainPage.ClosePageWithLoader(Me)
End Sub

Private Sub dock_ItemClick(sItemId As String)
    #If B4A
    B4XPages.MainPage.ShowToast("Dock tapped: " & sItemId, False)
    #End If
End Sub

Private Sub fab_Click(oTag As Object)
    #If B4A
    B4XPages.MainPage.ShowToast("FAB tapped!", False)
    #End If
End Sub

Private Sub btnSave_Click(oTag As Object)
    btnSave.Text = "Saved ✓"
    #If B4A
    B4XPages.MainPage.ShowToast("Saved successfully via Declarative Scaffold!", False)
    #End If
End Sub

Private Sub btnCancel_Click(oTag As Object)
    B4XPages.MainPage.ClosePageWithLoader(Me)
End Sub

Private Sub btnDelete_Click(oTag As Object)
    #If B4A
    B4XPages.MainPage.ShowToast("Delete requested", False)
    #End If
End Sub

#End Region

That's it!
 
Top