Share My Creation [B4X][B4A] B4XYogaLayoutEngine aka No Manual Coordinates Layouts

Hi Fam

With the B4XDaisyUIKit, I have been faced with most code following and flex and grid layout placement, no left, top, bottom co-ordinates. Research led me to Meta Yoga, a layout engine

used by Meta for React-Native. If ever you have ever come across react & react-native, you will soon recognize the use of style objects, its not css however it works like it. So me thinks, this should be possible in b4x, so this is our initial version.

Yes, the B4XDaisyUIKIt has a layout engine, a port of the web standards, however I had not tested ir fully to be comfortable with it for production use. This then could become a good alternative, as soon as I figure it out completely.

1773168781245.png


What is Meta's Yoga?

Meta’s Yoga is a cross-platform, embeddable layout engine that computes the size and position of boxes using a mostly Flexbox-style model. It is not a UI toolkit and it does not render anything itself; it only performs layout calculation. It is written in C++, exposes a public C API, and has bindings for multiple languages.

In practical terms, Yoga is the piece that lets a framework say, “Given this tree of nodes and these style properties, where should everything go?” That is why it is used in systems like React Native and other native UI frameworks. Meta’s own docs describe it as a portable layout engine “targeting web standards,” and the repo README calls it an “embeddable and performant flexbox layout engine.”

Lets visit the code for this screen..

B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
       
    ' The FlexContainer manages our entire layout
    Private fc As FlexContainer
   
    ' ============================================================
    ' STYLES — Defined like React Native's StyleSheet.create()
    ' ============================================================
    Private Styles As Map
End Sub
'You can add more parameters here.
Public Sub Initialize As Object
    Return Me
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
       
    ' ── Step 1: Define all styles (like StyleSheet.create) ──
    CreateStyles
   
    ' ── Step 2: Initialize FlexContainer with root panel ──
    fc.Initialize(Root, Me)
    fc.SetStyle(Styles.Get("container"))
   
    ' ── Step 3: Build the view tree ──
    BuildUI
   
    ' ── Step 4: Calculate layout and apply ──
    fc.CalculateAndApply
   
    ' Debug: Print the layout tree
    fc.DebugTree
End Sub

' ============================================================
' STYLES — All styles defined in one place
' Mirror of React Native's StyleSheet.create()
' ============================================================
Private Sub CreateStyles
    Styles = FlexStyle.StyleSheet(Array( _
        "container", CreateMap( _
            "flexDirection": "column", _
            "padding": 16, _
            "backgroundColor": "#0f172a", _
            "flex": 1), _
        _
        "header", CreateMap( _
            "flexDirection": "column", _
            "paddingBottom": 20, _
            "paddingTop": 8), _
        _
        "title", CreateMap( _
            "fontSize": 28, _
            "fontWeight": "bold", _
            "color": "#ffffff", _
            "marginBottom": 4), _
        _
        "subtitle", CreateMap( _
            "fontSize": 14, _
            "color": "#94a3b8"), _
        _
        "card", CreateMap( _
            "flexDirection": "column", _
            "backgroundColor": "#1e293b", _
            "borderRadius": 12, _
            "padding": 16, _
            "marginBottom": 12), _
        _
        "cardTitle", CreateMap( _
            "fontSize": 12, _
            "fontWeight": "bold", _
            "color": "#64748b", _
            "marginBottom": 12, _
            "textTransform": "uppercase"), _
        _
        "cardRow", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "space-between", _
            "alignItems": "center", _
            "paddingVertical": 8), _
        _
        "cardLabel", CreateMap( _
            "fontSize": 16, _
            "color": "#e2e8f0"), _
        _
        "cardValue", CreateMap( _
            "fontSize": 14, _
            "color": "#94a3b8"), _
        _
        "cardValueActive", CreateMap( _
            "fontSize": 14, _
            "color": "#818cf8"), _
        _
        "divider", CreateMap( _
            "height": 1, _
            "backgroundColor": "#334155"), _
        _
        "button", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "#6366f1", _
            "borderRadius": 12, _
            "height": 52, _
            "marginTop": 8), _
        _
        "buttonText", CreateMap( _
            "fontSize": 16, _
            "fontWeight": "bold", _
            "color": "#ffffff"), _
        _
        "dangerButton", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "transparent", _
            "borderRadius": 12, _
            "borderWidth": 1, _
            "borderColor": "#ef4444", _
            "height": 48, _
            "marginTop": 8), _
        _
        "dangerText", CreateMap( _
            "fontSize": 14, _
            "color": "#ef4444") _
    ))
