Android Tutorial Dialogs library 2017 - Custom dialogs and async methods

Status
Not open for further replies.
Dialogs v4 is an extension to @agraham original dialogs library. It requires B4A v7+.

SS-2017-06-01_16.00.52.png


The main changes are:

- New CustomLayoutDialog which makes it easier to develop custom dialogs.
- New ShowAsync methods for all dialogs except of CustomDialog and CustomDialog2.

The ShowAsync methods behave similar to Msgbox2Async and the other internal async dialogs: DoEvents deprecated and async dialogs (msgbox)

Example:
B4X:
Dim cd As ColorDialog
Dim sf As Object = cd.ShowAsync("Choose Color", "Yes", "Cancel", "No", Null, False)
Wait For (sf) Dialog_Result(Result As Int)
If Result = DialogResponse.POSITIVE Then
   Activity.Color = cd.RGB
End If
The async methods also include a Cancelable parameter that determines whether the dialog can be cancelled with the back key or a click outside of the dialog.
There are also other small improvements in the async methods implementation.
As explained in the tutorial about DoEvents, it is recommended to switch to the async methods.
Do note that ShowAsync + Wait For behavior is not identical to the modal dialogs behavior. When Wait For is called, the code returns to the calling sub (if there is one). If you want that the calling sub will wait for the sub that shows the async dialog: https://www.b4x.com/android/forum/threads/b4x-resumable-subs-sleep-wait-for.78601/page-2#post-499130


CustomLayoutDialog

CustomLayoutDialog replaces CustomDialog and CustomDialog2. As it is a non-modal dialog, it is more powerful. You can handle events while the dialog is visible and manage the dialog itself.
Note that CustomLayoutDialog is supported by Android 4+ (API 14+).

Showing the dialog is done in two steps:

1. Call ShowAsync and wait for Dialog_Ready event.
2. Load the layout to the panel (or create it programmatically).

The Dialog_Result event will be raised when the dialog is closed.

You can close the dialog programmatically by calling CloseDialog with the result:
B4X:
Dialog.CloseDialog (DialogResponse.POSITIVE)

You can explicitly set the dialog's size by calling SetSize. You need to call it after calling ShowAsync and before the Dialog_Ready event.
Note that the size set is the size of the dialog. The panel itself will be smaller. Use a layout with anchors to make sure that the layout adapts properly.

Dialog.GetButton will return one of the dialogs buttons. It can be used to disable or enable a button.
For example this code enables the OK button when all fields are non-empty.
B4X:
Sub DialogAge_ItemClick (Position As Int, Value As Object)
   CheckAllFieldsValid
End Sub

Sub DialogLastName_TextChanged (Old As String, New As String)
   CheckAllFieldsValid
End Sub

Sub DialogFirstName_TextChanged (Old As String, New As String)
   CheckAllFieldsValid
End Sub

Sub CheckAllFieldsValid
   Dim valid As Boolean = DialogAge.SelectedIndex > 0 And DialogFirstName.Text.Length > 0 And DialogLastName.Text.Length > 0
   DetailsDialog.GetButton(DialogResponse.POSITIVE).Enabled = valid
End Sub

The example is attached.

The library is available here: https://www.b4x.com/android/forum/threads/dialogs-library.6776

Edit: Cross platform custom layout dialog based on XUI: https://www.b4x.com/android/forum/threads/99756/#content
 

Attachments

  • DialogsExample.zip
    9.8 KB · Views: 4,320
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
And now for something that I wanted to do for a long time. A dialog that closes automatically after a few seconds:

SS-2017-06-01_16.37.34.png


The relevant code is:
B4X:
Sub btnEnterDetails_Click
   Dim dialog As CustomLayoutDialog
   Dim sf As Object = dialog.ShowAsync("", "Yes", "Cancel", "No", Null, False)
   Wait For (sf) Dialog_Ready (DialogPanel As Panel)
 
   DialogPanel.LoadLayout("DetailsDialog")
   Dim disable() As Boolean = Array As Boolean(False)
   AutoClose(dialog, lblSeconds, disable)
   Wait For (sf) Dialog_Result (Result As Int)
 
   disable(0) = True 'disable the AutoClose timer
   If Result = DialogResponse.POSITIVE Then
     '...
   End If
End Sub

Sub AutoClose (TimedDialog As CustomLayoutDialog, UpdateLabel As Label, Disable() As Boolean)
   UpdateLabel.Text = 9 '9 seconds
   Do While UpdateLabel.Text > 0
     Sleep(1000)
     'the timer was disabled
     If Disable(0) = True Then Return
     UpdateLabel.Text = NumberFormat(UpdateLabel.Text - 1, 0, 0)
   Loop
   TimedDialog.CloseDialog(DialogResponse.CANCEL)
End Sub

The trick in this code is that the Disable variable is an array. This allows us to change the value that the AutoClose sub will see and disable the "timer" if the user already clicked on one of the buttons.
Note that this AutoClose sub can serve multiple dialogs and a similar solution can be used in other cases where you want to wait for an event but also set a timeout.
 

Attachments

  • TimedDialogsExample.zip
    13.1 KB · Views: 3,000
Last edited:

Jaames

Active Member
Licensed User
Longtime User
Hi,

First example from the OP on the device 720x1280 , dialog is showing incorrectly :
Screenshot_2017-06-03-13-53-55.png

