Android实现支付宝6位密码输入界面
我们先来照图分析一下:
(1)限制输入6位,每一位都有自己的框格,每个格显示一位;
(2)有回退/取消支付按钮;
(3)有忘记密码链接;
(4)自定义的只能输入数字的键盘输入区;
(5)在6位输完后自动进行密码校验和支付交易。如上图左边是iOS支付宝支付密码输入控件,右边是我模仿实现的效果。
首先,我们需要一个页面来完成以上的静态布局,.xml代码如下:
<?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns: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:
<?xmlversion="1.0"encoding="utf-8"?> <shapexmlns:android="http://schemas.android.com/apk/res/android"> <cornersandroid:radius="5dp"/> <strokeandroid:color="@android:color/darker_gray" android:width="1dp"/> <solidandroid:color="@android:color/white"/> </shape>
需要数字按钮的背景selector_gride.xml:
<?xmlversion="1.0"encoding="utf-8"?> <selectorxmlns:android="http://schemas.android.com/apk/res/android"> <itemandroid:state_enabled="false"> <shape> <solidandroid:color="#C0C4C7"/> </shape> </item> <itemandroid:state_enabled="true"android:state_pressed="false"> <shape> <solidandroid:color="@android:color/white"/> </shape> </item> <itemandroid:state_enabled="true"android:state_pressed="true"> <shape> <solidandroid:color="#C0C4C7"/> </shape> </item> </selector>
需要回退键背景selector_key_del.xml:
<?xmlversion="1.0"encoding="utf-8"?> <selectorxmlns:android="http://schemas.android.com/apk/res/android"> <itemandroid:state_enabled="false"> <shape> <solidandroid:color="#C0C4C7"/> </shape> </item> <itemandroid:state_enabled="true"android:state_pressed="false"> <shape> <solidandroid:color="#C0C4C7"/> </shape> </item> <itemandroid:state_enabled="true"android:state_pressed="true"> <shape> <solidandroid:color="@android:color/white"/> </shape> </item> </selector>
下面来完成我们的自定义控件PasswordView.Java:
publicclassPasswordViewextendsRelativeLayoutimplementsView.OnClickListener{
Contextcontext;
privateStringstrPassword;//输入的密码
privateTextView[]tvList;//用数组保存6个TextView,为什么用数组?
//因为就6个输入框不会变了,用数组内存申请固定空间,比List省空间(自己认为)
privateGridViewgridView;//用GrideView布局键盘,其实并不是真正的键盘,只是模拟键盘的功能
privateArrayList<Map<String,String>>valueList;//有人可能有疑问,为何这里不用数组了?
//因为要用Adapter中适配,用数组不能往adapter中填充
privateImageViewimgCancel;
privateTextViewtvForget;
privateintcurrentIndex=-1;//用于记录当前输入密码格位置
publicPasswordView(Contextcontext){
this(context,null);
}
publicPasswordView(Contextcontext,AttributeSetattrs){
super(context,attrs);
this.context=context;
Viewview=View.inflate(context,R.layout.layout_popup_bottom,null);
valueList=newArrayList<Map<String,String>>();
tvList=newTextView[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
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.img_cancel:
Toast.makeText(context,"Cancel",Toast.LENGTH_SHORT).show();
break;
caseR.id.tv_forgetPwd:
Toast.makeText(context,"Forget",Toast.LENGTH_SHORT).show();
break;
}
}
privatevoidsetView(){
/*初始化按钮上应该显示的数字*/
for(inti=1;i<13;i++){
Map<String,String>map=newHashMap<String,String>();
if(i<10){
map.put("name",String.valueOf(i));
}elseif(i==10){
map.put("name","");
}elseif(i==12){
map.put("name","<<-");
}elseif(i==11){
map.put("name",String.valueOf(0));
}
valueList.add(map);
}
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(newAdapterView.OnItemClickListener(){
@Override
publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
if(position<11&&position!=9){//点击0~9按钮
if(currentIndex>=-1&¤tIndex<5){//判断输入位置————要小心数组越界
tvList[++currentIndex].setText(valueList.get(position).get("name"));
}
}else{
if(position==11){//点击退格键
if(currentIndex-1>=-1){//判断是否删除完毕————要小心数组越界
tvList[currentIndex--].setText("");
}
}
}
}
});
}
//设置监听方法,在第6位输入完成后触发
publicvoidsetOnFinishInput(finalOnPasswordInputFinishpass){
tvList[5].addTextChangedListener(newTextWatcher(){
@Override
publicvoidbeforeTextChanged(CharSequences,intstart,intcount,intafter){
}
@Override
publicvoidonTextChanged(CharSequences,intstart,intbefore,intcount){
}
@Override
publicvoidafterTextChanged(Editables){
if(s.toString().length()==1){
strPassword="";//每次触发都要先将strPassword置空,再重新获取,避免由于输入删除再输入造成混乱
for(inti=0;i<6;i++){
strPassword+=tvList[i].getText().toString().trim();
}
pass.inputFinish();//接口中要实现的方法,完成密码输入完成后的响应逻辑
}
}
});
}
/*获取输入的密码*/
publicStringgetStrPassword(){
returnstrPassword;
}
/*暴露取消支付的按钮,可以灵活改变响应*/
publicImageViewgetCancelImageView(){
returnimgCancel;
}
/*暴露忘记密码的按钮,可以灵活改变响应*/
publicTextViewgetForgetTextView(){
returntvForget;
}
//GrideView的适配器
BaseAdapteradapter=newBaseAdapter(){
@Override
publicintgetCount(){
returnvalueList.size();
}
@Override
publicObjectgetItem(intposition){
returnvalueList.get(position);
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
ViewHolderviewHolder;
if(convertView==null){
convertView=View.inflate(context,R.layout.item_gride,null);
viewHolder=newViewHolder();
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);
}
returnconvertView;
}
};
/**
*存放控件
*/
publicfinalclassViewHolder{
publicTextViewbtnKey;
}
}
自认为代码注释还是可以的。就是在实现过程中要注意数组的越界问题,在输入逻辑响应中要注意逻辑处理,也就是grideView的OnItemClickListener事件处理。其中用到自定义的接口OnPasswordInputFinish来实现输入完成的事件回掉:
/**
*BelongtotheProject——MyPayUI
*CreatedbyWangJon2015/11/2517:15.
*
*自定义接口,用于给密码输入完成添加回掉事件
*/
publicinterfaceOnPasswordInputFinish{
voidinputFinish();
}
还有就是Adapter中用到的每个按钮Item的布局item_gride.xml:
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns: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中用用一下我们定义好的控件:
publicclassMainActivityextendsActivity{
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
/*************第一种用法————开始***************/
setContentView(R.layout.activity_main);
finalPasswordViewpwdView=(PasswordView)findViewById(R.id.pwd_view);
//添加密码输入完成的响应
pwdView.setOnFinishInput(newOnPasswordInputFinish(){
@Override
publicvoidinputFinish(){
//输入完成后我们简单显示一下输入的密码
//也就是说——>实现你的交易逻辑什么的在这里写
Toast.makeText(MainActivity.this,pwdView.getStrPassword(),Toast.LENGTH_SHORT).show();
}
});
/**
*可以用自定义控件中暴露出来的cancelImageView方法,重新提供相应
*如果写了,会覆盖我们在自定义控件中提供的响应
*可以看到这里toast显示"BiuBiuBiu"而不是"Cancel"*/
pwdView.getCancelImageView().setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
Toast.makeText(MainActivity.this,"BiuBiuBiu",Toast.LENGTH_SHORT).show();
}
});
/************第一种用法————结束******************/
/*************第二种用法————开始*****************/
//finalPasswordViewpwdView=newPasswordView(this);
//setContentView(pwdView);
//pwdView.setOnFinishInput(newOnPasswordInputFinish(){
//@Override
//publicvoidinputFinish(){
//Toast.makeText(MainActivity.this,pwdView.getStrPassword(),Toast.LENGTH_SHORT).show();
//}
//});
/**************第二种用法————结束****************/
}
}
在第一种方法中我们用到的布局文件:
<?xmlversion="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密码使用教程
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。