Android Example Creating a cross-platform "dialog" class with input validation

I'm currently developing an App that'll be released for Android and IOS. It presents "files" to the user, allows them to select a file and then presents the content for editing, and finally allows them to run the content.

As part of the development process, I've needed to request information from the user - a file (to open, to save) or folder (to move a file into), a text or numeric value (while adding new content or editing content), a date or time value etc. I've also needed to pop up messages to the user - short "it's done" messages and more complex "here's the situation ... proceed" Yes/No/Cancel messages.

As I've worked through these needs, I've found different/alternative ways to request the input, improving each time. My latest solution has been built into PropertyEditor, a cross-platform solution for presenting object properties or database fields to a user so that they can edit existing or add new records.

But I'm still not satisfied. I want to be able to:
  1. Have a single cross-platform solution for displaying messages and requesting input;
  2. Validate user input so that the user sees when something is invalid and can correct it at point of entry;
  3. Leverage the current standard solution for Dialogs - the CustomDialogLayout available in the latest B4A/B4i releases; and,
  4. Develop the class incrementally so that it has immediate use and each iteration works on both platforms.
My intent then is a class that satisfies all of the above requirements ... and I thought it would be fun to post progress (and incremental updates) as an example of developing something useful that works for both Android and IOS.

I'll update this main post with the latest build, and I'll add posts detailing what's changed in the build, key decisions I had to make and so on, so that the individual posts chart the development with the latest result available here, in the first post.

Note that this post (and the individual posts) will focus on the development from an Android perspective. There is another thread in the IOS forums that focuses on the development from an IOS perspective:

Feel free to follow along or to comment if you have a suggestion or a question - this isn't meant to be an example of perfect development (is there such a thing?), rather it's meant to be an example of how I, personally, approached the above requirements, resulting in a class that all of us might choose to use in an App development.

Planned "sprints"/iterations

As a way of getting my thoughts in order (and a preview of where I'm headed), I thought I'd list out the plans. Comments and feedback welcomed!
  1. DONE. Basic structure. Toast DialogType. CharSequence (CS)/AttributedString (AS) integration.
  2. DONE. Message DialogType. Dialog layout. Callback/_Result event. CS/AS Message and Buttons.
  3. Add Icon/Color/Style properties.
  4. Custom DialogType. Receive a panel containing controls where calling routine handles control events and can set dialog to indicate valid/invalid. Implemented first to be able to leverage when implementing other types.
  5. Number DialogType (subtypes Integer, Decimal). Value check (>,>= etc.) Range check (In, NotIn).
  6. Text DialogType (subtypes Singleline, Multiline). Length check (At least, At most) Substring check (In, NotIn) RegExp check (contains, matches etc.)
  7. Choice DialogType (subtypes Single, Multi). Able to provide initial choice(s) and receive choice(s) back.
  8. FileFolder DialogType (subtypes File, Folder). Able to browse entire hierarchy or 1 level at a time.
Further possibilities:
  1. DateTime DialogType (subtypes Date, Time, DateTime). Extend Value and Range checks.


  • ValiDialogs (0.02).zip
    15.7 KB · Views: 275
Last edited:


Active Member
Licensed User
New development, initial decisions. I already decided to use the CustomLayoutDialog object available on both platforms. And I need to be able to display messages and request/receive user input, which should be possible using a custom layout. But my app also displays simple "it's done" messages. Under Android these are possible with ToastMessageShow - could I build that into the class?

This first iteration will also set the foundation for the rest of the development, so I spent some time working through potential properties, methods and events so that I had a reasonable chance of being able to extend the class for more complex additions later on.

I also wanted to be able to leverage test code across Android and IOS ... which meant removing it from the Main module and putting it into a Test module. I tried using a regular code module, but code modules don't work well with events and I needed to be able to handle a Dialog_Result message, so I created a Test class.

Finally, to the first iteration. I decided to use the Initialize method to set the type of dialog that would be created along with a Message that the dialog might use - most of the later dialog types could use a message either to display status to the user, or as a prompt for the kind of input needed. Researching a bit, I found the CSBuilder thread and confirmed that CharSequences can be used with ToastMessageShow.

This first iteration implements the Toast dialog type - not really a dialog type, but a convenient way for me to wrap all Dialog user interactions into a single class. It also allowed me to test out chaining method calls - by returning Me from a method, I'm able to write single statements that build on each other:
d.Initialize(d.DIALOGTYPE_TOAST, "Hello").ShowToast(False) 'Initialize and show in one statement
d.andMessage("Hello there!").ShowToast(False) 'Simple message
d.andMessage(cs.Initialize.Append("Hello ").Bold.Append("it's me").Pop.Append(" again ").Typeface(Typeface.FONTAWESOME).Append(Chr(0xF087)).PopAll).ShowToast(False) 'CSBuilder message, built in one statement

I then ported the code to IOS


  • ValiDialogs (0.01).zip
    7.8 KB · Views: 234
Last edited:


Active Member
Licensed User
Iteration 2 added the "Message" dialog type along with a bunch of properties corresponding to the different parts of a dialog - Title, PositiveText, NegativeText, CancelText - and the standard developer Tag property. I decided to defer implementation of an Icon property until a later stage, as I wanted to introduce a Style property for the Android version that was similar to the IOS Style property, which would take a little more work than I wanted to put into this iteration.

I'd already decided to use the CustomLayoutDialog object to show the dialogs, leveraging the standard dialog elements and leaving me to focus on the content of the custom panel in the centre of the dialog. Unfortunately, the Android and IOS objects are implemented differently ...
  • Android has a Dialog_Ready event for the developer to populate a panel, while IOS accepts a panel on the Initialize event;
  • Android's dialog sizing is explicit with a .SetSize method, while IOS takes dimensions from the panel passed during initialize
... which lead to quite a complex block of layout/positioning code in my ShowAsync method. In order to get the sizing correct, I leveraged a SizeToFit code module from an earlier project. And then to avoid problems with very long messages - should they truncate? ellipsize? - I opted for neither and wrapped the multi-line Message label in a ScrollView.

In line with allowing CharSequence/AttributedText objects in the Message itself, I also added code to support their use on the buttons - both CustomLayoutDialog objects support a GetButton method, and I wrapped setting the button text in it's own utility routine to hide the IOS dependency on NativeObject.

I wanted this class to behave similarly to the CustomLayoutDialog class when returning the result of the dialog (which button was pressed), so this iteration also introduced Initialize parameters to support a callback event with the ability to adjust the callback event name (the same as most other callback implementations).

Finally, I discovered that the previous iteration's implementation of DialogType constants wasn't going to work, as I was wanting to use the constants in the Initialize sub, but at the point of object initialization, the constants themselves had not been initialized. In OO terms, I needed "class constants" but B4A/B4i only supported "instance constants" - the solution was to move the constants into the Process_Globals sub of a code module.

I then ported to IOS, as before

This iteration took a little longer than expected, mostly due to the amount of time I spent figuring out how to code the layout logic. But now it's done, I think I've built a solid foundation for the introduction of input views in the next iterations.


  • ValiDialogs (0.02).zip
    15.7 KB · Views: 257
Last edited: