Is there a way I can group characters from a EditText in blocks while the user is typing? Exemple: 1234
4567
7890
and so on?
I have an edit text that support numeric numbers and has 16 char length and I would like to group them in separated blocks for a better visibility.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.edittext);
mEditText.addTextChangedListener(new FourDigitFormater());
}
class FourDigitFormater implements TextWatcher {
// Change this to what you want... ' ', '-' etc..
private static final char space = ' ';
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// Remove spacing char
if (s.length() > 0 && (s.length() % 5) == 0) {
final char c = s.charAt(s.length() - 1);
if (space == c) {
s.delete(s.length() - 1, s.length());
}
}
// Insert char where needed.
if (s.length() > 0 && (s.length() % 5) == 0) {
char c = s.charAt(s.length() - 1);
// Only if its a digit where there should be a space we insert a space
if (Character.isDigit(c) && TextUtils.split(s.toString(), String.valueOf(space)).length <= 3) {
s.insert(s.length() - 1, String.valueOf(space));
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="crxpress.dgflick.com.stackoverflow.MainActivity">
<EditText
android:id="@+id/edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:inputType="phone"/>
</RelativeLayout>
editText.addTextChangedListener(new FourDigitCardFormatWatcher(editText));
Add space for every 4 digits.Use the following code.
public class FourDigitCardFormatWatcher implements TextWatcher {
// Change this to what you want... ' ', '-' etc..
private final String space = " ";
EditText et_filed;
public FourDigitCardFormatWatcher(EditText et_filed){
this.et_filed = et_filed;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
String initial = s.toString();
// remove all non-digits characters
String processed = initial.replaceAll("\\D", "");
if (processed.length() > 4){
processed = processed.replaceAll("(\\d{4})(?=\\d)", "$1 ");
}
//Remove the listener
et_filed.removeTextChangedListener(this);
//Assign processed text
et_filed.setText(processed);
try {
et_filed.setSelection(processed.length());
} catch (Exception e) {
// TODO: handle exception
}
//Give back the listener
et_filed.addTextChangedListener(this);
}
}
Use a TextListener
, parse your input using something like Arrays.toString(bitstream.split("(?<=\\G.{4})")))
which return an array and then set it to your EditText
.
Example:
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String formatted = Arrays.toString(s.toString().split("(?<=\\G.{4})"));
// remove listener to avoid cyclic calling
editText.addTextChangedListener(null);
editText.setText(formatted);
// reattach listener
editText.addTextChangedListener(this);
}
@Override
public void afterTextChanged(Editable s) {
}
});
You can use a TextWatcher. For example:
// we make a filter to accept numbers and space only!
yourEditText.setFilters(new InputFilter[]{
new InputFilter() {
@Override
public CharSequence filter(CharSequence cs, int start,
int end, Spanned spanned, int dStart, int dEnd) {
if (cs.equals("")) { // for backspace
return cs;
}
if (cs.toString().matches("[0-9 ]+")) {
return cs;
}
return "";
}
}
});
yourEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (before == 0) { // If we aren't deleting characters...
if (start + count == 4 || start + count == 9 || start + count == 14 || start + count == 19) {
// we add a simple space to better looks
yourEditText.append(" ");
}
}
}
@Override
public void afterTextChanged(Editable s) {
// nothing here
}
});
If you want to just group visually the numbers, but you don't want to alter the value of the EditText
adding spaces, you can use this Span approach:
EditText editText = findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable editable) {
Object[] paddingSpans = editable.getSpans(0, editable.length(), SpaceSpan.class);
for (Object span : paddingSpans) {
editable.removeSpan(span);
}
addSpans(editable);
}
private static final int GROUP_SIZE = 4;
private void addSpans(Editable editable) {
final int length = editable.length();
for (int i = 1; i * (GROUP_SIZE) < length; i++) {
int index = i * GROUP_SIZE;
editable.setSpan(new SpaceSpan(), index - 1, index,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
});
where the SpaceSpan
class looks like this:
/**
* A {@link ReplacementSpan} used for spacing in {@link android.widget.EditText}
* to space things out. Adds ' 's
*/
public class SpaceSpan extends ReplacementSpan {
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
float padding = paint.measureText(" ", 0, 1);
float textSize = paint.measureText(text, start, end);
return (int) (padding + textSize);
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
int bottom, @NonNull Paint paint) {
canvas.drawText(text.subSequence(start, end) + " ", x, y, paint);
}
}
A full working example is available here.