Android仿支付宝自定义密码输入框及安全键盘(密码键盘)

 0、前言

之前做过的项目里有运用到一个支付场景:用户办理业务时需要输入交易密码,并且可根据平台下发的支付方式进行选择。这与支付宝的密码输入方式十分相似,如果使用Android系统或者第三方软件的键盘,会有密码泄露的风险。因此,大多数的应用软件使用的是自定义的密码输入框及安全键盘。

由于密码输入方式需要实现一个从底部弹出的效果,因此总体上决定采用BottomSheetDialog来进行封装,同时为了提高安全性,还应该随机生成键盘上的数字,界面如下图所示:

 

首先新建一个PasswordInputView类,将需要使用到的Context对象、支付金额、可支持的支付方式等数据,作为该类构造方法的参数进行传递。下文还将提到该类有一个回调方法,当用户输入的密码满足六位时,可以在回调方法中获取密码并显示出来。PasswordInputView类的构造方法如下所示:

public PasswordInputView(Context context, String payMoney, List<String> payWayList) {
 this.context = context;
 this.payMoney = payMoney;
 this.payWayList = payWayList;
 payPwdDialog = new BottomSheetDialog(context);
 View view = LayoutInflater.from(context).inflate(R.layout.dialog_pay_pwd, null, false);
 initStep1(view);
 initStep2(view);
 llyPwdInputView = (LinearLayout) view.findViewById(R.id.lly_pwd_input_view);
 llyPayWaySelect = (LinearLayout) view.findViewById(R.id.lly_pay_way_select);
 showStep1(); // 显示第一页
} 

1、自定义密码输入框

因为不能明文显示输入的密码,所以使用“●”来代替每位密码。自定义密码输入框涉及到的自定义属性,主要包括:输入框的大小、颜色、圆角半径以及密码圆点的大小、颜色、半径。因此,自定义属性attrs.xml文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="PasswordEditText">
  <attr name="borderWidth" format="dimension"/>
  <attr name="borderColor" format="color"/>
  <attr name="borderRadius" format="dimension"/>
  <attr name="passwordLength" format="integer"/>
  <attr name="passwordWidth" format="dimension"/>
  <attr name="passwordColor" format="color"/>
  <attr name="passwordRadius" format="dimension"/>
 </declare-styleable>
</resources> 

接下来就需要去绘制自定义控件了。首先获取自定义属性,然后在onDraw()中进行绘制,代码如下所示:

package com.syd.paypwddialogdemo;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
/**
 * 自定义密码输入框
 */
public class PasswordEditText extends AppCompatEditText {
 private int textLength;
 private int borderColor;
 private float borderWidth;
 private float borderRadius;
 private int passwordLength;
 private int passwordColor;
 private float passwordWidth;
 private float passwordRadius;
 private Paint passwordPaint = new Paint(ANTI_ALIAS_FLAG);
 private Paint borderPaint = new Paint(ANTI_ALIAS_FLAG);
 private final int defaultContMargin = 5;
 private final int defaultSplitLineWidth = 3;
 public PasswordEditText(Context context, AttributeSet attrs) {
  super(context, attrs);
  final Resources res = getResources();
  final int defaultBorderColor = res.getColor(R.color.colorGray);
  final float defaultBorderWidth = res.getDimension(R.dimen.default_ev_border_width);
  final float defaultBorderRadius = res.getDimension(R.dimen.default_ev_border_radius);
  final int defaultPasswordLength = res.getInteger(R.integer.default_ev_password_length);
  final int defaultPasswordColor = res.getColor(R.color.colorBlack);
  final float defaultPasswordWidth = res.getDimension(R.dimen.default_ev_password_width);
  final float defaultPasswordRadius = res.getDimension(R.dimen.default_ev_password_radius);
  TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordEditText, 0, 0);
  try {
   borderColor = a.getColor(R.styleable.PasswordEditText_borderColor, defaultBorderColor);
   borderWidth = a.getDimension(R.styleable.PasswordEditText_borderWidth, defaultBorderWidth);
   borderRadius = a.getDimension(R.styleable.PasswordEditText_borderRadius, defaultBorderRadius);
   passwordLength = a.getInt(R.styleable.PasswordEditText_passwordLength, defaultPasswordLength);
   passwordColor = a.getColor(R.styleable.PasswordEditText_passwordColor, defaultPasswordColor);
   passwordWidth = a.getDimension(R.styleable.PasswordEditText_passwordWidth, defaultPasswordWidth);
   passwordRadius = a.getDimension(R.styleable.PasswordEditText_passwordRadius, defaultPasswordRadius);
  } finally {
   a.recycle();
  }
  borderPaint.setStrokeWidth(borderWidth);
  borderPaint.setColor(borderColor);
  passwordPaint.setStrokeWidth(passwordWidth);
  passwordPaint.setStyle(Paint.Style.FILL);
  passwordPaint.setColor(passwordColor);
 }
 @Override
 protected void onDraw(Canvas canvas) {
  int width = getWidth();
  int height = getHeight();
  RectF rect = new RectF(0, 0, width, height);
  borderPaint.setColor(borderColor);
  canvas.drawRoundRect(rect, borderRadius, borderRadius, borderPaint);
  RectF rectIn = new RectF(rect.left + defaultContMargin, rect.top + defaultContMargin,
    rect.right - defaultContMargin, rect.bottom - defaultContMargin);
  borderPaint.setColor(Color.WHITE);
  canvas.drawRoundRect(rectIn, borderRadius, borderRadius, borderPaint);
  borderPaint.setColor(borderColor);
  borderPaint.setStrokeWidth(defaultSplitLineWidth);
  for (int i = 1; i < passwordLength; i++) {
   float x = width * i / passwordLength;
   canvas.drawLine(x, 0, x, height, borderPaint);
  }
  float cx, cy = height / 2;
  float half = width / passwordLength / 2;
  for (int i = 0; i < textLength; i++) {
   cx = width * i / passwordLength + half;
   canvas.drawCircle(cx, cy, passwordWidth, passwordPaint);
  }
 }
 @Override
 protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
  super.onTextChanged(text, start, lengthBefore, lengthAfter);
  this.textLength = text.toString().length();
  invalidate();
 }
 public int getBorderColor() {
  return borderColor;
 }
 public void setBorderColor(int borderColor) {
  this.borderColor = borderColor;
  borderPaint.setColor(borderColor);
  invalidate();
 }
 public float getBorderWidth() {
  return borderWidth;
 }
 public void setBorderWidth(float borderWidth) {
  this.borderWidth = borderWidth;
  borderPaint.setStrokeWidth(borderWidth);
  invalidate();
 }
 public float getBorderRadius() {
  return borderRadius;
 }
 public void setBorderRadius(float borderRadius) {
  this.borderRadius = borderRadius;
  invalidate();
 }
 public int getPasswordLength() {
  return passwordLength;
 }
 public void setPasswordLength(int passwordLength) {
  this.passwordLength = passwordLength;
  invalidate();
 }
 public int getPasswordColor() {
  return passwordColor;
 }
 public void setPasswordColor(int passwordColor) {
  this.passwordColor = passwordColor;
  passwordPaint.setColor(passwordColor);
  invalidate();
 }
 public float getPasswordWidth() {
  return passwordWidth;
 }
 public void setPasswordWidth(float passwordWidth) {
  this.passwordWidth = passwordWidth;
  passwordPaint.setStrokeWidth(passwordWidth);
  invalidate();
 }
 public float getPasswordRadius() {
  return passwordRadius;
 }
 public void setPasswordRadius(float passwordRadius) {
  this.passwordRadius = passwordRadius;
  invalidate();
 }
} 

2、安全键盘的实现

安全键盘主要是通过GridView来实现,上文提到为了保证安全性,在安全键盘初始化的时候,应该随机生成键盘上的数字,代码如下所示:

/**
 * 初始化密码键盘
 */
private void initKeyboard() {
 final int number = 10;
 int[] keys = new int[number];
 for (int i = 0; i < 10; i++) {
  keys[i] = i;
 }
 // 随机生成键盘数字
 Random random = new Random();
 for (int i = 0; i < number; i++) {
  int p = random.nextInt(number);
  int tmp = keys[i];
  keys[i] = keys[p];
  keys[p] = tmp;
 }
 numList = new ArrayList<>();
 for (int i = 0; i < 12; i++) {
  Map<String, String> map = new HashMap<>();
  if (i < 9) {
   map.put("num", String.valueOf(keys[i]));
  } else if (i == 9) {
   map.put("num", "");
  } else if (i == 10) {
   map.put("num", String.valueOf(keys[9]));
  } else if (i == 11) {
   map.put("num", "");
  }
  numList.add(map);
 }
 KeyAdapter keyAdapter = new KeyAdapter(context, numList, handler);
 gvKeyboard.setAdapter(keyAdapter);
} 

安全键盘点击事件的处理,是在适配器KeyAdapter的构造方法中传入Handler对象,通过收发消息的方式在PasswordInputView类中处理的,代码如下所示:

