Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
public class PinEntryEditText extends EditText {
public static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
private float mSpace = 24; //24 dp by default, space between the lines
private float mCharSize;
private float mNumChars = 4;
private float mLineSpacing = 8; //8dp by default, height of the text from our lines
private int mMaxLength = 4;
private OnClickListener mClickListener;
private float mLineStroke = 1; //1dp by default
private float mLineStrokeSelected = 2; //2dp by default
private Paint mLinesPaint;
int[][] mStates = new int[][]{
new int[]{android.R.attr.state_selected}, // selected
new int[]{android.R.attr.state_focused}, // focused
new int[]{-android.R.attr.state_focused}, // unfocused
};
int[] mColors = new int[]{
Color.GREEN,
Color.BLACK,
Color.GRAY
};
ColorStateList mColorStates = new ColorStateList(mStates, mColors);
public PinEntryEditText(Context context) {
super(context);
}
public PinEntryEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
float multi = context.getResources().getDisplayMetrics().density;
mLineStroke = multi * mLineStroke;
mLineStrokeSelected = multi * mLineStrokeSelected;
mLinesPaint = new Paint(getPaint());
mLinesPaint.setStrokeWidth(mLineStroke);
if (!isInEditMode()) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.colorControlActivated,
outValue, true);
final int colorActivated = outValue.data;
mColors[0] = colorActivated;
context.getTheme().resolveAttribute(R.attr.colorPrimaryDark,
outValue, true);
final int colorDark = outValue.data;
mColors[1] = colorDark;
context.getTheme().resolveAttribute(R.attr.colorControlHighlight,
outValue, true);
final int colorHighlight = outValue.data;
mColors[2] = colorHighlight;
}
setBackgroundResource(0);
mSpace = multi * mSpace; //convert to pixels for our density
mLineSpacing = multi * mLineSpacing; //convert to pixels for our density
mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4);
mNumChars = mMaxLength;
//Disable copy paste
super.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
// When tapped, move cursor to end of text.
super.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setSelection(getText().length());
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
});
}
@Override
public void setOnClickListener(OnClickListener l) {
mClickListener = l;
}
@Override
public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
int availableWidth = getWidth() - getPaddingRight() - getPaddingLeft();
if (mSpace < 0) {
mCharSize = (availableWidth / (mNumChars * 2 - 1));
} else {
mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
}
int startX = getPaddingLeft();
int bottom = getHeight() - getPaddingBottom();
//Text Width
Editable text = getText();
int textLength = text.length();
float[] textWidths = new float[textLength];
getPaint().getTextWidths(getText(), 0, textLength, textWidths);
for (int i = 0; i < mNumChars; i++) {
updateColorForLines(i == textLength);
canvas.drawLine(startX, bottom, startX + mCharSize, bottom, mLinesPaint);
if (getText().length() > i) {
float middle = startX + mCharSize / 2;
canvas.drawText(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
}
if (mSpace < 0) {
startX += mCharSize * 2;
} else {
startX += mCharSize + mSpace;
}
}
}
private int getColorForState(int... states) {
return mColorStates.getColorForState(states, Color.GRAY);
}
/**
* @param next Is the current char the next character to be input?
*/
private void updateColorForLines(boolean next) {
if (isFocused()) {
mLinesPaint.setStrokeWidth(mLineStrokeSelected);
mLinesPaint.setColor(getColorForState(android.R.attr.state_focused));
if (next) {
mLinesPaint.setColor(getColorForState(android.R.attr.state_selected));
}
} else {
mLinesPaint.setStrokeWidth(mLineStroke);
mLinesPaint.setColor(getColorForState(-android.R.attr.state_focused));
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:padding="@dimen/activity_horizontal_margin"
tools:context="com.alimuzaffar.customwidgets.MainActivity">
<TextView
android:textAppearance="@android:style/TextAppearance.Large"
android:text="Please enter PIN"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.alimuzaffar.customwidgets.PinEntryEditText
android:id="@+id/txt_pin_entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cursorVisible="false"
android:digits="1234567890"
android:inputType="number"
android:maxLength="4"
android:textIsSelectable="false"
android:textSize="20sp" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:hint="Regular EditText"/>
</LinearLayout>
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final PinEntryEditText txtPinEntry = (PinEntryEditText) findViewById(R.id.txt_pin_entry);
txtPinEntry.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 s) {
if (s.toString().equals("1234")) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
} else if (s.length() == "1234".length()) {
Toast.makeText(MainActivity.this, "Incorrect", Toast.LENGTH_SHORT).show();
txtPinEntry.setText(null);
}
}
});
}
}
@tintomathew

This comment has been minimized.

Copy link

@tintomathew tintomathew commented Aug 14, 2019

I am not able to change the text color? tried both in xml and programatically? please let me know how can be changed?

@ganeshkumar10

This comment has been minimized.

Copy link

@ganeshkumar10 ganeshkumar10 commented Aug 26, 2019

I need curve at the lines.Can you help me?

@sageradh1

This comment has been minimized.

Copy link

@sageradh1 sageradh1 commented Oct 10, 2019

Excellent Job.
However, I am not being able to change the text color in PinEntryEditText.
I tried changing it from XML and progammatically thinking it would work as if it would work for EditText because the class is extending EditText class . But, I have had no luck with this? Is there any way to do so?

@grrigore

This comment has been minimized.

Copy link

@grrigore grrigore commented Oct 30, 2019

Excellent Job.
However, I am not being able to change the text color in PinEntryEditText.
I tried changing it from XML and progammatically thinking it would work as if it would work for EditText because the class is extending EditText class . But, I have had no luck with this? Is there any way to do so?

I am not able to change the text color? tried both in xml and programatically? please let me know how can be changed?

To change text color use getPaint().setColor(Color.parseColor("#FFFFFF")). You can write this on line 152.

@jjsan

This comment has been minimized.

Copy link

@jjsan jjsan commented Nov 4, 2019

there is error getting width of character
canvas.drawText(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
should be
canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, bottom - mLineSpacing, getPaint());

@NizarETH

This comment has been minimized.

Copy link

@NizarETH NizarETH commented Nov 5, 2019

for AndroidX extend androidx.appcompat.widget.AppCompatEditText instead of Edittext

@sajidbelim99

This comment has been minimized.

Copy link

@sajidbelim99 sajidbelim99 commented Nov 12, 2019

--To change text color following this line write in PinEntryEditText.java class
To change text color use getPaint().setColor(Color.parseColor("#FFFFFF")). You can write this on line 152.
--To change edit text underline color to write following line in PinEntryEditText
Replace colorControlActivated, colorPrimaryDark, colorControlHighlight To "colorBackgroundFloating"

@adispatil

This comment has been minimized.

Copy link

@adispatil adispatil commented Jun 5, 2020

android:cursorVisible="true"
cursor is not visible.

@Uche01

This comment has been minimized.

Copy link

@Uche01 Uche01 commented Oct 14, 2020

How can change to a password edittext? Setting the attribute in XML or programmatically does not work

@jjsan

This comment has been minimized.

Copy link

@jjsan jjsan commented Oct 16, 2020

How can change to a password edittext? Setting the attribute in XML or programmatically does not work
what have you tried?

Have you tried
android:inputType="password"
?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment