一、效果
二、描述
实现一个密码输入框,继承自Editext免去了位置的测量,将这个放入一个Dialog中,可以实现一个自定义的输入密码键盘
三、分析
1.首先要画好背景框
2.在画里面的竖线
1)每一次:从上一次的竖线宽度+(本次条目的宽度 )+ 本次边框的宽度
int startX = bgBorderSize + (i + 1) * itemWidth + i * bgBorderSize;
3.画圆点
1)其实就是用的Canvas画View替换了系统的draw(),如果这里不注释 super.onDraw(canvas);在最开始的起点那里长按依然可以选中那些文字,当然这不是重点;
3)键盘就简单多了,继承自LinearLayout引入布局,主要是把子View设置监听事件,然后进行一个回调。
四、动手
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);
//屏蔽系统键盘
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 {
//密码个数
private int inputCount;
//点的半径大小
private int pointSizePi;
//点的颜色
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;
//设置最大输入个数
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); //把用户输入的内容设置为透明
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);
}
/**
* 绘制框中心的点
*/
private void drawPWD(Canvas canvas) {
//实心圆
//输入的个数
int pwdLength = getText().toString().length();
for (int i = 0; i < pwdLength; i++) {
//核心:竖线宽度 + 宽度的一半
// 竖线宽度 + 项的宽度* i + i+竖线条数 + 项宽度一半
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) {
//总的宽度 - (数量减-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();
//抗据齿
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);
}
/**
* 递归设置子View事件
* @param view
*/
private void addKeyBordClickListener(View view) {
if (view instanceof ViewGroup){
//遍历所有的子View设置事件
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){
//强转获取键盘的数字
String tx = ((TextView) v).getText().toString();
if (keyBordBack==null)return;
if ("删除".equals(tx)){
keyBordBack.delete();
}else {
keyBordBack.click(tx);
}
}
}
}
五、结论
在画框那里有点复杂,主要是算位置那里一定画图参考,明白计算的过程,只有动手才能明白内在的流程。