Android实现支付宝6位密码输入界面

发布时间 - 2026-01-10 22:13:52    点击率:

 我们先来照图分析一下:
(1)限制输入6位,每一位都有自己的框格,每个格显示一位;
(2)有回退/取消支付按钮;
(3)有忘记密码链接;
(4)自定义的只能输入数字的键盘输入区;
(5)在6位输完后自动进行密码校验和支付交易。如上图左边是iOS支付宝支付密码输入控件,右边是我模仿实现的效果。

首先,我们需要一个页面来完成以上的静态布局,.xml代码如下:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="#EEEEEE" 
 android:gravity="bottom"> 
 
 <LinearLayout 
  android:id="@+id/linear_pass" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:orientation="vertical"> 
 
  <RelativeLayout 
   android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:layout_margin="5dp"> 
 
   <!-- 取消按钮 --> 
   <ImageView 
    android:id="@+id/img_cancel" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:background="@drawable/icon_clean" /> 
 
   <TextView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centerInParent="true" 
    android:text="输入密码" 
    android:textColor="#898181" 
    android:textSize="20sp" /> 
  </RelativeLayout> 
 
  <View 
   android:layout_width="match_parent" 
   android:layout_height="0.5dp" 
   android:background="#555555" /> 
 
  <!-- 6位密码框布局,需要一个圆角边框的shape作为layout的背景 --> 
  <LinearLayout 
   android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:layout_marginLeft="40dp" 
   android:layout_marginRight="40dp" 
   android:layout_marginTop="20dp" 
   android:background="@drawable/shape_input_area" 
   android:orientation="horizontal"> 
 
   <!-- inputType设置隐藏密码明文 
     textSize设置大一点,否则“点”太小了,不美观 --> 
   <TextView 
    android:id="@+id/tv_pass1" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
 
   <View 
    android:layout_width="1dp" 
    android:layout_height="match_parent" 
    android:background="#999999" /> 
 
   <TextView 
    android:id="@+id/tv_pass2" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
 
   <View 
    android:layout_width="1dp" 
    android:layout_height="match_parent" 
    android:background="#999999" /> 
 
   <TextView 
    android:id="@+id/tv_pass3" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
 
   <View 
    android:layout_width="1dp" 
    android:layout_height="match_parent" 
    android:background="#999999" /> 
 
   <TextView 
    android:id="@+id/tv_pass4" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
 
   <View 
    android:layout_width="1dp" 
    android:layout_height="match_parent" 
    android:background="#999999" /> 
 
   <TextView 
    android:id="@+id/tv_pass5" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
 
   <View 
    android:layout_width="1dp" 
    android:layout_height="match_parent" 
    android:background="#999999" /> 
 
   <TextView 
    android:id="@+id/tv_pass6" 
    android:layout_width="0dp" 
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:gravity="center" 
    android:inputType="numberPassword" 
    android:textSize="32sp" /> 
  </LinearLayout> 
 
  <!-- 忘记密码链接 --> 
  <TextView 
   android:id="@+id/tv_forgetPwd" 
   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   android:layout_gravity="right" 
   android:layout_margin="15dp" 
   android:text="忘记密码?" 
   android:textColor="#354EEF" /> 
 </LinearLayout> 
 
 <!-- 输入键盘 --> 
 <GridView 
  android:id="@+id/gv_keybord" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:layout_below="@id/linear_pass" 
  android:layout_marginTop="40dp" 
  android:background="@android:color/black" 
  android:horizontalSpacing="0.5dp" 
  android:numColumns="3" 
  android:verticalSpacing="0.5dp" /> 
</RelativeLayout> 

其中需要圆角背景shape_input_area.xml:

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
 <corners android:radius="5dp"/> 
 <stroke android:color="@android:color/darker_gray" 
  android:width="1dp"/> 
 <solid android:color="@android:color/white"/> 
</shape> 

需要数字按钮的背景selector_gride.xml:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
 <item android:state_enabled="false"> 
  <shape> 
   <solid android:color="#C0C4C7" /> 
  </shape> 
 </item> 
 <item android:state_enabled="true" android:state_pressed="false"> 
  <shape> 
   <solid android:color="@android:color/white" /> 
  </shape> 
 </item> 
 <item android:state_enabled="true" android:state_pressed="true"> 
  <shape> 
   <solid android:color="#C0C4C7" /> 
  </shape> 
 </item> 
</selector> 

