Android Tutorial DialogView: A complete walk-through guide

Introduction

Since we discovered b4a I looked for a flexible and developer friendly dialog library with an extensive and versatile object model. Unfortunately I could not find anything that could satisfy our development requirements so I decided to write one.

This tutorial is available in the latest XtraViews package and as standalone APK

Part 1 Creating a custom login dialog

DialogViews are based on layouts that are build with the b4a integrated dialog designer. First of all, design the layout like you do with any other activity layout. Start with dropping a panel and then drop all needed controls inside that panel. In our case, 2 textedit controls. Set the appropriate anchors save the layout into the "dialog1" file and move on to the code.

upload_2014-7-20_2-14-9.png
upload_2014-7-20_2-15-33.png


Let's instantiate our DialogView in our Sub Globals:
B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim Dialog As DialogView
End Sub
In our button click handler, load the layout in the dialog and show it.
B4X:
Dialog.LoadLayout("dialog1").ShowYesNo("Login", "proceed", "later")
Note that dialog1 is the name of the layout file. The engine will open the layout, extract the first panel that it will find and will generate our dialog with the views inside. The ShowYesNo method will show the dialog with a system title and 2 buttons.


Part 2 Accessing views in the dialog

Now that we have our barebone dialog, we can proceed with accessing its views. Lets add a label in our layout and change it's text and color in code. In order to do this we have to break our single function call into several parts.

First, create a DialogViewLayout object using our global DialogView instance and load our layout.
B4X:
Dim DialogLayout As DialogViewLayout
DialogLayout = Dialog.LoadLayout("dialog2")
Then, get a handle of the label we want to access
B4X:
Dim Label1 As Label = DialogLayout.Views.Get("label1")
Set the label properties
B4X:
Label1.Text = "Please login below:"
Label1.TextColor = Colors.Red
Finally, call our ShowYesNo method
B4X:
Dim Result As Int = DialogLayout.ShowYesNo("Login", "proceed", "later")
Main.Toast.Show("Result = " & Result)

One powerful feature of the DialogView engine are the events that will be raised before the dialog is shown and before the dialog is dismissed.
B4X:
Sub Dialog2_Show
    'This event will be raised just before the dialog is closed passing the DialogResult
    Main.Toast.Show(Dialog.Name & " is shown")
End Sub

Sub Dialog2_Dismiss (DialogResult As Int) As Boolean
    'This event will be raised just before the dialog is closed passing the DialogResult
    'Return true to dismiss or false to cancel
    Return True
End Sub


Part 3 Advanced event handling

Now that we know how to access views in our layout, let's go a step further and do something more complicated.

upload_2014-7-20_4-8-4.png
upload_2014-7-20_4-8-58.png


Lets add a Button that we will use to clear the fields. When ever the text changes, our code will enable or disable the clear button accordingly.

Now, let's write the code that will enable/disable the clear button
B4X:
Sub SetBtnClearState
    'Get the EdUserName and EdPassword from the layout
    Dim EdUserName As Label = Dialog.Views.Get("EdUserName")
    Dim EdPassword As Label = Dialog.Views.Get("EdPassword")

    'Get the BtnClear from the layout
    Dim BtnClear As Button = Dialog.Views.Get("BtnClear")

    'Enable or disable the BtnClear according to user input
    BtnClear.Enabled = EdUserName.Text <> "" OR EdPassword.Text <> ""
End Sub
Generate the TextChanged event from the layout designer for both textedits and call the previous function.
B4X:
Sub EdElement_TextChanged (Old As String, New As String)
    'Use CallSubDelayed in order to avoid deadlocks
    CallSubDelayed(Me, "SetBtnClearState")
End Sub
Generate the Click handler for the BtnClear button from the layout designer
B4X:
Sub BtnClear_Click
    'Get the EdUsername from the layout AND clear it
    Dim EdUserName As Label = Dialog.Views.Get("EdUserName")
    EdUserName.Text = ""

    'Get the EdPassword from the layout and clear it
    Dim EdPassword As Label = Dialog.Views.Get("EdPassword")
    EdPassword.Text = ""
