一、效果

密碼輸入.png
二、描述
實現(xiàn)一個密碼輸入框,繼承自Editext免去了位置的測量,將這個放入一個Dialog中,可以實現(xiàn)一個自定義的輸入密碼鍵盤
三、分析
1.首先要畫好背景框
2.在畫里面的豎線
1)每一次:從上一次的豎線寬度+(本次條目的寬度 )+ 本次邊框的寬度
int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;

表格.png
3.畫圓點(diǎn)
1)其實就是用的Canvas畫View替換了系統(tǒng)的draw(),如果這里不注釋 super.onDraw(canvas);在最開始的起點(diǎn)那里長按依然可以選中那些文字,當(dāng)然這不是重點(diǎn);

圓點(diǎn).png
3)鍵盤就簡單多了,繼承自LinearLayout引入布局,主要是把子View設(shè)置監(jiān)聽事件,然后進(jìn)行一個回調(diào)。
四、動手
1)man.xml
<com.example.my_inputlayout.view.MyEditextLayout
android:id="@+id/editextLayout"
android:layout_width="300dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:background="@null"
app:bgCircularBeadSize="1dp"
app:inputCount="6"
app:bgBorderSize="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:pointSizePi="6dp"
app:lineColor="@color/colorAccent"
app:lineWidth="2" />
<com.example.my_inputlayout.view.InputKeybordLayout
android:id="@+id/inputKeyBord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
></com.example.my_inputlayout.view.InputKeybordLayout>
··
2)Main.java
editextLayout = findViewById(R.id.editextLayout);
inputKeyBord = findViewById(R.id.inputKeyBord);
//屏蔽系統(tǒng)鍵盤
editextLayout.setEnabled(false);
inputKeyBord.setKeyBordBack(new InputKeybordLayout.keyBordBack() {
@Override
public void click(String str) {
editextLayout.addTextNumber(str);
}
@Override
public void delete() {
editextLayout.deleteNumber();
}
});
3)MyEditextLayout.java
public class MyEditextLayout extends AppCompatEditText {
//密碼個數(shù)
private int inputCount;
//點(diǎn)的半徑大小
private int pointSizePi;
//點(diǎn)的顏色
private int pointColor = Color.GRAY;
//分隔線顏色
private int lineColor = Color.GRAY;
//線條寬度
private int lineWidth = 1;
//背景邊框顏色
private int bgBorderColor = Color.GRAY;
//背景邊框大小
private int bgBorderSize = 1;
//背景邊框圓角
private int bgCircularBeadSize = 2;
//設(shè)置最大輸入個數(shù)
private int MAXNUMBERS = 6;
private Paint mPaint;
private Paint mBGPaint;
private Paint mPointPaint;
public MyEditextLayout(Context context) {
super(context);
}
public MyEditextLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MyEditextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyEditextLayout);
inputCount = array.getInteger(R.styleable.MyEditextLayout_inputCount, inputCount);
pointSizePi = (int) array.getDimension(R.styleable.MyEditextLayout_pointSizePi, dip2px(pointSizePi));
pointColor = array.getColor(R.styleable.MyEditextLayout_pointColor, pointColor);
lineColor = array.getColor(R.styleable.MyEditextLayout_lineColor, lineColor);
lineWidth = array.getInteger(R.styleable.MyEditextLayout_lineWidth, (int) dip2px(lineWidth));
bgBorderColor = array.getColor(R.styleable.MyEditextLayout_bgBorderColor, bgBorderColor);
bgBorderSize = (int) array.getDimension(R.styleable.MyEditextLayout_bgBorderSize, dip2px(bgBorderSize));
bgCircularBeadSize = (int) array.getDimension(R.styleable.MyEditextLayout_bgCircularBeadSize, bgCircularBeadSize);
array.recycle();
mPaint = getMPaint();
mPaint.setColor(bgBorderColor);
mBGPaint = getMPaint();
mBGPaint.setColor(bgBorderColor);
mBGPaint.setStrokeWidth(bgBorderSize);
mPointPaint = getMPaint();
mPointPaint.setColor(pointColor);
mPointPaint.setStyle(Paint.Style.FILL_AND_STROKE);
setTextColor(0X00ffffff); //把用戶輸入的內(nèi)容設(shè)置為透明
setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
this.setBackgroundDrawable(null);
setLongClickable(false);
setTextIsSelectable(false);
setCursorVisible(false);
}@Override
protected void onDraw(Canvas canvas) {// super.onDraw(canvas);
drawBorderBG(canvas);
drawBorderSeparate(canvas);
drawPWD(canvas);
}
public void addTextNumber(String str) {
if (TextUtils.isEmpty(str) || MAXNUMBERS == str.length())
return;
setText(getText() + str);
}
public void deleteNumber() {
if (TextUtils.isEmpty(getText()) || getText().length() <= 0)
return;
String str = getText().toString().trim();
str = str.substring(0, str.length() - 1);
setText(str);
}
/**
* 繪制框中心的點(diǎn)
*/
private void drawPWD(Canvas canvas) {
//實心圓
//輸入的個數(shù)
int pwdLength = getText().toString().length();
for (int i = 0; i < pwdLength; i++) {
//核心:豎線寬度 + 寬度的一半
// 豎線寬度 + 項的寬度* i + i+豎線條數(shù) + 項寬度一半
int cx = bgBorderSize + itemWidth * i + i * bgBorderSize + itemWidth / 2;
int cy = getHeight() / 2;
canvas.drawCircle(cx, cy, pointSizePi, mPointPaint);
}
}
/**
* 中間的分隔
*
* @param canvas
*/
private int itemWidth = 0;
private void drawBorderSeparate(Canvas canvas) {
//總的寬度 - (數(shù)量減-1 * 條豎線)
int passwordWidth = getWidth() - (inputCount - 1) * lineWidth;
itemWidth = passwordWidth / inputCount;
mPaint.setStrokeWidth(bgBorderSize);
// itemWidth = (getWidth() - 2 * bgBorderSize - (inputCount - 1) * lineWidth) / inputCount;
for (int i = 0; i < inputCount - 1; i++) {
//x = 每一次:從上一次的豎線寬度+(本次條目的寬度 )+ 本次次邊框的寬度
int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;
int startY = bgBorderSize;
int endX = startX;
int endY = getHeight() - bgBorderSize;
canvas.drawLine(startX, startY, endX, endY, mPaint);
}
}
/**
* 確定背景
*
* @param canvas
*/
private void drawBorderBG(Canvas canvas) {
RectF mRect = new RectF(bgCircularBeadSize, bgCircularBeadSize, getWidth() - bgCircularBeadSize, getHeight() - bgCircularBeadSize);
if (bgCircularBeadSize > 0) {
canvas.drawRoundRect(mRect, bgCircularBeadSize, bgCircularBeadSize, mBGPaint);
} else {
canvas.drawRect(mRect, mBGPaint);
}
}
private Paint getMPaint() {
Paint mPaint = new Paint();
//抗據(jù)齒
mPaint.setAntiAlias(true);
//防抖動
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
return mPaint;
}
private float dip2px(int dip) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
}
4)InputKeybordLayout.java
public class InputKeybordLayout extends LinearLayout implements View.OnClickListener {
public interface keyBordBack{
void click(String str);
void delete();
}
private keyBordBack keyBordBack;
public void setKeyBordBack(InputKeybordLayout.keyBordBack keyBordBack) {
this.keyBordBack = keyBordBack;
}
public InputKeybordLayout(Context context) {
// super(context);
this(context, null);
}
public InputKeybordLayout(Context context, @Nullable AttributeSet attrs) {
// super(context, attrs);
this(context, attrs, 0);
}
public InputKeybordLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//加載布局
inflate(context, R.layout.layout_keybord, this);
addKeyBordClickListener(this);
}
/**
* 遞歸設(shè)置子View事件
* @param view
*/
private void addKeyBordClickListener(View view) {
if (view instanceof ViewGroup){
//遍歷所有的子View設(shè)置事件
for (int i=0;i<((ViewGroup) view).getChildCount();i++){
View childV = ((ViewGroup) view).getChildAt(i);
addKeyBordClickListener(childV);
}
}else {
view.setOnClickListener(this);
}
}
@Override
public void onClick(View v) {
if (v instanceof TextView){
//強(qiáng)轉(zhuǎn)獲取鍵盤的數(shù)字
String tx = ((TextView) v).getText().toString();
if (keyBordBack==null)return;
if ("刪除".equals(tx)){
keyBordBack.delete();
}else {
keyBordBack.click(tx);
}
}
}
}
五、結(jié)論
在畫框那里有點(diǎn)復(fù)雜,主要是算位置那里一定畫圖參考,明白計算的過程,只有動手才能明白內(nèi)在的流程。