需要回退键背景selector_key_del.xml:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
 <item android:state_enabled="false"> 
  <shape> 
   <solid android:color="#C0C4C7" /> 
  </shape> 
 </item> 
 <item android:state_enabled="true" android:state_pressed="false"> 
  <shape> 
   <solid android:color="#C0C4C7" /> 
  </shape> 
 </item> 
 <item android:state_enabled="true" android:state_pressed="true"> 
  <shape> 
   <solid android:color="@android:color/white" /> 
  </shape> 
 </item> 
</selector> 

下面来完成我们的自定义控件PasswordView.Java:

public class PasswordView extends RelativeLayout implements View.OnClickListener { 
 Context context; 
 
 private String strPassword;  //输入的密码 
 private TextView[] tvList;  //用数组保存6个TextView,为什么用数组? 
         //因为就6个输入框不会变了,用数组内存申请固定空间,比List省空间(自己认为) 
 private GridView gridView; //用GrideView布局键盘,其实并不是真正的键盘,只是模拟键盘的功能 
 private ArrayList<Map<String, String>> valueList; //有人可能有疑问,为何这里不用数组了? 
              //因为要用Adapter中适配,用数组不能往adapter中填充 
 
 private ImageView imgCancel; 
 private TextView tvForget; 
 private int currentIndex = -1; //用于记录当前输入密码格位置 
 
 public PasswordView(Context context) { 
  this(context, null); 
 } 
 
 public PasswordView(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  this.context = context; 
  View view = View.inflate(context, R.layout.layout_popup_bottom, null); 
   
  valueList = new ArrayList<Map<String, String>>(); 
  tvList = new TextView[6]; 
   
  imgCancel = (ImageView) view.findViewById(R.id.img_cancel); 
  imgCancel.setOnClickListener(this); 
 
  tvForget = (TextView) findViewById(R.id.tv_forgetPwd); 
  tvForget.setOnClickListener(this); 
   
  tvList[0] = (TextView) view.findViewById(R.id.tv_pass1); 
  tvList[1] = (TextView) view.findViewById(R.id.tv_pass2); 
  tvList[2] = (TextView) view.findViewById(R.id.tv_pass3); 
  tvList[3] = (TextView) view.findViewById(R.id.tv_pass4); 
  tvList[4] = (TextView) view.findViewById(R.id.tv_pass5); 
  tvList[5] = (TextView) view.findViewById(R.id.tv_pass6); 
 
  gridView = (GridView) view.findViewById(R.id.gv_keybord); 
 
  setView(); 
   
  addView(view);  //必须要,不然不显示控件 
 } 
 
 @Override 
 public void onClick(View v) { 
  switch (v.getId()) { 
   case R.id.img_cancel: 
    Toast.makeText(context, "Cancel", Toast.LENGTH_SHORT).show(); 
    break; 
   case R.id.tv_forgetPwd: 
    Toast.makeText(context, "Forget", Toast.LENGTH_SHORT).show(); 
    break; 
  } 
 } 
 