End Sub
' ============================================================
' BUILD UI — Construct the view tree
' This mirrors React Native's render() / JSX
' ============================================================
Private Sub BuildUI
   
    ' ── Header Section ──
    Dim header As FlexView = fc.CreatePanel("header", Styles.Get("header"))
    Dim title As FlexView = fc.CreateLabel("title", "Settings", Styles.Get("title"))
    Dim subtitle As FlexView = fc.CreateLabel("subtitle", "Manage your preferences", Styles.Get("subtitle"))
   
    fc.Root.AddChild(header)
    header.AddChild(title)
    header.AddChild(subtitle)
   
    ' ── Appearance Card ──
    Dim card1 As FlexView = fc.CreatePanel("card1", Styles.Get("card"))
    Dim card1Title As FlexView = fc.CreateLabel("card1Title", "Appearance", Styles.Get("cardTitle"))
   
    fc.Root.AddChild(card1)
    card1.AddChild(card1Title)
   
    ' Dark Mode row
    AddSettingsRow(card1, "darkMode", "Dark Mode", "On", True)
    AddDivider(card1, "div1")
    ' Font Size row
    AddSettingsRow(card1, "fontSize", "Font Size", "Medium", False)
    AddDivider(card1, "div2")
    ' Language row
    AddSettingsRow(card1, "language", "Language", "English", False)
   
    ' ── Notifications Card ──
    Dim card2 As FlexView = fc.CreatePanel("card2", Styles.Get("card"))
    Dim card2Title As FlexView = fc.CreateLabel("card2Title", "Notifications", Styles.Get("cardTitle"))
   
    fc.Root.AddChild(card2)
    card2.AddChild(card2Title)
   
    ' Push Notifications row
    AddSettingsRow(card2, "push", "Push Notifications", "On", True)
    AddDivider(card2, "div3")
    ' Email row
    AddSettingsRow(card2, "email", "Email Notifications", "Off", False)
    AddDivider(card2, "div4")
    ' Sound row
    AddSettingsRow(card2, "sound", "Sound", "Default", False)
   
    ' ── Spacer (pushes buttons to bottom) ──
    Dim spacer As FlexView = fc.CreateSpacer("spacer", 1)
    fc.Root.AddChild(spacer)
   
    ' ── Save Button ──
    Dim saveBtn As FlexView = fc.CreatePanel("saveBtn", Styles.Get("button"))
    Dim saveBtnText As FlexView = fc.CreateLabel("saveBtnText", "Save Changes", Styles.Get("buttonText"))
   
    fc.Root.AddChild(saveBtn)
    saveBtn.AddChild(saveBtnText)
   
    ' ── Logout Button ──
    Dim logoutBtn As FlexView = fc.CreatePanel("logoutBtn", Styles.Get("dangerButton"))
    Dim logoutBtnText As FlexView = fc.CreateLabel("logoutBtnText", "Log Out", Styles.Get("dangerText"))
   
    fc.Root.AddChild(logoutBtn)
    logoutBtn.AddChild(logoutBtnText)
End Sub
' ============================================================
' HELPER: Add a settings row (label + value)
' ============================================================
Private Sub AddSettingsRow(parent As FlexView, tag As String, label As String, value As String, isActive As Boolean)
    Dim row As FlexView = fc.CreatePanel(tag & "Row", Styles.Get("cardRow"))
    Dim rowLabel As FlexView = fc.CreateLabel(tag & "Label", label, Styles.Get("cardLabel"))
   
    ' Use active style if flag is set (like RN conditional style)
    Dim valueStyle As Map
    If isActive Then
        valueStyle = Styles.Get("cardValueActive")
    Else
        valueStyle = Styles.Get("cardValue")
    End If
    Dim rowValue As FlexView = fc.CreateLabel(tag & "Value", value, valueStyle)
   
    parent.AddChild(row)
    row.AddChild(rowLabel)
    row.AddChild(rowValue)
End Sub
' ============================================================
' HELPER: Add a divider line
' ============================================================
Private Sub AddDivider(parent As FlexView, tag As String)
    Dim divider As FlexView = fc.CreatePanel(tag, Styles.Get("divider"))
    parent.AddChild(divider)
End Sub
' ============================================================
' RESIZE — Re-run layout when screen size changes
' ============================================================
Private Sub B4XPage_Resize(Width As Int, Height As Int)
    fc.Resize(Width, Height)
End Sub


Related Content


#SharingTheGoodness
 
Last edited:
Top