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

</pre><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">我们先来照图分析一下:</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">(1)限制</span><span style="font-family: Arial; font-size: 14px; line-height: 26px;">输入</span><span style="font-family: Arial; font-size: 14px; line-height: 26px;">6位,每一位都有自己的框格,每个格显示一位;</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">(2)有回退/取消支付按钮;</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">(3)有忘记密码链接;</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">(4)自定义的只能输入数字的键盘输入区;</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">(5)</span><span style="font-family: Arial; font-size: 14px; line-height: 26px;">在6位输完后自动进行密码校验和支付交易。如上图左边是<a target=_blank target="_blank" href="http://lib.csdn.net/base/1" class="replace_word" title="Swift知识库" style="text-decoration: none; color: rgb(223, 52, 52); font-weight: bold;">iOS</a>支付宝支付密码输入控件,右边是我模仿实现的效果。</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;"></span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;">首先,我们需要一个页面来完成以上的静态布局,.xml代码如下:</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(85, 85, 85); font-family: "microsoft yahei"; font-size: 15px; line-height: 35px;"><span style="font-family: Arial; font-size: 14px; line-height: 26px;"></span><pre name="code" class="html"><?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>  




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值