 private void setView() { 
  /* 初始化按钮上应该显示的数字 */ 
  for (int i = 1; i < 13; i++) { 
   Map<String, String> map = new HashMap<String, String>(); 
   if (i < 10) { 
    map.put("name", String.valueOf(i)); 
   } else if (i == 10) { 
    map.put("name", ""); 
   } else if (i == 12) { 
    map.put("name", "<<-"); 
   } else if (i == 11) { 
    map.put("name", String.valueOf(0)); 
   } 
   valueList.add(map); 
  } 
 
  gridView.setAdapter(adapter); 
  gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
   @Override 
   public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
    if (position < 11 && position != 9) { //点击0~9按钮 
     if (currentIndex >= -1 && currentIndex < 5) {  //判断输入位置————要小心数组越界 
      tvList[++currentIndex].setText(valueList.get(position).get("name")); 
     } 
    } else { 
     if (position == 11) {  //点击退格键 
      if (currentIndex - 1 >= -1) {  //判断是否删除完毕————要小心数组越界 
       tvList[currentIndex--].setText(""); 
      } 
     } 
    } 
   } 
  }); 
 } 
 
 //设置监听方法,在第6位输入完成后触发 
 public void setOnFinishInput(final OnPasswordInputFinish pass) { 
  tvList[5].addTextChangedListener(new TextWatcher() { 
   @Override 
   public void beforeTextChanged(CharSequence s, int start, int count, int after) { 
 
   } 
 
   @Override 
   public void onTextChanged(CharSequence s, int start, int before, int count) { 
 
   } 
 
   @Override 
   public void afterTextChanged(Editable s) { 
    if (s.toString().length() == 1) { 
     strPassword = "";  //每次触发都要先将strPassword置空,再重新获取,避免由于输入删除再输入造成混乱 
     for (int i = 0; i < 6; i++) { 
      strPassword += tvList[i].getText().toString().trim(); 
     } 
     pass.inputFinish(); //接口中要实现的方法,完成密码输入完成后的响应逻辑 
    } 
   } 
  }); 
 } 
 
 /* 获取输入的密码 */ 
 public String getStrPassword() { 
  return strPassword; 
 } 
 
 /* 暴露取消支付的按钮,可以灵活改变响应 */ 
 public ImageView getCancelImageView() { 
  return imgCancel; 
 } 
 
 /* 暴露忘记密码的按钮,可以灵活改变响应 */ 
 public TextView getForgetTextView() { 
  return tvForget; 
 } 
 
 //GrideView的适配器 
 BaseAdapter adapter = new BaseAdapter() { 
  @Override 
  public int getCount() { 
   return valueList.size(); 
  } 
 
  @Override 
  public Object getItem(int position) { 
   return valueList.get(position); 
  } 
 
  @Override 
  public long getItemId(int position) { 
   return position; 
  } 
 
  @Override 
  public View getView(int position, View convertView, ViewGroup parent) { 
   ViewHolder viewHolder; 
   if (convertView == null) { 
    convertView = View.inflate(context, R.layout.item_gride, null); 
    viewHolder = new ViewHolder(); 
    viewHolder.btnKey = (TextView) convertView.findViewById(R.id.btn_keys); 
    convertView.setTag(viewHolder); 
   } else { 
    viewHolder = (ViewHolder) convertView.getTag(); 
   } 
   viewHolder.btnKey.setText(valueList.get(position).get("name")); 
   if(position == 9){ 
    viewHolder.btnKey.setBackgroundResource(R.drawable.selector_key_del); 
    viewHolder.btnKey.setEnabled(false); 
   } 
   if(position == 11){ 
    viewHolder.btnKey.setBackgroundResource(R.drawable.selector_key_del); 
   } 
 
   return convertView; 
  } 
 }; 
 
 /** 
  * 存放控件 
  */ 
 public final class ViewHolder { 
  public TextView btnKey; 
 } 
} 

自认为代码注释还是可以的。就是在实现过程中要注意数组的越界问题,在输入逻辑响应中要注意逻辑处理,也就是grideView的OnItemClickListener事件处理。其中用到自定义的接口OnPasswordInputFinish来实现输入完成的事件回掉:

/** 
 * Belong to the Project —— MyPayUI 
 * Created by WangJ on 2015/11/25 17:15. 
 * 
 * 自定义接口,用于给密码输入完成添加回掉事件 
 */ 
public interface OnPasswordInputFinish { 
 void inputFinish(); 
} 

还有就是Adapter中用到的每个按钮Item的布局item_gride.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent"> 
 
 <!-- 模拟键盘按钮,当然你可以用Button,但要注意Button和GrideView的点击响应问题 --> 
 <TextView 
  android:id="@+id/btn_keys" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:padding="10dp" 
  android:gravity="center" 
  android:textSize="25sp" 
  android:background="@drawable/selector_gride"/> 
</LinearLayout> 

好了,到此我们的自定义控件——模仿支付宝6位支付密码输入控件就完成了,下边我们在Activity中用一下,检验一下效果:
我们在MianActivity中用用一下我们定义好的控件:

public class MainActivity extends Activity { 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
   
  /************* 第一种用法————开始 ***************/ 
  setContentView(R.layout.activity_main); 
 
  final PasswordView pwdView = (PasswordView) findViewById(R.id.pwd_view); 
   
  //添加密码输入完成的响应 
  pwdView.setOnFinishInput(new OnPasswordInputFinish() { 
   @Override 
   public void inputFinish() { 
    //输入完成后我们简单显示一下输入的密码 
    //也就是说——>实现你的交易逻辑什么的在这里写 
    Toast.makeText(MainActivity.this, pwdView.getStrPassword(), Toast.LENGTH_SHORT).show(); 
   } 
  }); 
   
