-
-
Save alphamu/0d3055e0233c5749b8d6 to your computer and use it in GitHub Desktop.
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); | |
} | |
} | |
}); | |
} | |
} |
for AndroidX extend androidx.appcompat.widget.AppCompatEditText instead of Edittext
--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"
android:cursorVisible="true"
cursor is not visible.
How can change to a password edittext? Setting the attribute in XML or programmatically does not work
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"
?
i tried but its not working numbers are visible when input
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());