I have a string like this 08:12:01,868 -> hour:minute:second,millisecond
now I need to edit this, I must give an option to edit first two character skip one for : then allow edit next two character again skip : and so on.
Currently I'm achieving this with lot of logic behind. I have four edit text and I'm splitting the string, then loading values in 4 edit texts and retrieving it. After joining all the edited sub strings I'm saving the value in DB.
Is there any other better way to achieve this.
I mean I'll load the string in only one edit text, Then I should be able to lock specific characters like lockFromEditChar(":",",") and remaining values can be edited with default value zero if they clear all the character.
Is it possible ? or any other best alternatives ?
The technique is called Masking. Create this class MaskWatcher like this
import android.text.Editable;
import android.text.TextWatcher;
public class MaskWatcher implements TextWatcher {
private boolean isRunning = false;
private boolean isDeleting = false;
private final String mask;
public MaskWatcher(String mask) {
this.mask = mask;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
isDeleting = count > after;
}
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable editable) {
if (isRunning || isDeleting) {
return;
}
isRunning = true;
int editableLength = editable.length();
if (editableLength < mask.length()) {
if (mask.charAt(editableLength) != '#') {
editable.append(mask.charAt(editableLength));
} else if (mask.charAt(editableLength-1) != '#') {
editable.insert(editableLength-1, mask, editableLength-1, editableLength);
}
}
isRunning = false;
}
}
and than use your edittext like this
editText.addTextChangedListener(MaskWatcher("##:##:##,###"));
If you have the cursor blocked in the last position and longClick disabled(copy paste):
Note that this example works only for strings, no spans
Create a TextWatcher and auto add : and , when you detect a new character added and the new size is 2,4(for ':'),6(for ',').
Also detect when you delete a character and the current size is 2,4,6, you have to delete the character before ';' or ',' as well.
class Watcher(private val textView:TextView) : TextWatcher {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val text = s?.toString()?:""
val isDelete = textView.length > text.size
if(isDelete) {
//you can change this to an if to check for 2,4,6 and use take(size-1)
newString = when(text.size) {
2->text.take(1)
4->text.take(3)
6->text.take(5)
}
if(newString!=null) {
textView.text = newString
}
} else {
newString = when(text.size) {
2,4 -> text + ":"
6 -> text + ","
}
if(newString!=null) {
textView.text = newString
}
}
}
}
Related
As the title says, I set up an EditText in my activity and want to limit the input to only numbers. However, it doesn't matter if it is a decimal number or integer. I do require the number of digits is limited at 3. For example, the input of '123', '1.23', '12.3' are all legit input.
'1234', '123.', '.123' are all illegal input.
I have tried to set up
android:inputType = "numberDecimal"
in the xml file.
And set the max length to 4.
edit:
I also tried following code:
InputFilter filter = new InputFilter() {
//^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$
//^\-?(\d{0,3}|\d{0,2}\.\d{0,1}|\d{0,1}\.\d{0,2})$
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (end > start) {
// adding: filter
// build the resulting text
String destinationString = dest.toString();
String resultingTxt = destinationString.substring(0, dstart) + source.subSequence(start, end) + destinationString.substring(dend);
// return null to accept the input or empty to reject it
return resultingTxt.matches("^\\-?(\\d{0,3}|\\d{0,2}\\.\\d{0,1}|\\d{0,1}\\.\\d{0,2})$") ? null : "";
}
return null;
}
};
I did modified the regex from the sample code mentioned by #Suman Dash.
My understanding of the regex
^\-?(\d{0,3}|\d{0,2}\.\d{0,1}|\d{0,1}\.\d{0,2})$
is to allow certain pattern of number input such as #.##, ##.# and ###.
When I test the code, the pattern #.## and ##.# are working fine, but the pattern ### also allow input like ".##", for example, ".88" as legit input. And it treats the decimal point as a legit number, so I can only input ".88", not ".123". Anyway, I don't want any number starts with the decimal point.
How can I eliminate that?
What's the best way to achieve this goal? Thanks!
InputFilter filter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
for (int i = start; i < end; ++i)
{
if (!Pattern.compile("[1234567890\.]*").matcher(String.valueOf(source.charAt(i))).matches())
{
return "";
}
}
return null;
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText ntxt =(EditText)findViewById(R.id.numberEditTextbox) ;
ntxt.setFilters(new InputFilter[]{filter,new InputFilter.LengthFilter(4)});
}
This code may help you.
Do it exists a tool in Java to do this type of task below?
I got this hard typed String: {[1;3] || [7;9;10-13]}
The curly brackets {} means that is required
The square brackets [] means a group that is required
The double pipe || means a "OR"
Reading the string above, we get this:
It's required that SOME STRING have 1 AND 3 OR 7 AND 9 AND 10, 11, 12 AND 13
If true, it will pass. If false, will not pass.
I'm trying to do this in hard coding, but I'm felling that there is an easier or a RIGHT WAY to this type of validation.
Which type of content I must study to learn more about this?
I started with this code, but I'm felling that is not right:
//Gets the string
String requiredGroups = "{[1;3]||[7;9;10-13]}";
//Gets the groups that an Object belongs to
//It will return something like 5,7,9,10,11,12
List<Integer> groupsThatAnObjectIs = object.getListOfGroups();
//Validate if the Object is in the required groups
if ( DoTheObjectIsInRequiredGroups( groupsThatAnObjectIs, requiredGroups ) ) {
//Do something
}
I'm trying to use this iterator to get the required values from the requiredGroups variable
//Used for values like {[1;3]||[9;10;11-15]} and returns the required values
public static void IterateRequiredValues(String values, List<String> requiredItems) {
values = values.trim();
if( !values.equals("") && values.length() > 0 ) {
values = values.replace("{", "");
values = values.replace("}", "");
String arrayRequiredItems[];
if ( values.contains("||") ) {
arrayRequiredItems = values.split("||");
}
//NOTE: it's not done yet
}
}
So the rules are not really clear to me.
For example, are you only focussing on || or do you also have &&?
If I look at your example, I can derive from it that the && and operators are implicit in the ;.
None the less, I have made a code example (without much regex) that checks your rules.
First you need to begin with the || operator.
Put all the different OR statements into a String block.
Next you will need to check each element in the String block and check if the input value contains all block values.
If so then it must be true that your input string contains all the rules set by you.
If your rule consists of a range, you must first fully fill the range block
and then do the same with the range block as you would with the normal rule value.
Complete code example below.
package nl.stackoverflow.www.so;
import java.util.ArrayList;
import java.util.List;
public class App
{
private String rules = "{[1;3] || [7;9;10-13] || [34;32]}";
public static void main( String[] args )
{
new App();
}
public App() {
String[] values = {"11 12", "10 11 12 13", "1 2 3", "1 3", "32 23", "23 32 53 34"};
// Iterate over each value in String array
for (String value : values) {
if (isWithinRules(value)) {
System.out.println("Success: " + value);
}
}
}
private boolean isWithinRules(String inputValue) {
boolean result = false;
// || is a special char, so you need to escape it with \. and since \ is also a special char
// You need to escape the \ with another \ so \\| is valid for one | (pipe)
String[] orRules = rules.split("\\|\\|");
// Iterate over each or rules
for (String orRule : orRules) {
// Remove [] and {} from rules
orRule = orRule.replace("[", "");
orRule = orRule.replace("]", "");
orRule = orRule.replace("{", "");
orRule = orRule.replace("}", "");
orRule.trim();
// Split all and rules of or rule
String[] andRules = orRule.split(";");
boolean andRulesApply = true;
// Iterate over all and rules
for (String andRule : andRules) {
andRule = andRule.trim();
// check if andRule is range
if (andRule.contains("-")) {
String[] andRulesRange = andRule.split("-");
int beginRangeAndRule = Integer.parseInt(andRulesRange[0]);
int endRangeAndRule = Integer.parseInt(andRulesRange[1]);
List<String> andRangeRules = new ArrayList<String>();
// Add all values to another rule array
while (beginRangeAndRule < endRangeAndRule) {
andRangeRules.add(Integer.toString(beginRangeAndRule));
beginRangeAndRule++;
}
for (String andRangeRule : andRangeRules) {
// Check if andRule does not contain in String inputValue
if (!valueContainsRule(inputValue, andRangeRule)) {
andRulesApply = false;
break;
}
}
} else {
// Check if andRule does not contain in String inputValue
if (!valueContainsRule(inputValue, andRule)) {
andRulesApply = false;
break;
}
}
}
// If andRules apply, break and set bool to true because string contains all andRules
if (andRulesApply) {
result = true;
break;
}
}
return result;
}
private boolean valueContainsRule(String val, String rule) {
boolean result = true;
// Check if andRule does not contain in String inputValue
if (!val.contains(rule)) {
result = false;
}
return result;
}
}
I have 3 languages on my keyboard in android device and I want to show only English language letters and numbers when starting to edit text inside EditText like username field , I tried to use this line in xml file for Edittext but without any result.
android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
the best way is to use inputfilter and set it to your editText you can see a workaround to do that here :
How do I use InputFilter to limit characters in an EditText in Android?
also i found a code snippet to this like below:
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend)
{
for (int i = start; i < end; i++) {
if (!isEnglishOrHebrew(source.charAt(i))) {
return "";
}
}
return null;
}
private boolean isEnglishOrHebrew(char c) {
. . .
}
};
edit.setFilters(new InputFilter[]{filter});
I want an editText that only allows text input from A to z, no numbers or other characters. I've found out I have to use InputFilter but I don't understand how this code works.
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!Character.isLetterOrDigit(source.charAt(i))) {
return "";
}
}
return null;
}
};
edit.setFilters(new InputFilter[]{filter});
The code you posted adds a custom filter to the EditText field. It checks to see if the character entered is not a number or digit and then, if so, returns an empty string "". That code is here:
if (!Character.isLetterOrDigit(source.charAt(i))) {
return "";
}
For your needs, you want to change the code slightly to check if the character is NOT a letter. So, just change the call to the static Character object to use the isLetter() method. That will look like this:
if (!Character.isLetter(source.charAt(i))) {
return "";
}
Now, anything that is not a letter will return an empty string.
Haven't actually done it, but check Androids NumberKeyListener. You can find the source code for it here:
http://www.java2s.com/Open-Source/Android/android-core/platform-frameworks-base/android/text/method/NumberKeyListener.java.htm
it does exactly the opposite of what you need, but that should be a good enough starting point.
I have following code that needs something smart to deal with typed in chars and detection:
private final MultiWordSuggestOracle mySuggestions = new MultiWordSuggestOracle();
private final Set<String> mySuggestionsData = new HashSet<String>();
#UiHandler("suggestBox")
public void onKeyPress(KeyDownEvent event) {
if (Character.isLetterOrDigit(event.getCharCode())) {
char[] text = suggestBox.getText().trim().toCharArray();
if (text.length != 1) return;
for (char ch : text) {
if (!Character.isLetterOrDigit(ch)) {
return;
}
}
//load data from server into mySuggestionsData
}
}
The question has 3 parts:
How do you test pressed key against alphanumeric chars. Keep in mind this is GWT so I would rather not use regex ( but if there is no other option ...).
What is the best way to detect the length of text typed into the SuggestBox?
Is KeyDownEven the best choise? And why is it triggered twice when any key is pressed?
Instead of handling events, you should make your own SuggestOracle (possible wrapping a MultiSuggestOracle used as an internal cache) and check the query's length and "pattern" there to decide whether to call the server or not (and then give an empty list of suggestions as the response, or maybe a single suggestion being the exact query).
As a side note, I don't understand why you don't want to use a regex; either using the java.lang.String methods taking a regex as a String, or the com.google.gwt.regexp.shared.RegExp class.
1. I'd use KeyPressHandler instead of Up/Down handler.
As far as I understand, you are more interested to get what the user has typed but not the key that was actually pressed on the keyboard. Also, you can use Character.isDigit(c) and Character.isLetter(c) since KeyPressEvent.getCharCode() will return char (c).
2. Likely you want to check text length at some point (e.g. when user presses Enter), then
// handler block
if (c == KeyCodes.KEY_ENTER) {
int length = ((SuggestBox) event.getSource()).getText().length();
// take an action depending on length
}
// handler block continued
should fit.
3. See [1] and perhaps it's browser specific.
Edit: [1],[2] and [3] combined (using KeyUpHandler):
private static final int THREASHOLD = 2;
private String phrase = "";
...
searchBox.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent event) {
String text = ((SuggestBox) event.getSource()).getText();
if (!phrase.equals(text)) {
if (text.length() >= THREASHOLD) {
boolean alphanum = true;
for (int i = 0; i < THREASHOLD; i++) {
char c = text.charAt(i);
if (!Character.isDigit(c) && !Character.isLetter(c)) {
alphanum = false;
break;
}
}
if (alphanum) {
//RPC (won't be called twice)
}
}
phrase = text;
}
}
});