Android Tutorial [B4X] [XUI] Creating custom views with XUI

Discussion in 'Tutorials & Examples' started by Erel, Oct 17, 2017.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Start with this tutorial if you are not familiar with custom views: [B4X] Custom Views with Enhanced Designer Support

    With the help of XUI it is quite simple to create custom views classes that will work with B4A, B4i and B4J.

    The first step is to use a slightly modified template:
    Code:
    #DesignerProperty: Key: BooleanExample, DisplayName: Show Seconds, FieldType: Boolean, DefaultValue: True
    #DesignerProperty: Key: TextColor, DisplayName: Text Color, FieldType: Color, DefaultValue: 0xFFFFFFFF, Description: Text color

    Sub Class_Globals
       
    Private mEventName As String 'ignore
       Private mCallBack As Object 'ignore
       Private mBase As B4XView
      
    Private xui as XUI
    End Sub

    Public Sub Initialize (Callback As Object, EventName As String)
       mEventName = EventName
       mCallBack = Callback
    End Sub

    'Base type must be Object
    Public Sub DesignerCreateView (Base As Object, Lbl As Label, Props As Map)
       mBase = Base
      
    End Sub

    Private Sub Base_Resize (Width As Double, Height As Double)
      
    End Sub
    Example of a clock view:

    [​IMG]

    Code:
    Code:
    #DesignerProperty: Key: ShowSeconds, DisplayName: Show Seconds, FieldType: Boolean, DefaultValue: True
    #DesignerProperty: Key: TextColor, DisplayName: Text Color, FieldType: Color, DefaultValue: 0xFFA2A2A2, Description: Text color

    Sub Class_Globals
       
    Private mEventName As String 'ignore
       Private mCallBack As Object 'ignore
       Private mBase As B4XView
       
    Private mLbl As B4XView
       
    Private xui As XUI
       
    Private Timer1 As Timer
       
    Private showSeconds As Boolean
    End Sub

    Public Sub Initialize (Callback As Object, EventName As String)
       mEventName = EventName
       mCallBack = Callback
       Timer1.Initialize(
    "Timer1"1000)
    End Sub

    'Base type must be Object
    Public Sub DesignerCreateView (Base As Object, Lbl As Label, Props As Map)
       mBase = Base
       mLbl = Lbl
      mBase.AddView(mLbl, 
    00, mBase.Width, mBase.Height)
       mLbl.SetTextAlignment(
    "CENTER""CENTER")
       mLbl.TextColor = xui.PaintOrColorToColor(Props.Get(
    "TextColor"))
       showSeconds = Props.Get(
    "ShowSeconds")
       Timer1.Enabled = 
    True
       Timer1_Tick
    End Sub

    Private Sub Base_Resize (Width As Double, Height As Double)
       mLbl.SetLayoutAnimated(
    000, Width, Height)
    End Sub

    Sub Timer1_Tick
       
    Dim t As Long = DateTime.Now
       mLbl.Text = 
    $"$2.0{DateTime.GetHour(t)}:$2.0{DateTime.GetMinute(t)}"$
       
    If showSeconds Then
         mLbl.Text = mLbl.Text & 
    $":$2.0{DateTime.GetSecond(t)}"$
       
    End If
    End Sub
    I think that the only thing interesting here is the xui.PaintOrColorToColor method.
    In B4A and B4i colors are represented as Ints (0xAARRGGBB).
    In B4J colors are natively represented as Paint objects.

    In the XUI library colors are represented as Ints.
    The default color constants are available in the XUI type:
    Code:
    Button1.Color = xui.Color_Red
    Back to PaintOrColorToColor, the Props map in B4J will hold Paint objects for color values. xui.PaintOrColorToColor checks the object type and converts it, if needed, to an Int representing the same color. In B4A and B4i these methods do not do anything.

    Note that Base_Resize will only be called in B4J and B4i.

    A more advanced example: [B4X] [XUI] [custom view] CircularProgressBar
     

    Attached Files:

  2. LucaMs

    LucaMs Expert Licensed User

    Which will be the basic template in the next versions of b4a, b4j and b4i, I suppose.
     
  3. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    Hello everyone,

    What's the best way to put in a CustomProperty some DIP value?

    The question is: I need to create a property with DIP value, to put in this property

    Props.Get("BorderCornerRadius")

    But we dont have DIP types, just INT.

    So, when receive this property I need to convert from INT to DIP, and need to work to B4i and B4A.

    Thank you
     
  4. klaus

    klaus Expert Licensed User

    In the Designer all position and size properties are dip values for B4A!
    The same for the CustomProperties.
     
    Last edited: Apr 9, 2018
  5. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    Strange, because if I put for example: 10 in my property is not getting the right value, and If I hardcoded 10dip inside my customview, I got the right value
     
  6. klaus

    klaus Expert Licensed User

    Can you post your test project.
     
  7. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    is simple to explain:

    Check this property:

    Code:
    #DesignerProperty: Key: BorderCornerRadius, DisplayName: Border Corner Radius, FieldType: Int, DefaultValue: 10
    and then get the value through:

    Code:
    log(Props.Get("BorderCornerRadius"))
    I need to send the value 10 for example, but this 10 is in dip
     
  8. klaus

    klaus Expert Licensed User

    My answer in post #4 was wrong.
    You need to use:
    Code:
    BorderCornerRadius = Props.Get("BorderCornerRadius")
    #If B4A Then
        BorderCornerRadius = BorderCornerRadius / 
    GetDeviceLayoutValues.Scale
    #End If
    The code above is wrong! It aconverts pixels to dip values.

    It's the other way, thank you Erel, I remembered this answer this morning and wanted to change it, but you were faster:
    Code:
    BorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius"))
     
    Last edited: Jul 31, 2018
    Alexander Stolte likes this.
  9. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    okkk thanks Klaus.. i will try right now

    for B4i I can use GetDeviceLayoutValues.Scale?
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    It is the other way. It should be:
    Code:
    BorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius"))
    (same code for the three platforms)
     
  11. Alberto Iglesias

    Alberto Iglesias Well-Known Member Licensed User

    You absolutely right:
    Code:
    Dim iBorderCornerRadius As Int = Props.Get("BorderCornerRadius")
        LogColor(
    "iBorderCornerRadius1=" & iBorderCornerRadius,Colors.Blue)
        iBorderCornerRadius = iBorderCornerRadius / 
    GetDeviceLayoutValues.Scale
        LogColor(
    "iBorderCornerRadius2=" & iBorderCornerRadius,Colors.Blue)
        LogColor(
    "iBorderCornerRadius3=" & DipToCurrent(Props.Get("BorderCornerRadius")),Colors.Blue)
        LogColor(
    "10dip DtC=" & DipToCurrent(10),Colors.Blue)
        LogColor(
    "10dip=" & 10dip,Colors.Blue)
    Result:
    Code:
    ** Activity (main) Create, isFirst = true **
    ** 
    Activity (main) Resume **
    iBorderCornerRadius1=
    10
    iBorderCornerRadius2=
    5
    iBorderCornerRadius3=
    20
    10dip DtC=20
    10dip=20
    The confusion is because the name of function DipToCurrent should be something like :
    IntToDip, CurrentToDip, right? Because the final result is in DIP.

    Thank you again!

    Alberto
     
  12. klaus

    klaus Expert Licensed User

    You should use GetDeviceLayoutValues in B4A only, for a conversion from pixels to dip values. The GetDeviceLayoutValues method doesn't exist in B4i nor in B4J.

    No, the name DipToCurrent is correct because it converts a dip value into a pixel value.
    In B4i you don't need the conversion, it is done automatically by the OS.

    In your example you have a value of 10 and a scale of 2.
    In B4A, 10 is considered as a dip value so you need to convert it to a pixel value with DipToCurrent to get 20 pixels with:
    iBorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius".
    This is the correct line:
    iBorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius"))
     
    Last edited: Apr 10, 2018
    LucaMs and Erel like this.
  13. DonManfred

    DonManfred Expert Licensed User

    No, you get an Syntax-Error :D

    Sorry, could´nt resist :)
     
  14. LucaMs

    LucaMs Expert Licensed User

    You should try to resist and also add a Like, instead.
     
  15. klaus

    klaus Expert Licensed User

    Sorry, it must be:
    iBorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius"))
     
  16. DonManfred

    DonManfred Expert Licensed User

    Code:
    iBorderCornerRadius = DipToCurrent(Props.Get("BorderCornerRadius"))
    ;)
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice