Format Credit Card in Edit Text in Android

Format credit card in edit text in android

Demo - How this works

Example on github.com

Late answer, but I guess it may helpful for somebody:

    cardNumberEditText.addTextChangedListener(new TextWatcher() {

private static final int TOTAL_SYMBOLS = 19; // size of pattern 0000-0000-0000-0000
private static final int TOTAL_DIGITS = 16; // max numbers of digits in pattern: 0000 x 4
private static final int DIVIDER_MODULO = 5; // means divider position is every 5th symbol beginning with 1
private static final int DIVIDER_POSITION = DIVIDER_MODULO - 1; // means divider position is every 4th symbol beginning with 0
private static final char DIVIDER = '-';

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// noop
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// noop
}

@Override
public void afterTextChanged(Editable s) {
if (!isInputCorrect(s, TOTAL_SYMBOLS, DIVIDER_MODULO, DIVIDER)) {
s.replace(0, s.length(), buildCorrectString(getDigitArray(s, TOTAL_DIGITS), DIVIDER_POSITION, DIVIDER));
}
}

private boolean isInputCorrect(Editable s, int totalSymbols, int dividerModulo, char divider) {
boolean isCorrect = s.length() <= totalSymbols; // check size of entered string
for (int i = 0; i < s.length(); i++) { // check that every element is right
if (i > 0 && (i + 1) % dividerModulo == 0) {
isCorrect &= divider == s.charAt(i);
} else {
isCorrect &= Character.isDigit(s.charAt(i));
}
}
return isCorrect;
}

private String buildCorrectString(char[] digits, int dividerPosition, char divider) {
final StringBuilder formatted = new StringBuilder();

for (int i = 0; i < digits.length; i++) {
if (digits[i] != 0) {
formatted.append(digits[i]);
if ((i > 0) && (i < (digits.length - 1)) && (((i + 1) % dividerPosition) == 0)) {
formatted.append(divider);
}
}
}

return formatted.toString();
}

private char[] getDigitArray(final Editable s, final int size) {
char[] digits = new char[size];
int index = 0;
for (int i = 0; i < s.length() && index < size; i++) {
char current = s.charAt(i);
if (Character.isDigit(current)) {
digits[index] = current;
index++;
}
}
return digits;
}
});

this works perfectly with start-string/end-string/mid-string editing, also paste works perfectly.

Formatting credit card input like (xxxx xxxx xxxx xxxx) in android

If i am not wrong, you want to do like, as user provides input in edittext after every four characters typed, a space should be placed after it.

If this is the thing you need, then you can implement:

editText.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
// apply your logic for putting space after every four characters typed
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){}
});

Edit:

I think you can use PatternMatcher class. Follow these links on [developer.android.com]:

http://developer.android.com/reference/android/os/PatternMatcher.html

http://developer.android.com/reference/java/util/regex/Pattern.html

http://developer.android.com/reference/java/util/regex/Matcher.html

Check the tutorial here: http://www.vogella.com/articles/JavaRegularExpressions/article.html

Custom format edit text input android to accept credit card number

Now this works fine for soft/hard keyboard for all delete/edit ops.
tx 4 ur help..

package com.and;

import android.app.Activity;
import android.app.AlertDialog;
import android.inputmethodservice.KeyboardView;
import android.os.Bundle;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.text.format.Formatter;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.Toast;

public class ccformat extends Activity {

String a;
int keyDel;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final EditText text = (EditText) findViewById(com.and.R.id.editText1);

text.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

boolean flag = true;
String eachBlock[] = text.getText().toString().split("-");
for (int i = 0; i < eachBlock.length; i++) {
if (eachBlock[i].length() > 4) {
flag = false;
}
}
if (flag) {

text.setOnKeyListener(new OnKeyListener() {

@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_DEL)
keyDel = 1;
return false;
}
});

if (keyDel == 0) {

if (((text.getText().length() + 1) % 5) == 0) {

if (text.getText().toString().split("-").length <= 3) {
text.setText(text.getText() + "-");
text.setSelection(text.getText().length());
}
}
a = text.getText().toString();
} else {
a = text.getText().toString();
keyDel = 0;
}

} else {
text.setText(a);
}

}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub

}

@Override
public void afterTextChanged(Editable s) {
}
});
}
}

How to allow mm/yyyy format in edittext for entering credit/debit card details

As by my understanding, your date divider must always be at position 2

private static final int CARD_DATE_DIVIDER_POSITION = CARD_DATE_DIVIDER_MODULO - 1; // means divider position is every 2nd symbol beginning with 0

with the above declaration, before appending the date divider, I should test this way ( you can change your isInputCorrect method this way):

 private boolean isInputCorrect(Editable s, int size, int dividerPosition, char divider) {
boolean isCorrect = s.length() <= size;

for (int i = 0; i < s.length(); i++) {
if (i > 0 && (i + 1) % dividerPosition == 0) {
if (divider=='/') {
if (i==2) {
isCorrect &= divider == s.charAt(i);
}
}

} else {
isCorrect &= Character.isDigit(s.charAt(i));

}
}
return isCorrect;
}

And then after the text has changed can be modified a bit to become:

@Override
public void afterTextChanged(Editable s) {
card_num = String.valueOf(s);
String ss=cardDateEditText.getText().toString();

Log.i("TAG", "Card Date:" + s);
Log.i("TAG", "Card Date :" + ss);

if (s == cardno.getEditableText()) {
if (!isInputCorrect(s, CARD_NUMBER_TOTAL_SYMBOLS, CARD_NUMBER_DIVIDER_MODULO, CARD_NUMBER_DIVIDER)) {
s.replace(0, s.length(), concatString(getDigitArray(s, CARD_NUMBER_TOTAL_DIGITS), CARD_NUMBER_DIVIDER_POSITION, CARD_NUMBER_DIVIDER));

}
} else if (s == cardDateEditText.getEditableText()) {
if (s.length()<=CARD_DATE_TOTAL_SYMBOLS)
{
if (!isInputCorrect(s, CARD_DATE_TOTAL_SYMBOLS, CARD_DATE_DIVIDER_MODULO, CARD_DATE_DIVIDER)) {
Log.e("TAG",s+"");

s.replace(0, s.length(), concatString(getDigitArray(s, CARD_DATE_TOTAL_DIGITS), CARD_DATE_DIVIDER_POSITION, CARD_DATE_DIVIDER));

}
}else
{
s.delete(CARD_DATE_TOTAL_SYMBOLS,s.length());
}

} else if (s == cardCVCEditText.getEditableText()) {
if (s.length() > CARD_CVC_TOTAL_SYMBOLS) {
s.delete(CARD_CVC_TOTAL_SYMBOLS, s.length());

}

}

}

So you test also the length of the editable text.

The date divider must be included only once and just after the month represented by two first characters. That means the last digit must be at 2nd position index 1, at that instant i==1. So no other divider will be appended. I should have to test if the divider set is for date, to know I'm dealing with the date and then test if the index is not greater or equals to 2.

That's how I could handle that. I hope this will help.

how to format credit card expiry date in mm/yy when entered by user

First set the max amount of characters of the EditText to 5, like this:

android:maxLength="5"

And set as numbers editText

android:inputType="number"

Then add an onEditTextChangedListener to the EditText to detect if the amount of characters is changed to two and did not change from three to two and remove "/" if a number before "/" is removed:

edit_text.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {}

override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}

override fun onTextChanged(p0: CharSequence?, start: Int, removed: Int, added: Int) {
if (start == 1 && start+added == 2 && p0?.contains('/') == false) {
edit_text.setText(p0.toString() + "/")
} else if (start == 3 && start-removed == 2 && p0?.contains('/') == true) {
edit_text.setText(p0.toString().replace("/", ""))
}
}
})

Android Edittext with auto detection of credit card type

From the help of above answers and suggestion i have achieved the result,

Here is the solution:

Create a function for regex making

public static ArrayList<String> listOfPattern()
{
ArrayList<String> listOfPattern=new ArrayList<String>();

String ptVisa = "^4[0-9]$";

listOfPattern.add(ptVisa);

String ptMasterCard = "^5[1-5]$";

listOfPattern.add(ptMasterCard);

String ptDiscover = "^6(?:011|5[0-9]{2})$";

listOfPattern.add(ptDiscover);

String ptAmeExp = "^3[47]$";

listOfPattern.add(ptAmeExp);

return listOfPattern;
}

Integer[] imageArray = { R.drawable.visa, R.drawable.master, R.drawable.disnet, R.drawable.ae };

use this below code in addTextChangedListener

creditcardnumberedittext.addTextChangedListener(new TextWatcher()
{

@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
String ccNum = s.toString();

if(ccNum.length()>=2)
{
for (int i = 0; i < listOfPattern.size(); i++)
{
if (ccNum.substring(0, 2).matches(listOfPattern.get(i)))
{
creditcardnumberedittext.setCompoundDrawablesWithIntrinsicBounds(0, 0, imageArray[i], 0);

cardtype = String.valueOf(i);
}
}
}

}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
// TODO Auto-generated method stub

}

@Override
public void afterTextChanged(Editable s)
{

if (!creditcardnumberedittext.getText().toString().equalsIgnoreCase(""))
{
for (int i = 0; i < listOfPattern.size(); i++)
{
if (creditcardnumberedittext.getText().toString().matches(listOfPattern.get(i)))
{
creditcardnumberedittext.setCompoundDrawablesWithIntrinsicBounds(0, 0, imageArray[i], 0);

cardtype = String.valueOf(i);
}
}
}
else
{
creditcardnumberedittext.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.allcards, 0);
}
}
});

Thanks..

How to make {EditText} accept input in format:

You are unable to delete hyphen because in ontextchanged, when you get to the hyphen character position, you are again adding the hyphen.

You should differentiate if you got to hyphen character by adding the text or by deleting the text.

If you got to the hyphen position by deleting text, you dont want to add hyphen.

You can check by this code if(before-count<0){

Below is your working example

     editText.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

if ((editText.getText().length() + 1 == 3 || editText.getText().length() + 1 == 6 || editText.getText().length() + 1 == 9)) {
if(before-count<0){
editText.setText(editText.getText() + "-");
editText.setSelection(editText.getText().length());
}
}
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}

@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
}

}

XML

 android:maxLength="13"

Want to format the number in EditText

It would be much easier if you changed your approach a bit. You could be always analyzing unformatted verion of your string after every single change in your EditText.

Try this (remember to set android:maxLength="13" for your EditText):

Enrollement.addTextChangedListener(new TextWatcher() {

final int[] blockLengths = new int[]{2, 6, 3};
String mUnformatted = "";

@Override
public void onTextChanged (CharSequence s,int start, int before, int count){
String unformattedSeq = s.toString().replace("-", "");
if (mUnformatted.length() == unformattedSeq.length()) {
return; //length of text has not changed
}

mUnformatted = unformattedSeq;
//formatting sequence
StringBuilder formatted = new StringBuilder();
int blockIndex = 0;
int currentBlock = 0;
for (int i = 0; i < mUnformatted.length(); ++i) {
if (currentBlock == blockLengths[blockIndex]) {
formatted.append("-");
currentBlock = 0;
blockIndex++;
}
formatted.append(mUnformatted.charAt(i));
currentBlock++;
}

Enrollement.setText(formatted.toString());
Enrollement.setSelection(formatted.length());
}

@Override
public void beforeTextChanged (CharSequence s,int start, int count, int after){
}

@Override
public void afterTextChanged (Editable s){
}
});

This code should work correctly. You could only improve the setSelection part (currently if you delete a number in the middle of your EditText it will move your cursor to the end of the text).

How do I format a string into EditText in Android with AAA-AAA-AAA format

I have found the solution using a TextWatcher. I'm using

android:inputType="textCapCharacters|textNoSuggestions"

for the EditText input type in order to receive only uppercase letters.

        txtCode = (EditText) findViewById(R.id.txtCode);

txtCode.addTextChangedListener( new TextWatcher() {
boolean isEdiging;
@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) {
if(isEdiging) return;
isEdiging = true;
// removing old dashes
StringBuilder sb = new StringBuilder();
sb.append(s.toString().replace("-", ""));

if (sb.length()> 3)
sb.insert(3, "-");
if (sb.length()> 7)
sb.insert(7, "-");
if(sb.length()> 11)
sb.delete(11, sb.length());

s.replace(0, s.length(), sb.toString());
isEdiging = false;
}
});


Related Topics



Leave a reply



Submit