holder.btnKey.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
  Message msg = new Message();
  msg.what = Constants.KEYBOARD_INPUT;
  msg.obj = position;
  handler.sendMessage(msg);
 }
}); 

Handler对象在PasswordInputView类中定义,主要用于处理安全键盘的点击事件,代码如下所示:

Handler handler = new Handler() {
 @Override
 public void dispatchMessage(Message msg) {
  switch (msg.what) {
   case Constants.KEYBOARD_INPUT:
    int position = (int) msg.obj;
    if (position < 11 && position != 9) {
     // 点击0-9按键
     password = etPwd.getText().append(numList.get(position).get("num")).toString();
     etPwd.setText(password);
    } else {
     if (position == 11) {
      // 点击退格键
      if (!TextUtils.isEmpty(password) && !password.equals("")) {
       password = etPwd.getText().delete(password.length() - 1, password.length()).toString();
       etPwd.setText(password);
      }
     }
    }
    break;
  }
 }
}; 

为了方便外部获取到用户输入的密码,设计一个回调接口OnPwdInputListener,并在PasswordInputView类中为回调接口创建一个set方法,代码如下所示:

package com.syd.paypwddialogdemo;
public interface OnPwdInputListener {
 void onPwdInput(String password);
} 

当PasswordEditText控件的TextWatcher对象监听到输入的密码满足六位时,调用回调方法,将密码作为参数进行传递,代码如下所示:

textWatcher = new TextWatcher() {
 @Override
 public void afterTextChanged(Editable s) {
  if (etPwd.getText().length() == 6) {
   onPwdInputListener.onPwdInput(etPwd.getText().toString());
  }
 }
};
etPwd.addTextChangedListener(textWatcher); 

在外部调用set方法,创建OnPwdInputListener对象,重写回调方法,即可获取到用户输入的密码,代码如下所示:

pwdInputView.setOnPwdInputListener(new OnPwdInputListener() {
 @Override
 public void onPwdInput(String password) {
  Toast.makeText(MainActivity.this, password, Toast.LENGTH_SHORT).show();
 }
}); 

3、结语

以上介绍了自定义密码输入框及安全键盘的大致实现思路,对源码感兴趣的小伙伴可以点击下载Demo,查看具体的实现过程及演示效果。

您可能感兴趣的文章:

  • android仿支付宝、微信密码输入框效果
  • android仿微信支付宝的支付密码输入框示例
  • Android 仿支付宝密码输入框效果
  • Android仿支付宝支付密码输入框
  • Android仿支付宝、京东的密码键盘和输入框
  • Android仿微信/支付宝密码输入框
(0)