End Sub
In our Dialog3_Dismiss event we cancel the dialog dismiss if the user has clicked the "proceed" button and the textedits are not filled in.
B4X:
Sub Dialog3_Dismiss (DialogResult As Int) As Boolean
    'This event will be raised just before the dialog is closed passing the DialogResult
    'Return true to dismiss or false to cancel

    Dim AllowDismiss As Boolean

    If DialogResult = DialogResponse.POSITIVE Then
        'Get the edit views contents
        Dim EdUserName As Label = Dialog.Views.Get("EdUserName")
        Dim EdPassword As Label = Dialog.Views.Get"EdPassword")

        'if any of them is empty return false
        AllowDismiss = EdUserName.Text <> "" AND EdPassword.Text <> ""
    Else
        AllowDismiss = True
    End If

    If Not(AllowDismiss) Then Main.Toast.Show("all fields are required!")

    Return AllowDismiss
End Sub
Finally, we show the dialog and with the Msgbox function of the DialogView the user input.
B4X:
Dim Result As Int = DialogLayout.ShowYesNo("Login", "proceed", "later")
If Result = DialogResponse.POSITIVE Then
    Dim EdUserName As Label = Dialog.Views.Get("EdUserName")
    Dim EdPassword As Label = Dialog.Views.Get("EdPassword")

    Dialog.Msgbox("DialogView", "<b>Username:</b> " & EdUserName.Text & "<br/><br/>" & "<b>Password:</b> " & EdPassword.Text, "done", "", "", LoadBitmap(File.DirAssets, "icon1.png"))
End If


Part 4 Listview and layout per orientation

Now, lets make it a little bit more complex. Let's create 2 different layouts containing some buttons and a listview. One for portrait and one for landscape.

upload_2014-7-20_1-21-54.png
upload_2014-7-20_1-23-19.png


Another powerful feature of the DialogView engine is that whenever the user clicks on a button with a numeric id in its tag, the DialogView will dismiss itself and will return the tag of that button as a result. Following that methodology, let's set Button1 tag to 1 and Button2 tag to 2.

Create the function that we will use to add some items to the listview
B4X:
Sub AddItemsToTheListView(ListView As ListView)
    Dim Count As Int = ListView.Size
    For i=1 To 10
        ListView.AddSingleLine("item #" & (Count + i))
    Next
    ListView.SetSelection(ListView.Size)
End Sub
Then, create the Click handler of the BtnBeepAndAddItems button in the layout designer
B4X:
Sub BtnBeepAndAddItems_Click
    Dim Beeper As Beeper : Beeper.Initialize(300, 500) : Beeper.Beep
    Dim ListView As ListView = Dialog.Views.Get("ListView1")

    AddItemsToTheListView(Dialog.Views.Get("ListView1"))
    Main.Toast.Show("10 items added to the listview (total: " & ListView.Size & ")")
End Sub
Create the ItemClick handler of the ListView1 in the layout designer
B4X:
Sub ListView1_ItemClick (Position As Int, Value As Object)
    Main.Toast.Show("listview (pos #" & Position & ") = " & Value)
End Sub
Load the multiple layouts by using the LoadLayoutMultiple method
B4X:
Dim DialogLayout As DialogViewLayout
DialogLayout = Dialog.LoadLayoutMultiple("dialog4_portrait", "dialog4_landscape", "dialog4")
Get a reference of the ListView1 from the layout, set the textcolor and add 10 items to it
B4X:
Dim ListView1 As ListView = DialogLayout.Views.Get("ListView1")
ListView1.SingleLineLayout.Label.TextColor = Colors.Black
AddItemsToTheListView(ListView1)
Finally, show the dialog without the system title and buttons
B4X:
Dim Result = DialogLayout.ShowDefault


Part 5 A reusable custom dialog

After having gone through the previous steps, it is very easy even to create a reusable custom dialog.

upload_2014-7-20_1-42-33.png
upload_2014-7-20_1-43-52.png


Set the tag of the label that your want to use as a title to "title" and the tag of the label you want to use as content to "content" and call the following function:
B4X:
Dim Result As Int = Dialog.LoadLayout("dialog5").ShowDefault2("This is a title", "This is a custom content")


Part 6 Customizing the system and any other dialog

The DialogView.Options property has a wide range of configuration options that you can set in order to totally alter the look and feel of everything in a dialog. For example:

upload_2014-7-20_2-8-22.png
upload_2014-7-20_2-8-50.png