if I change line :
B4X:
Dim sf As Object = DetailsDialog.ShowAsync("Enter details", "Ok", "Cancel", "", LoadBitmap(File.DirAssets, "form.png"), True)

to:

B4X:
Dim sf As Object = DetailsDialog.ShowAsync("Enter details", "Ok", "Cancel", "", LoadBitmapSample(File.DirAssets, "form.png",20dip,20dip), True)

then it is ok.

Screenshot_2017-06-03-13-58-54.png
 

Erel

B4X founder
Staff member
Licensed User
Longtime User

Erel

B4X founder
Staff member
Licensed User
Longtime User
Good question. The array allows us to pass the boolean value by reference. If it was a regular boolean variable then it wouldn't have been possible to later change it:
B4X:
Sub DoSomething
   Dim disable As Boolean = False
   AutoClose(disable) 'this is exactly like passing AutoClose(False)
   disable = True 'the local disable variable is assigned a a new value. No relation to the local Disable variable of AutoClose.
End Sub

Sub AutoClose(Disable As Boolean)
   Sleep(5000)
   Log(Disable) 'always false
End Sub
 

Victoire

New Member
Licensed User
Longtime User
I've resized the image to 32x32 in the example. Note that if you want to resize an image to a specific size then it is better to use CreateScaledBitmap: https://www.b4x.com/android/forum/threads/javaobject-library.34486/#content

While further testing it, it appears that the custom dialogs will not work properly on Android 2.x. The minimum version should be Android 4.
(Android 2.x is mostly irrelevant now: https://developer.android.com/about/dashboards/index.html)
 

Dey

Active Member
Licensed User
Longtime User
And now for something that I wanted to do for a long time. A dialog that closes automatically after a few seconds:

SS-2017-06-01_16.37.34.png


The relevant code is:
B4X:
Sub btnEnterDetails_Click
   Dim dialog As CustomLayoutDialog
   Dim sf As Object = dialog.ShowAsync("", "Yes", "Cancel", "No", Null, False)
   Wait For (sf) Dialog_Ready (DialogPanel As Panel)

   DialogPanel.LoadLayout("DetailsDialog")
   Dim disable() As Boolean = Array As Boolean(False)
   AutoClose(dialog, lblSeconds, disable)
   Wait For (sf) Dialog_Result (Result As Int)

   disable(0) = True 'disable the AutoClose timer
   If Result = DialogResponse.POSITIVE Then
     '...
   End If
End Sub

Sub AutoClose (TimedDialog As CustomLayoutDialog, UpdateLabel As Label, Disable() As Boolean)
   UpdateLabel.Text = 9 '9 seconds
   Do While UpdateLabel.Text > 0
     Sleep(1000)
     'the timer was disabled
     If Disable(0) = True Then Return
     UpdateLabel.Text = NumberFormat(UpdateLabel.Text - 1, 0, 0)
   Loop
   TimedDialog.CloseDialog(DialogResponse.CANCEL)
End Sub

The trick in this code is that the Disable variable is an array. This allows us to change the value that the AutoClose sub will see and disable the "timer" if the user already clicked on one of the buttons.
Note that this AutoClose sub can serve multiple dialogs and a similar solution can be used in other cases where you want to wait for an event but also set a timeout.

Hello
How can i close a Sub (data processing end) Dialog,
Example after I finished data processing

Thank you as always for what you do
 

Martin Fdez

Member
Licensed User
Longtime User
Hello

How can I hide the keyboard after in Sub CheckAllFieldsValid Valid=true?
Keyboard remains open after click ok

Thanks

This doesn't work

B4X:
Sub CheckAllFieldsValid
    Dim valid As Boolean = DialogAge.SelectedIndex > 0 And EditText2.text.Length > 0
    DetailsDialog.GetButton(DialogResponse.POSITIVE).Enabled = valid
    If valid= True Then
        Dim Phone1 As Phone
        Phone1.HideKeyboard(Activity)
    End If
End Sub
 

Martin Fdez

Member
Licensed User
Longtime User
This is not the correct place to hide it as it will hide it while the user is typing.

You should instead hide it after the user clicks on Ok:
B4X:
Wait For (sf) Dialog_Result(res As Int)
Sleep(50)
Dim im As IME
im.Initialize("")
im.HideKeyboard
Thanks Erel

It works!
 

Roberto P.

Well-Known Member
Licensed User
Longtime User
Hello to all
I can not see a scrollview to let you see a dialogue with many fields I use to handle filters.

B4X:
Dim sf As Object = DetailsDialog.ShowAsync("Filtri Anagrafiche", "OK", "Annulla", "", LoadBitmap(File.DirAssets, "img/form_trasparent.png"), True)
  
    DetailsDialog.SetSize(100%x, 100%y)
      
    Wait For (sf) Dialog_Ready(pnl As Panel)
      
    'pnl.LoadLayout("frmFiltriAnagrafiche")
    pnl.AddView(msvFiltri, 0dip,0dip, 90%x, aMaxHeight )
    msvFiltri.Panel.LoadLayout("frmFiltriAnagrafiche")
  
  
    Wait For (sf) Dialog_Result(res As Int)

Does not scroll vertically ?!

Where am I wrong?
thanks
 
Status
Not open for further replies.
Top