相关推荐

  • Android 仿支付宝密码输入框效果

    模仿支付宝输入效果,实现很简单,就是画个矩形框和圆形,其他的通过组合view来实现所有功能,虽然简单但是封装起来,方便以后使用,也分享一下,希望对别人也有点帮助. 1.如何使用,可以设置自己的进入退出动画,不设置则没有动画效果,自己觉得封装之后还是非常用好的. private MyInputPwdUtil myInputPwdUtil; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(sa

  • android仿支付宝、微信密码输入框效果

    本文实例为大家分享了android密码输入框效果展示的具体代码,供大家参考,具体内容如下 老规矩,先看效果:这是现在商城类app中很常见的支付密码效果,首先说下这个不是自定义控件,是github上的开源库: https://github.com/Jungerr/GridPasswordView 下面主要说下这个开源库的用法和平时我们常用的几点功能: 想要使用这个开源库首先我们需要将库导入到咱们的项目中: 直接在app的build.gradle下添加如下代码 dependencies { comp

  • Android仿支付宝支付密码输入框

    本文实例为大家分享了Android实现一个仿支付宝支付密码的输入框,主要实现如下: PasswordView.java package com.jackie.alipay.password; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphic

  • Android仿支付宝、京东的密码键盘和输入框

    首先看下效果图 一:布局代码 键盘由0~9的数字,删除键和完成键组成,也可以根据需求通过GridView适配器的getItemViewType方法来定义.点击键的时候背景有变色的效果. 密码输入框由六个EditText组成,每个输入框最对能输入一个数字,监听最后一个输入框来完成密码输入结束的监听. 二:键盘 键盘中的主要逻辑处理,键盘样式,item的点击事件 @Override public int getViewTypeCount() { return 2; } @Override publi

  • Android仿微信/支付宝密码输入框

    在用到支付类app时,都有一个简密的输入框..开始实现的时候思路有点问题,后来到github上搜了下,找到了一个开源的库看起来相当的牛逼,,来个地址先: https://github.com/Jungerr/GridPasswordView 效果图: 这个开源库我研究了之后,又有了自己的一个思路:来个假的简密框---底部放一个EditTextView,顶部放置6个ImageView的原点,控制他们的显隐来实现这个简密宽 开发步骤: 1 布局 <?xml version="1.0"

  • android仿微信支付宝的支付密码输入框示例

    大家好,我是狸小华,萌汉子一枚.今天给大家带来的是仿微信/支付宝的密码输入框.这个效果也出来有一段时间了,所以搜索一下还是有不少的网友实现,但是,但是!经过一番查看后,我发现他们的实现分为两大类. 一,直接继承EditText,然后在ondraw里面做文章:二,EditText外面包一个viewGroup.我不喜欢这两种实现方式,觉着有些臃肿了,所以我详细介绍下我的实现方式:直接继承View,获取用户的输入,然后draw出来. 我们实现的是上面的密码输入框,这个键盘...系统自带的哦,调用用户输

  • Android仿支付宝自定义密码输入框及安全键盘(密码键盘)

     0.前言 之前做过的项目里有运用到一个支付场景:用户办理业务时需要输入交易密码,并且可根据平台下发的支付方式进行选择.这与支付宝的密码输入方式十分相似,如果使用Android系统或者第三方软件的键盘,会有密码泄露的风险.因此,大多数的应用软件使用的是自定义的密码输入框及安全键盘. 由于密码输入方式需要实现一个从底部弹出的效果,因此总体上决定采用BottomSheetDialog来进行封装,同时为了提高安全性,还应该随机生成键盘上的数字,界面如下图所示:   首先新建一个PasswordInpu

  • Android仿支付宝密码输入效果封装

    模仿支付宝输入效果,实现很简单,就是画个矩形框和圆形,其他的通过组合view来实现所有功能,虽然简单但是封装起来,方便以后使用,也分享一下,希望对别人也有点帮助. 1.如何使用,可以设置自己的进入退出动画,不设置则没有动画效果,自己觉得封装之后还是非常用好的. private MyInputPwdUtil myInputPwdUtil; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(sa

  • Android 仿微信自定义数字键盘的实现代码

    本文介绍了Android 仿微信自定义数字键盘的实现代码,分享给大家,希望对大家有帮助 最终效果: 实现这个自定义键盘的思路很简单: 要写出一个数字键盘的布局: 与 Edittext 结合使用,对每个按键的点击事件进行处理: 禁用系统软键盘. 有了思路,实现起来就不难了. 1. 实现键盘的 xml 布局 网格样式的布局用 GridView 或者 RecyclerView 都可以实现,其实用 GridView 更方便一些,不过我为了多熟悉 RecyclerView 的用法,这里选择用了 Recyc

  • android仿支付宝密码输入框效果

    本文实例为大家分享了android仿支付宝密码输入框展示的具体代码,供大家参考,具体内容如下 这个没什么好分析的,就是一些基本的绘制什么线,矩形什么的,看代码更具体 布局文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

  • Android仿支付宝的头部伸缩动画效果

    Android5.0推出的MaterialDesign库包含了处理头部工具栏的多个控件,不但允许自定义顶部导航栏,而且导航栏高度是可以伸缩的.如此一来,一方面导航栏能够放得下更多控件,另一方面在用户想看具体内容时也能腾出更多的屏幕空间. 这么说可能比较抽象,那就先来看看两张导航栏的效果图,第一张是导航栏完全展开时的界面,此时页面头部的导航栏占据了较大部分的高度: 第二张是导航栏完全收缩时的界面,此时头部导航栏只剩矮矮的一个长条. 看起来很眼熟是不是,上面的截图正是仿支付宝首页的头部效果.如果你熟

  • Android仿支付宝微信支付密码界面弹窗封装dialog

    一,功能效果 二,实现过程 1,先写xml文件:dialog_keyboard.xml 注意事项 (1),密码部分用的是一个线性布局中6个TextView,并设置android:inputType="numberPassword",外框是用的一个有stroke属性的shape, (2),1-9数字是用的recycleview ,每个item的底部和右边有1dp的黑线,填充后形成分割线. (3),recycleview 要设置属性  android:overScrollMode=&quo

  • Android 仿支付宝中的余额宝收益进度条

    一. 看效果 二.上代码 package com.framework.widget; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import androi

  • Android仿支付宝中余额宝的数字动画效果

    实现效果图: 下面是具体代码,可直接复制: package com.lcw.rabbit.widget; import android.animation.ObjectAnimator; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.animation.AccelerateDecelerateInterpola

随机推荐