Configure the dialog title
B4X:
Dim TitleBackground As ColorDrawable : TitleBackground.Initialize(Colors.Gray, 0)
Dialog.Options.Title.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_BOLD_ITALIC), Colors.Blue, 25, Gravity.CENTER, TitleBackground, Colors.Red)
Configure the message content
B4X:
Dim MessageBackground As ColorDrawable : MessageBackground.Initialize(Colors.Magenta, 0)
Dialog.Options.Message.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_BOLD_ITALIC), Colors.Blue, 25, Gravity.CENTER, MessageBackground)
Configure the dialog buttons
B4X:
Dim ButtonBackground As StateListDrawable : ButtonBackground.Initialize
Dim ButtonBackgroundNormal As ColorDrawable : ButtonBackgroundNormal.Initialize(Colors.Yellow, 0)
Dim ButtonBackgroundPressed As ColorDrawable : ButtonBackgroundPressed.Initialize(Colors.Cyan, 0)
ButtonBackground.AddState(ButtonBackground.State_Pressed, ButtonBackgroundPressed)
ButtonBackground.AddCatchAllState(ButtonBackgroundNormal)

Dim ButtonStyle1, ButtonStyle2, ButtonStyle3 As DialogViewButtonStyle

ButtonStyle1.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_NORMAL), Colors.Blue, 14, Gravity.LEFT + Gravity.BOTTOM, ButtonBackground)
ButtonStyle2.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_BOLD), Colors.Red, 14, Gravity.LEFT + Gravity.Top, ButtonBackground)
ButtonStyle3.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_BOLD_ITALIC), Colors.Black, 24, Gravity.CENTER, ButtonBackground)

'Dialog.Options.Buttons.Default.Style = ButtonStyle1 <= apply the style to all buttons
Dialog.Options.Buttons.Positive.Style = ButtonStyle1
Dialog.Options.Buttons.Neutral.Style = ButtonStyle2
Dialog.Options.Buttons.Negative.Style = ButtonStyle3
Or set the style in one line
B4X:
Dialog.Options.Buttons.Default.Style.Set(Typeface.CreateNew(Typeface.SANS_SERIF, Typeface.STYLE_NORMAL), Colors.Blue, 14, Gravity.LEFT + Gravity.BOTTOM, ButtonBackground)


Part 7 Applying animations and gravity

Adding animation to any type of dialog is very simple.
  • Copy the AssetsXtra folder from the tutorial sample root folder to your project's root folder
  • Add this directive to your project attributes:
    B4X:
    #AdditionalRes: ..\AssetsXtra
  • Finally set the animation:
    B4X:
        Dialog.Options.Animation = "<animation_name>"
Currently the available animations are:
  • zoom
  • slide_from_top, slide_from_top_and_back
  • slide_from_bottom, slide_from_bottom_and_back,
  • slide_from_left,slide_from_left_and_back,
  • slide_from_right,slide_from_right_and_back

To set the gravity of the dialog:
B4X:
    Dialog.Options.Gravity = Gravity.RIGHT + Gravity.BOTTOM


Part 8 Customizing dialog dimensions

If you want to have specific dialog dimensions based on a display ratio or fixed values, just use the DialogView.Options.Dimensions property.

If you use the DialogView.Options.Dimensions.MODE_ANCHORS mode, the engine will respect any anchors that are set and will resize the views accordingly. Using the DialogView.Options.Dimensions.MODE_STRETCH mode, will stretch and reposition all views to fit the new dimensions nicely. Using the DialogView.Options.Dimensions.MODE_STRETCH_TEXT mode, is the same like MODE_STRETCH but it will try to adjust the textsize of affected buttons and textviews.

B4X:
Dialog.Options.Dimensions.Set(100%x, 100%y, Dialog.Options.Dimensions.MODE_ANCHORS)

--

That was all for now folks!

Tip: All dialog fields (title, message, button captions) accept HTML as an input that will be properly displayed.

There are a lot more things hidden. Play with it and you will discover them!

Enjoy! :D
 
Last edited:

Thraka

Member
Licensed User
That is what I was doing originally, but the thread there doesn't stop and moves on leaving the sub while the window is still open waiting for the user to click something.
 

Thraka

