Welcome

首页 / 移动开发 / Android / 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"><LinearLayoutandroid:id="@+id/linear_pass"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"><!-- 取消按钮 --><ImageViewandroid:id="@+id/img_cancel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/icon_clean" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="输入密码"android:textColor="#898181"android:textSize="20sp" /></RelativeLayout><Viewandroid:layout_width="match_parent"android:layout_height="0.5dp"android:background="#555555" /><!-- 6位密码框布局,需要一个圆角边框的shape作为layout的背景 --><LinearLayoutandroid: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设置大一点,否则“点”太小了,不美观 --><TextViewandroid: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" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#999999" /><TextViewandroid: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" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#999999" /><TextViewandroid: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" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#999999" /><TextViewandroid: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" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#999999" /><TextViewandroid: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" /><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#999999" /><TextViewandroid: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><!-- 忘记密码链接 --><TextViewandroid: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><!-- 输入键盘 --><GridViewandroid: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); //必须要,不然不显示控件}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic 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() {@Overridepublic int getCount() {return valueList.size();}@Overridepublic Object getItem(int position) {return valueList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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的点击响应问题 --><TextViewandroid: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 {@Overrideprotected 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() {@Overridepublic void inputFinish() {//输入完成后我们简单显示一下输入的密码//也就是说——>实现你的交易逻辑什么的在这里写Toast.makeText(MainActivity.this, pwdView.getStrPassword(), Toast.LENGTH_SHORT).show();}});/*** 可以用自定义控件中暴露出来的cancelImageView方法,重新提供相应* 如果写了,会覆盖我们在自定义控件中提供的响应* 可以看到这里toast显示 "Biu Biu Biu"而不是"Cancel"*/pwdView.getCancelImageView().setOnClickListener(new View.OnClickListener() {@Overridepublic 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"?><RelativeLayoutandroid: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.PasswordViewandroid:id="@+id/pwd_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"/></RelativeLayout> 
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。