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

我们先来照图分析一下:
(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密码使用教程

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

(0)

相关推荐

  • Android实现支付宝手势密码功能

    今天就给大家分享android实现支付宝手势密码,很常见,像现在用微信支付,支付宝支付的时候都要自己设置的4位PIN码,然后输入PIN码后立即调用支付接口去支付,毫无疑问的安全问题,不会觉得手机被人拿了后却不知道自己网银的钱的去向,这也是正常安全逻辑性问题. 好,下面我们来看下具体的实现: 入口,启动页面就简单的几个按钮,布局贴出来,代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android

  • 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仿支付宝支付密码输入框

    本文实例为大家分享了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仿微信支付宝的支付密码输入框示例

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

  • Android仿支付宝手势密码解锁功能

    Starting 创建手势密码可以查看 CreateGestureActivity.java 文件. 登陆验证手势密码可以看 GestureLoginActivity.java 文件. Features 使用了 JakeWharton/butterknife butterknife 使用了 ACache 来存储手势密码 /** * 保存手势密码 */ private void saveChosenPattern(List<LockPatternView.Cell> cells) { byte[

  • Android 实现仿支付宝的密码均分输入框

    Android 仿支付宝的密码均分输入框 此为安卓项目,通过重绘edittext进行文字的均分排布. 直接贴上代码: package com.xxx.xxx; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android

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

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

  • Android自定义View仿支付宝输入六位密码功能

    跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码.效果图如下: 自定义view布局效果图及代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

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

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

随机推荐