Member
Licensed User
That's what I had originally, but it didn't work. :( I think there may be an issue with nested dialogs...

Another issue, in the same class, I cannot get the dialog show event to fire either.
B4X:
Public Sub Initialize
    cities.Initialize 'map object
    layout = dialog.LoadLayout("setupweather")
End Sub

Sub dialog_Show
    'this never fires.
End Sub

'This is what I call from outside my wrapper to show the dialog
Public Sub Show
    lstLocations.CallBack = Me
 
    'Code does pause here waiting for a close, unlike the post above which doesn't pause and wait.
    layout.ShowOk("Edit Weather Locations", "Close")
End Sub
 

awoo060

Member
Licensed User
Stupendous work!

Is there anyway to have my initial panel use rounded corners? I have kind of found ways, but the black panel on which it sits becomes visible instead of being transparent...
 

little3399

Active Member
Licensed User
Hi, Periklis

I found a question about using dialogview in Activity_KeyPress routine ... it can not seem to work ! Ple help .

here was my code ... I want to show the PopMenu when I press the BACK TO HOME key

Sub Activity_KeyPress (KeyCode As Int) As Boolean

Dim DialogLayout As DialogViewLayout
DialogLayout = Dialog.LoadLayoutMultiple("CountMenu", "CountMenu", "CountMenu")
DialogLayout.ShowOk("Option","Close)


End Sub
 

henrywood

Active Member
Licensed User
I am trying to using DialogView.
My Dialog has a CustomView (as chosen in designer as it will not let me choose anything else)
Before showing this dialogview, I would like to replace this customView with a CustomListView.

How can this be done ?

My code thus far:

B4X:
Sub Globals
     Dim ShareToDialog As DialogView
End Sub


Sub Test
    ' Ask if add to another list
     ShareToDialog.Options.Animation = Main.DIALOGS_ANIMATION_DEFAULT
     ShareToDialog.Name = "share_to_list_dialog"
     Dim DialogLayout As DialogViewLayout
     DialogLayout = ShareToDialog.LoadLayout("share_to_list_dialog")
     Dim lv As CustomListView = DialogLayout.Views.Get("ListView1")
     Dim lbl1 As Label = DialogLayout.Views.Get("Labe11")
     Dim lbl2 As Label = DialogLayout.Views.Get("Label2")
     lbl1.Text = Strings.FE.Get("add_entry_shoppinglist") 
     lbl2.Text = Strings.FE.Get("add_entry_shoppinglist") 

     Dim lists As Map
     lists.Add("1", "Family List")
     lists.Add("2", "Friends List")

     For Each listID As String In lists.Keys
 
       lv.Add(addToCustomViewListShareToDialog(listID, lists.Get(listID), 50dip, listID)

     Next
     Dim Result As Int = DialogLayout.ShowYesNo(Main.APPLICATION_NAME_HUMAN & ": " & Strings.FE.Get("share_to_lists"), Strings.FE.Get("cancel"), Strings.FE.Get("done"))

 


   Else



   End If

End Sub

Sub addToCustomViewListShareToDialog(listId As String, listName As String)

   Dim p As Panel
   p.Initialize("")
   p.Color = Colors.Black
   Dim chkb As CheckBox
   chkb.Initialize("chkb")
   ckkb.Tag = listId
   p.AddView(chkb, 5dip, 2dip, 50dip, 50dip)
   Return p

End Sub

Sub share_to_list_dialog_Dismiss(DialogResult As Int) As Boolean

If DialogResult = DialogResponse.POSITIVE Then

    'Is this correct ?
    Dim cv As CustomListView = ShareToDialog.Views.Get("ListView1")

    For i=0 To cv.GetSize - 1

         Dim pnl As Panel
         pnl = cv.GetPanel(i)
         Dim chk As CheckBox
         chk = pnl.GetView(0)

         If chk.Checked = True Then

              ' TODO: Do our deeds


         End If

    Next

    clv1.Clear
    LoadFromDB

End if

End Sub
 
Last edited:

tagwato

Member
Licensed User
Wonderful addition to B4A, Periklis !

Please, could you check the behaviour of DialogView.Options.Dimensions.MODE_STRETCH_TEXT ?
It seems that it is not properly adjusting the text sizes of Labels and Listviews when we change the dialog dimensions.
 
Top