上面这个是采用自定view方式实现的一个仿支付宝支付弹窗的效果;
1、自定义view并初始化自定义属性
public class PasswordEditText extends EditText{ //一个密码所占的宽度 private int mPasswordItemWidth; //密码的个数默认6个 private int mPasswordNumder=6; //背景边框颜色 private int mBgColor= Color.parseColor("#d1d2d6"); //背景边框的大小 private int mBgSize=1; //背景边框圆角大小 private int mBgCorner=0; //分割线的颜色 private int mDivisionLineColor=mBgColor; //分割线的大小 private int mDivisionLineSize=1; //密码圆点的颜色 private int mPasswordColor=mDivisionLineColor; //密码圆点的半径大小 private int mPasswordRadius=4; public PasswordEditText(Context context) { this(context,null); } public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initAttributeSet(context, attrs); } /** * 初始化属性 * @param context * @param attrs */ private void initAttributeSet(Context context, AttributeSet attrs) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText); //获取大小 mDivisionLineSize= (int) array.getDimension(R.styleable.PasswordEditText_divisionLineSize,dip2px(mDivisionLineSize)); mPasswordRadius= (int) array.getDimension(R.styleable.PasswordEditText_passwordRadius,dip2px(mPasswordRadius)); mBgSize= (int) array.getDimension(R.styleable.PasswordEditText_bgSize,dip2px(mBgSize)); mBgCorner= (int) array.getDimension(R.styleable.PasswordEditText_bgCorner,dip2px(mBgCorner)); //获取颜色 mBgColor=array.getColor(R.styleable.PasswordEditText_bgColor,mBgColor); mDivisionLineColor=array.getColor(R.styleable.PasswordEditText_divisionLineColor,mDivisionLineColor); mPasswordColor=array.getColor(R.styleable.PasswordEditText_passwordColor,mDivisionLineColor); array.recycle(); } }继承自EditText的话可以用使用EditText中的一些属性和方法,在初始化完自定义属性后要记得调用recycle()方法进行回收;
2、初始化画笔
/** * 初始化画笔 */ private void initPaint() { mPaint=new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); }在第三个构造函数中调用就可以了,
3、在onDraw()方法中进行绘制 在绘制的时候先要计算出一个密码所占的宽度
//一个密码的宽度 private int mPasswordItemWidth=(getWidth()-2*mBgSize-(mPasswordNumder-1)*mDivisionLineSize)/mPasswordNumder; 一个密码的宽度=(整个输入框的宽度-(最左边边框的宽度+最右边边框的宽度)-(密码个数-1)*密码之间分割线的宽度)/密码的个数获取到一个密码的宽度后就可以进行绘制; 3.1、绘制密码输入框的背景
private void drawBg(Canvas canvas) { RectF rect=new RectF(mBgSize,mBgSize,getWidth()-mBgSize,getHeight()-mBgSize); //绘制背景 如果有圆角就绘制圆角矩形,没有就绘制矩形 //设置画笔的大小 mPaint.setStrokeWidth(mBgSize); mPaint.setColor(mBgColor); //绘制空心 mPaint.setStyle(Paint.Style.STROKE); if(mBgCorner==0){ canvas.drawRect(rect,mPaint); }else{ canvas.drawRoundRect(rect,mBgCorner,mBgCorner,mPaint); } }没有圆角的话,就调用canvas.drawRect(rect,mPaint);绘制矩形,第一个参数是RectF对象,第二个参数是Paint(画笔);
/* @param left The X coordinate of the left side of the rectangle * @param top The Y coordinate of the top of the rectangle * @param right The X coordinate of the right side of the rectangle * @param bottom The Y coordinate of the bottom of the rectangle */ public RectF(float left, float top, float right, float bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; }RectF源码对四个参数都有说明;
left=输入框边框的大小; top=输入框边框的大小; right=getWidth()-输入框边框的大小; bottom=getHeight()-输入框边框的大小;如果有圆角的话,就调用canvas.drawRoundRect(rect,mBgCorner,mBgCorner,mPaint);绘制圆角矩形,
/** * @param rect The rectangular bounds of the roundRect to be drawn * @param rx The x-radius of the oval used to round the corners * @param ry The y-radius of the oval used to round the corners * @param paint The paint used to draw the roundRect */ public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) { drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint); }drawRoundRect源码也对要传入的参数做了说明; 3.2、绘制密码输入框之间的分割线
private void drawDivisionLine(Canvas canvas) { mPaint.setStrokeWidth(mDivisionLineSize); mPaint.setColor(mDivisionLineColor); for (int i=0;i<mPasswordNumder-1;i++){ int startX=mBgSize+(i+1)*mPasswordItemWidth+i*mDivisionLineSize; int startY=mBgSize; int endX=startX; int endY=getHeight()-mBgSize; canvas.drawLine(startX,startY,endX,endY,mPaint); } }在绘制分割线的时候需要注意,假设密码的个数是6,只需要绘制5个分割线,调用canvas.drawLine(startX,startY,endX,endY,mPaint);方法进行绘制,
/** * @param startX The x-coordinate of the start point of the line * @param startY The y-coordinate of the start point of the line * @param paint The paint used to draw the line */ public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); }上面是drawLine方法的源码,第一个参数是X的起始位置,第二个参数是Y的起始位置,第三个参数是X的终点位置,第四个参数是Y的终点位置;
startX=输入框边框的宽度+(每个密码的宽度)*当前绘制的位置(当前绘制第几个)+单个分割线的宽度*当前绘制的位置(当前绘制第几个); startY=输入框边框的宽度; stopX=startX; stopY=getHeight()-输入框边框的宽度;3.3、绘制密码
private void drawPassword(Canvas canvas) { //设置实心样式 mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(mPasswordColor); String text=getText().toString().trim(); int passwordLength=text.length(); for(int i=0;i<passwordLength;i++){ int cx=mBgSize+i*mPasswordItemWidth+i*mDivisionLineSize+mPasswordItemWidth/2; int cy=getHeight()/2; canvas.drawCircle(cx,cy,mPasswordRadius,mPaint); } }在绘制密码黑圆点之前先要获取到输入的字符的长度,根据长度遍历该字符串调用canvas.drawCircle(cx,cy,mPasswordRadius,mPaint);进行绘制, drawCircle()源码:
/** * @param cx The x-coordinate of the center of the cirle to be drawn * @param cy The y-coordinate of the center of the cirle to be drawn * @param radius The radius of the cirle to be drawn * @param paint The paint used to draw the circle */ public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) { native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance()); }第一个参数是X的位置,第二个参数是Y的位置,第三个参数是圆的半径,第四个参数是画笔;
cx=输入框边框的宽度+单个分割线的宽度*当前绘制哪一个+密码框的宽度*当前绘制哪一个+密码框的宽度/2; cy=getHeight()/2;到这里输入框背景、分割线、密码都已经绘制完毕了,在这里面添加一个密码添加和删除的方法;
/** * 设置密码 * @param numder */ public void addPassword(String numder) { //把之前的密码取出来 String password=getText().toString().trim(); //判断密码的长度,不能超过当前设置的密码的个数 if(password.length()>=mPasswordNumder){ return; } //密码叠加 password+=numder; setText(password); } /** * 删除最后一位密码 */ public void deleteLastPassword() { //把之前的密码取出来 String password=getText().toString().trim(); //判断当前密码是否为空 if(TextUtils.isEmpty(password)){ return; } password=password.substring(0,password.length()-1); setText(password); }剩下还有键盘没有弄好,键盘的实现是在xml布局里面写好,添加到LinearLayout中;
4、输入键盘的实现
public class CustomerKeyboard extends LinearLayout implements View.OnClickListener { public CustomerKeyboard(Context context) { this(context,null); } public CustomerKeyboard(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomerKeyboard(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //直接加载布局 inflate(context,R.layout.ui_customer_keyboard,this); } }添加进来后,设置相应的点击事件;
/** * 设置点击事件 * @param view */ private void setItemClickListener(View view) { if(view instanceof ViewGroup){ ViewGroup viewGroup= (ViewGroup) view; int childCount = viewGroup.getChildCount(); for (int i=0;i<childCount;i++){ View childView = viewGroup.getChildAt(i); setItemClickListener(childView); } }else{ view.setOnClickListener(this); } } @Override public void onClick(View v) { if(v instanceof TextView){ //点击的是文本 String number=((TextView) v).getText().toString().trim(); if(mListener!=null&&number.length()!=0){ mListener.click(number); } } if(v instanceof ImageView){ //点击的是删除 if(mListener!=null){ mListener.delete(); } } }差不多效果就实现了,在点击的地方调用就可以了;
//弹出dialog输入框 AlertDialog dialog=new AlertDialog.Builder(this). setContentView(R.layout.activity_main). fullWith(). formBottom(true). setCancelable(true). show(); passwordEditText=dialog.getView(R.id.password); mCustomerKeyboard=dialog.getView(R.id.customer_keyboard); mCustomerKeyboard.setOnCustomerKeyboardClickListener(this); passwordEditText.setEnabled(false); passwordEditText.setOnPasswordFullListener(this);源码地址: http://download.csdn.net/download/wangwo1991/9894467