版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31433525/article/details/79106866
示例
原理
继承EditText的自定义控件,当输入字符的时候,监听字符变化,绘制边框和内容。
代码
public class PasswordInputEdit extends android.support.v7.widget.AppCompatEditText {
private Paint rectPaint;
private Paint textPaint;
private Rect textRect;
private String text = "";
private List<RectF> list = new ArrayList<>();
private boolean isFocus = false;
/**
* 是否密文显示
*/
private boolean isPwd;
/**
* 是否只能输入数字
*/
private boolean isNumber;
/**
* 横向间距
*/
private int widthSpace;
/**
* 纵向间距
*/
private int heightSpace;
/**
* 密码框的宽度
*/
private int rectStroke;
/**
* 字体大小
*/
private int txtSize;
/**
* 边框或者实体框
*/
private boolean isBgFill;
/**
* 密码长度
*/
private int numLength;
/**
* 字体颜色
*
* @param context
*/
private int textColor;
/**
* 默认框框颜色
*
* @param context
*/
private int rectNormalColor;
/**
* 选中框框颜色
*
* @param context
*/
private int rectChooseColor;
/**
* 密码显示方式
*/
private PwdType pwdType;
/**
* 是否需要在输入完成后关闭键盘
*/
private boolean isAutoCloseKeyBoard = true;
/***
* 矩形边框圆角
*/
private int cornerBound;
public enum PwdType {
CIRCLE,
XINGHAO
}
public void setPwdType(PwdType pwdType) {
this.pwdType = pwdType;
}
private int pwdType_CircleRadius;
private onInputOverListener onInputOverListener;
public void setOnInputOverListener(PasswordInputEdit.onInputOverListener onInputOverListener) {
this.onInputOverListener = onInputOverListener;
}
public PasswordInputEdit(Context context) {
super(context);
setAttr(null, 0);
init();
}
public PasswordInputEdit(Context context, AttributeSet attrs) {
super(context, attrs);
setAttr(attrs, 0);
init();
}
public PasswordInputEdit(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setAttr(attrs, defStyleAttr);
init();
}
public boolean isFocus() {
return isFocus;
}
public void setFocus(boolean focus) {
isFocus = focus;
}
public boolean isPwd() {
return isPwd;
}
public void setIsPwd(boolean pwd) {
isPwd = pwd;
}
public void setIsNumber(boolean number) {
isNumber = number;
}
public void setWidthSpace(int widthSpace) {
this.widthSpace = widthSpace;
}
public void setHeightSpace(int heightSpace) {
this.heightSpace = heightSpace;
}
public void setRectStroke(int rectStroke) {
this.rectStroke = rectStroke;
}
public void setTxtSize(int txtSize) {
this.txtSize = txtSize;
}
public boolean isBgFill() {
return isBgFill;
}
public void setIsBgFill(boolean bgFill) {
this.isBgFill = bgFill;
}
public void setNumLength(int numLength) {
this.numLength = numLength;
}
public void setRectChooseColor(int rectChooseColor) {
this.rectChooseColor = rectChooseColor;
}
public void setRectNormalColor(int rectNormalColor) {
this.rectNormalColor = rectNormalColor;
}
@Override
public void setTextColor(int textColor) {
this.textColor = textColor;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
switch (heightMode){
//尺寸的值是多少,那么这个组件的长或宽就是多少
case MeasureSpec.EXACTLY:
heightSize = MeasureSpec.getSize(heightMeasureSpec);
break;
//父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小
case MeasureSpec.AT_MOST:
heightSize = widthSize/numLength;
break;
//当前组件,可以随便用空间,不受限制
case MeasureSpec.UNSPECIFIED:
break;
}
setMeasuredDimension(widthSize,heightSize);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
isFocus = focused;
}
//监听输入文本变化
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if (this.text == null) {
return;
}
if (this.text.length() < numLength) {
this.text = this.text + text.toString();
} else {
if (onInputOverListener != null) {
onInputOverListener.onInputOver(this.text);
if (isAutoCloseKeyBoard) {
closeKeybord();
}
}
}
if (text.toString().length() != 0) {
setText("");
}
}
private void init() {
rectPaint = new Paint();
textPaint = new Paint();
textRect = new Rect();
setBackgroundDrawable(null);
setLongClickable(false);
setTextIsSelectable(false);
setCursorVisible(false);
textPaint.setStyle(Paint.Style.FILL);
}
private void setAttr(AttributeSet attrs, int defStyleAttr) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordInputEdt, defStyleAttr, 0);
isPwd = a.getBoolean(R.styleable.PasswordInputEdt_isPwd, true);
isAutoCloseKeyBoard = a.getBoolean(R.styleable.PasswordInputEdt_autoCloseKeyBoard, true);
isNumber = a.getBoolean(R.styleable.PasswordInputEdt_isNumber, true);
widthSpace = a.getDimensionPixelSize(R.styleable.PasswordInputEdt_widthSpace, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));
pwdType_CircleRadius = a.getDimensionPixelSize(R.styleable.PasswordInputEdt_circleRadius, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));
heightSpace = a.getDimensionPixelSize(R.styleable.PasswordInputEdt_heightSpace, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));
rectStroke = a.getDimensionPixelSize(R.styleable.PasswordInputEdt_rectStroke, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics()));
txtSize = a.getDimensionPixelSize(R.styleable.PasswordInputEdt_txtSize, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 18, getResources().getDisplayMetrics()));
isBgFill = a.getBoolean(R.styleable.PasswordInputEdt_bgFill, false);
numLength = a.getInt(R.styleable.PasswordInputEdt_numLength, 6);
textColor = a.getColor(R.styleable.PasswordInputEdt_textColor, 0xff666666);
rectNormalColor = a.getColor(R.styleable.PasswordInputEdt_rectNormalColor, 0xff808080);
rectChooseColor = a.getColor(R.styleable.PasswordInputEdt_rectChooseColor, 0xff44ce61);
pwdType = a.getInt(R.styleable.PasswordInputEdt_pwdType, 0) == 0 ? PwdType.CIRCLE : PwdType.XINGHAO;
cornerBound =a.getDimensionPixelSize(R.styleable.PasswordInputEdt_cornerBound, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics()));
a.recycle();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//手机按下退格键
if (keyCode == 67 && text.length() != 0) {
text = text.substring(0, text.length() - 1);
invalidate();
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isBgFill) {
rectPaint.setStyle(Paint.Style.STROKE);
}
rectPaint.setStrokeWidth(rectStroke);
textPaint.setColor(textColor);
textPaint.setTextSize(txtSize);
if (isNumber) {
setInputType(InputType.TYPE_CLASS_NUMBER);
}
int width = Math.min(getMeasuredHeight(), getMeasuredWidth() / numLength);
//画框
for (int i = 0; i < numLength; i++) {
if (i <= text.length() && isFocus) {
rectPaint.setColor(rectChooseColor);
} else {
rectPaint.setColor(rectNormalColor);
}
RectF rectF =new RectF(i * width + widthSpace, heightSpace, i * width + width - widthSpace, width - heightSpace);
canvas.drawRoundRect(rectF,cornerBound,cornerBound,rectPaint);
list.add(rectF);
}
//画内容
for (int i = 0; i < text.length(); i++) {
if (isPwd) {
switch (pwdType) {
case CIRCLE:
canvas.drawCircle(list.get(i).centerX(), list.get(i).centerY(), pwdType_CircleRadius, textPaint);
break;
case XINGHAO:
textPaint.getTextBounds("*", 0, 1, textRect);
canvas.drawText("*", list.get(i).left + (list.get(i).right - list.get(i).left) / 2 - textRect.width() / 2,
list.get(i).top + ((list.get(i).bottom - list.get(i).top) / 2) + textRect.height(), textPaint);
break;
}
} else {
textPaint.getTextBounds(text.substring(i, i + 1), 0, 1, textRect);
canvas.drawText(text.substring(i, i + 1), list.get(i).left + (list.get(i).right - list.get(i).left) / 2 - textRect.width() / 2,
list.get(i).top + ((list.get(i).bottom - list.get(i).top) / 2) + textRect.height() / 2, textPaint);
}
}
}
public interface onInputOverListener {
void onInputOver(String text);
}
/**
* 关闭软键盘
*/
public void closeKeybord() {
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
TypedArray属性设置
<resources>
<declare-styleable name="PasswordInputEdt">
<attr name="isPwd" format="boolean" />
<attr name="autoCloseKeyBoard" format="boolean" />
<attr name="isNumber" format="boolean" />
<attr name="widthSpace" format="dimension" />
<attr name="heightSpace" format="dimension" />
<attr name="rectStroke" format="dimension" />
<attr name="txtSize" format="dimension" />
<attr name="circleRadius" format="dimension" />
<attr name="bgFill" format="boolean" />
<attr name="numLength" format="integer" />
<attr name="textColor" format="color" />
<attr name="rectNormalColor" format="color" />
<attr name="rectChooseColor" format="color" />
<attr name="cornerBound" format="dimension"/>
<attr name="pwdType" format="enum" >
<enum name="CIRCLE" value="0"/>
<enum name="XINGHAO" value="1"/>
</attr>
</declare-styleable>
</resources>
使用方式
<com.example.example.view.PasswordInputEdit
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isPwd="true"
app:bgFill="false"
app:numLength="6"
app:rectStroke="2dp"
app:circleRadius="8dp"
app:pwdType="XINGHAO"
app:rectChooseColor="@color/text_color"
app:rectNormalColor="@color/colorPrimary"
app:textColor="@color/button_background"
app:cornerBound="5dp"
app:txtSize="25sp"/>
回调
edit.setOnInputOverListener(new PasswordInputEdit.onInputOverListener() {
@Override
public void onInputOver(String text) {
Toast.makeText(InputPasswordEdit.this, text, Toast.LENGTH_SHORT).show();
}
});