B4A Library [Lib] Masked EditText

This EditText fixes a few issues with the standard EditText and adds new features:
- Filter: you can transform any input before the text is changed;
- Mask: you can define an input mask;
- Read-only: you can protect your EditText against changes;
- Floating hint: the hint moves above the EditText when the user starts typing;
- Error popup: you can display a message in a popup to warn the user:

met.png


v1.1:
- It is now a custom view supported by the designer
- I fixed a bug when Format was set after WithSuggestions

v1.2:
- I moved the CompactText function from the example to the library;
- I fixed a bug with SelectionStart;
- I fixed a bug when InputType is set to NONE.

v1.3:
- WithSuggestions works now as expected on Samsung devices.
- Suggestions are automatically disabled in password mode.

v1.4:
- I added the EnableFloatingHint function;
- I added the custom view properties for the designer.

v1.41:
- I improved the animation of the floating hint;
- I fixed an issue with the hint color.

v1.42:
- I fixed a bug with the floating hint when the EditText is moved.

v1.5:
- I rewrote the code of floating hints to make it more robust and fix a few issues;
- I added the SetFromHTML function.

v1.51:
- A few properties set in the designer were not taken into account.

v1.52:
- There was an issue with the background drawable as it was set by default by the designer to a white colored drawable. The support of this property in the designer was removed to keep the original default background.

This library does not work with Android versions < 2.
 

Attachments

  • MaskedEditText v1.52.zip
    24.9 KB · Views: 2,514
  • Java source - MaskedEditText.zip
    9.2 KB · Views: 916
  • MaskedEditText v1.53.zip
    25.2 KB · Views: 1,505
Last edited:

Dave O

Well-Known Member
Licensed User
Longtime User
Fixed. Sorry for the inconvenience.

Confirmed, it's working better now. I'll check again to see if the text not dimming is reproducible in a simple example, but that's also an easy one to work around in any case.

Thanks for the quick update!
 

Widget

Well-Known Member
Licensed User
Longtime User
I went through your demo and it looks like a library that will be used a lot.

I'd like to offer a couple of suggestions that may make it even better. Now I'm new to B4A so I don't know how much of this is possible or not.

1) Is it possible to add a new property called "Literals"? This is a String property whose value contains special characters like "/:" or "@" that when the user types them in, control moves immediately to the field's location following the literal that was just pressed?

Example:
ET1.Format = "Date/time: ##/##/#### ##:##"
ET1.Literals = "/:"

When the user types in "1/", input then moves to the first "#" after the next "/" so we get "1/##/#### ##:##" . If the user then presses "5/" we get "1/5/#### ##:##" etc. So pressing any of the characters in the Literals property will jump to the next input character after the literal that was just pressed. Does this make sense?

The keyboard would of course have to display a button for each of the Literals "/" and ":" for this date field. If we were entering an email address and Literals="@" then an "@" button would be on the keyboard.

If the Literals property could be implemented, I think it will make data entry much faster.

2) When entering data for a MultiLine edit box, can you put a Next View button ">" on the keyboard so the user can use this key to leave the MultiLine edit view and move to the next view?

TIA
 

Informatix

Expert
Licensed User
Longtime User
I went through your demo and it looks like a library that will be used a lot.

I'd like to offer a couple of suggestions that may make it even better. Now I'm new to B4A so I don't know how much of this is possible or not.

1) Is it possible to add a new property called "Literals"? This is a String property whose value contains special characters like "/:" or "@" that when the user types them in, control moves immediately to the field's location following the literal that was just pressed?

Example:
ET1.Format = "Date/time: ##/##/#### ##:##"
ET1.Literals = "/:"

When the user types in "1/", input then moves to the first "#" after the next "/" so we get "1/##/#### ##:##" . If the user then presses "5/" we get "1/5/#### ##:##" etc. So pressing any of the characters in the Literals property will jump to the next input character after the literal that was just pressed. Does this make sense?

The keyboard would of course have to display a button for each of the Literals "/" and ":" for this date field. If we were entering an email address and Literals="@" then an "@" button would be on the keyboard.

If the Literals property could be implemented, I think it will make data entry much faster.

2) When entering data for a MultiLine edit box, can you put a Next View button ">" on the keyboard so the user can use this key to leave the MultiLine edit view and move to the next view?

TIA
The virtual keyboard is not something that I created. It's the stock IME of Android. So I can't create buttons or replace the existing ones (except in the case of the Next button that I can force to display Done).
In your first suggestion, "1/5/####" is not possible as # is not an optional char.
 

Dave O

Well-Known Member
Licensed User
Longtime User
Minor wish: Add HintColor as a property in the Designer.

I couldn't figure out why my hints were not appearing, until it occurred to me to try changing the color in code. That worked, but would be easier in the Designer if that's possible.
 

ykucuk

Well-Known Member
Licensed User
Longtime User
Hello,

I set mask and it works great but i have a problem with it.

I use mask for phone numbers. it works well if user click on edit text and move cursor to begin otherwise its starts point where user click on edit text.

is there way for start to write begin of edit text each time user click on it

Thank you

B4X:
edtMail.Format = "+1"  &" ### ### ####"
 

Informatix

Expert
Licensed User
Longtime User
Hello,

I set mask and it works great but i have a problem with it.

I use mask for phone numbers. it works well if user click on edit text and move cursor to begin otherwise its starts point where user click on edit text.