  /** 
   * 可以用自定义控件中暴露出来的cancelImageView方法,重新提供相应 
   * 如果写了,会覆盖我们在自定义控件中提供的响应 
   * 可以看到这里toast显示 "Biu Biu Biu"而不是"Cancel"*/ 
  pwdView.getCancelImageView().setOnClickListener(new View.OnClickListener() { 
   @Override 
   public void onClick(View v) { 
    Toast.makeText(MainActivity.this, "Biu Biu Biu", Toast.LENGTH_SHORT).show(); 
   } 
  }); 
  /************ 第一种用法————结束 ******************/ 
 
   
  /************* 第二种用法————开始 *****************/ 
//  final PasswordView pwdView = new PasswordView(this); 
//  setContentView(pwdView); 
//  pwdView.setOnFinishInput(new OnPasswordInputFinish() { 
//   @Override 
//   public void inputFinish() { 
//    Toast.makeText(MainActivity.this, pwdView.getStrPassword(), Toast.LENGTH_SHORT).show(); 
//   } 
//  }); 
  /************** 第二种用法————结束 ****************/ 
 } 
} 

在第一种方法中我们用到的布局文件:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
 android:id="@+id/xxx" 
 xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="#624762"> 
 
 <com.wangj.mypayview.PasswordView 
  android:id="@+id/pwd_view" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:layout_alignParentBottom="true"/> 
</RelativeLayout> 

更多内容请参考专题:Android密码使用教程

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Android支付宝6位密码输入界面  # Android支付宝6位密码输入  # Android支付宝密码输入  # Android仿支付宝自定义密码输入框及安全键盘(密码键盘)  # Android仿支付宝微信支付密码界面弹窗封装dialog  # android仿微信支付宝的支付密码输入框示例  # Android 仿支付宝密码输入框效果  # Android自定义View仿支付宝输入六位密码功能  # Android仿支付宝、京东的密码键盘和输入框  # Android仿微信/支付宝密码输入框  # Android仿支付宝支付密码输入框  # Android仿支付宝手势密码解锁功能  # Android实现支付宝支付密码输入界面  # 自定义  # 忘记密码  # 可以用  # 完成后  # 要小心  # 来完成  # 支付宝  # 第二种  # 第一种  # 中要  # 输入密码  # 自己的  # 圆角  # 都有  # 在这里  # 好了  # 都要  # 要注意  # 要用  # 可以看到 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何在腾讯云免费申请建站?  安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出  Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门  phpredis提高消息队列的实时性方法(推荐)  Laravel定时任务怎么设置_Laravel Crontab调度器配置  如何在阿里云完成域名注册与建站?  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  如何快速搭建支持数据库操作的智能建站平台?  Laravel如何实现模型的全局作用域?(Global Scope示例)  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  如何在阿里云域名上完成建站全流程?  php json中文编码为null的解决办法  php打包exe后无法访问网络共享_共享权限设置方法【教程】  如何在景安云服务器上绑定域名并配置虚拟主机?  深入理解Android中的xmlns:tools属性  韩国服务器如何优化跨境访问实现高效连接?  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  如何在云主机上快速搭建多站点网站?  深圳网站制作的公司有哪些,dido官方网站?  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  如何在Tomcat中配置并部署网站项目?  Python并发异常传播_错误处理解析【教程】  canvas 画布在主流浏览器中的尺寸限制详细介绍  Laravel如何使用withoutEvents方法临时禁用模型事件  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  佛山企业网站制作公司有哪些,沟通100网上服务官网?  Laravel PHP版本要求一览_Laravel各版本环境要求对照  JS碰撞运动实现方法详解  b2c电商网站制作流程,b2c水平综合的电商平台?  Laravel怎么使用artisan命令缓存配置和视图  微信公众帐号开发教程之图文消息全攻略  html5如何实现懒加载图片_ intersectionobserver api用法【教程】  三星、SK海力士获美批准:可向中国出口芯片制造设备  JS中对数组元素进行增删改移的方法总结  Laravel如何实现用户密码重置功能?(完整流程代码)  高性能网站服务器部署指南:稳定运行与安全配置优化方案  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  Laravel如何保护应用免受CSRF攻击?(原理和示例)  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  EditPlus中的正则表达式 实战(1)  如何在企业微信快速生成手机电脑官网?  如何快速打造个性化非模板自助建站?  java ZXing生成二维码及条码实例分享  如何在香港服务器上快速搭建免备案网站?  如何在七牛云存储上搭建网站并设置自定义域名?  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  湖南网站制作公司,湖南上善若水科技有限公司做什么的?