is there way for start to write begin of edit text each time user click on it

Thank you

B4X:
edtMail.Format = "+1"  &" ### ### ####"
Interesting question. Unfortunately, I have no solution to offer for now.
 

mojako

Member
Licensed User
INPUT_TYPE_TEXT_WITH_CAPS not work for me. when I type text, it still appears to be lowercase.
 

mojako

Member
Licensed User
Including the first letters? INPUT_TYPE_TEXT_WITH_CAPS is supposed to convert only the first letter of each word. If you want to convert everything to caps, use a filter like in the demo.
thanks ... it works like sample.. nice library..
 

peacemaker

Expert
Licensed User
Longtime User
Please, any example of using "_Filter" event. Or more detaled description.
 

Informatix

Expert
Licensed User
Longtime User
Please, any example of using "_Filter" event. Or more detaled description.
You have an example provided with the library. From the example:
B4X:
Sub ET2_Filter(NewText As String, Position As Int, Replace As Boolean) As String
   'All characters are converted to lower case
   Log("Incoming=" & NewText & " (" & NewText.Length & ") Position=" & Position & " Replace=" & Replace)
   Return NewText.ToLowerCase
End Sub
"Filter" allows to replace the modified text whenever a change occurs (typed key, pasted text) before the change is displayed to the user (so you can fully control the result of any input).
 

biometrics

Active Member
Licensed User
Longtime User
When I copy and paste masked edit fields from one layout to another and run the code and open that layout with Activity.LoadLayout I get this error. Then no matter if I recreate the masked edit field it keeps doing this. The masked edit fields works fine in the original layout.

Any help will be appreciated! I'm now stuck with project as this won't run.

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Error occurred on line: 255 (Main)
java.lang.RuntimeException: java.lang.RuntimeException: Field txtphonenumber1 was declared with the wrong type.
   at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:170)
   at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
   at java.lang.reflect.Method.invoke(Native Method)
   at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:735)
   at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:360)
   at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:260)
   at java.lang.reflect.Method.invoke(Native Method)
   at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
   at anywheresoftware.b4a.objects.Timer$TickTack.run(Timer.java:105)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:234)
   at android.app.ActivityThread.main(ActivityThread.java:5526)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.RuntimeException: Field txtphonenumber1 was declared with the wrong type.
   at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayoutHelper(LayoutBuilder.java:431)
   at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayoutHelper(LayoutBuilder.java:454)
   at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayoutHelper(LayoutBuilder.java:454)
   at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:148)
   ... 15 more
 

biometrics

Active Member
Licensed User
Longtime User
Seems some of them were still Dim'ed as EditText in Globals. That's a nice few hours wasted. /slaps head
 

Guenter Becker

Active Member
Licensed User
Hello Informatix,

your lib is great. I tried it to use it as input field.
If I set the mask for example as ##.##.#### and I did not enter anything and then retriving the value like strX = maskededittext.text strX should be Null or "" because there was no user input. But I got strX = __.__.____ as return and this is not correct!:( Is there a way to avoid this?

A solution is really important because yet I am not able to test if the user did an input or not. This is needed not to store the value of maskededittext fields with no user input in a database. Doing it now the returned value of __.__.____ is stored and this is not what I want neither is it correct.

Thank you for your answer and best regards from Germany
Guenter:D
 

Informatix

Expert
Licensed User
Longtime User
Hello Informatix,

your lib is great. I tried it to use it as input field.
If I set the mask for example as ##.##.#### and I did not enter anything and then retriving the value like strX = maskededittext.text strX should be Null or "" because there was no user input. But I got strX = __.__.____ as return and this is not correct!:( Is there a way to avoid this?

A solution is really important because yet I am not able to test if the user did an input or not. This is needed not to store the value of maskededittext fields with no user input in a database. Doing it now the returned value of __.__.____ is stored and this is not what I want neither is it correct.

Thank you for your answer and best regards from Germany
Guenter:D
Did you look at the demo ? See RawText.
 

Guenter Becker

Active Member
Licensed User
Thank you Informatix. I am using now an enhanced version of RawText. Because if I check with your Rawtext and have no Input but a mask like ##.##.#### string "0" is returned? I debuged the function step by step and it strips off the mask correct but I could not recognize where the "0" is comming from. My workaround is as followes:

Sub RawText(ED As MaskedEditText,isDate As Boolean) As String
'Returns a copy of the text without the mask characters
Dim Raw As StringBuilder
Raw.Initialize
Dim mskCar, txtCar As Char
Dim Text As String = ED.text
Dim Mask As String = ED.Format
If Mask.Length = 0 Or Mask = "" Then
Return ED.Text
Else
For i = 0 To Mask.Length - 1
If i >= Text.Length Then Exit
mskCar = Mask.CharAt(i)
If mskCar = "#" Or mskCar = "A" Or mskCar = "H" Or mskCar = "L" Or mskCar = "?" Then
txtCar = Text.CharAt(i)
If txtCar <> ED.Placeholder Then
Raw.Append(txtCar)
End If
End If
Next
Dim res As String = Raw.ToString
If isDate And res = "0" Then res =""
Return res
End If
End Sub

This works and does what it should for me and I am able to use the MaskedEditText as Inputfield for a Date.

Thank you for the quick asstistance
best Regards from Germany
Guenter
 
Top