zoukankan      html  css  js  c++  java
  • Android 高仿微信支付密码输入控件

      像微信支付密码控件,在app中是一个多么司空见惯的功能。最近,项目需要这个功能,于是乎就实现这个功能。

      老样子,投篮需要找准角度,变成需要理清思路。对于这个"小而美"的控件,我们思路应该这样子。

      Ⅰ、将要输入密码数量动态通过代码加载出来。

      Ⅱ、利用Gridview模拟产生一个输入数字键盘,并且按照习惯从屏幕底部弹出来。

      Ⅲ、对输入数字键盘进行事件监听,将这个输入数字填入到这个密码框中,并且当您输入密码长度一致的时候,进行事件回调。

      这个思维导图应该是这样的:

     

      首先,我们要根据需求动态加载密码框,相应的代码如下:

    for (int i = 0; i < 6; i++) {
                TextView textView = new TextView(context);
                android.widget.LinearLayout.LayoutParams layoutParams = new android.widget.LinearLayout.LayoutParams(
                        0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1);
                textView.setGravity(Gravity.CENTER);
                textView.setTransformationMethod(PasswordTransformationMethod.getInstance());
                textView.setTextSize(32);
                textView.setLayoutParams(layoutParams);
                ll_pwd.addView(textView);
                if (i != 5) {
                    View view2 = new View(context);
                    android.widget.LinearLayout.LayoutParams layoutParams1 = new android.widget.LinearLayout.LayoutParams(
                            1,
                            android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
                            0);
                    view2.setLayoutParams(layoutParams1);
                    view2.setBackgroundColor(Color.parseColor("#999999"));
                    ll_pwd.addView(view2);
    
                }
                tvList[i] = textView;
            }

      我们这里密码长度设置为6,将这6个密码框控件添加到盛放这些控件的父控件中去,并且每个密码控件中都有一个分隔控件。并且把每个密码输入控件放入控件数组,以便我们进行接下来的操作。

      然后了,我们利用Gridview产生一个12宫格的模拟数字键盘,这样模拟键盘样子是这样的:

      源代码应该是这样的:

         
           /**
         * 加载数据的代码
         */
        private void initData() {
            /* 初始化按钮上应该显示的数字 */
            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 == 11) {
                    map.put("name", String.valueOf(0));
                } else if (i == 12) {
                    map.put("name", "×");
                } else {
                    map.put("name", "");
                }
                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("");
                            }
                        }
                    }
                }
            });
        }
            /**
               * 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;
            }
    
            @SuppressWarnings("deprecation")
            @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||position==11) {
                    viewHolder.btnKey.setBackgroundDrawable(Utils.getStateListDrawable(context));
                    viewHolder.btnKey.setEnabled(false);
                }
                if (position == 11) {
                    viewHolder.btnKey.setBackgroundDrawable(Utils.getStateListDrawable(context));
                }
    
                return convertView;
            }
        };
        
        
        /**
         * 存放控件
         */
        public final class ViewHolder {
            public TextView btnKey;
        }    
                

      加载模拟键盘上的数据为0-9与x,然后将这个数据通过一个适配器将这些数据填充到这个Gridview控件。这些都是老司机的老套路。按照惯例,这个模拟键盘应该从屏幕的底部弹出,我这里所做的就是将Gridview依附在popupwindow,然后在从屏幕的底部进行弹出。相应的代码如下:

        View contentView = LayoutInflater.from(context).inflate(
                    R.layout.layout_popupdemo, null);// 定义后退弹出框
            gridView = (GridView) contentView.findViewById(R.id.gv_keybord);// 泡泡窗口的布局    
        popupWindow = new PopupWindow(contentView,
                    ViewGroup.LayoutParams.MATCH_PARENT,// width
    
                    ViewGroup.LayoutParams.WRAP_CONTENT);// higth
            popupWindow.setFocusable(false);
            popupWindow.setAnimationStyle(R.style.animation);
                //从底部弹出
      public void show() {
            popupWindow.showAtLocation(rl_bottom, Gravity.BOTTOM, 0, 0); // 确定在界面中出现的位置
        }
        @Override
        public void onWindowFocusChanged(boolean hasWindowFocus) {
            super.onWindowFocusChanged(hasWindowFocus);
            show();
        }

      当这个控件一加载的时候,就弹出。

      最后,我们要做的就是监听模拟键盘,将这个模拟键盘的输入填入到密码框,说的貌似很高大上的,其实就是监听Gridview的onitemclick事件,相应代码如下:

    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("");
                            }
                        }
                    }
                }
            });

      如果用户点击数字0-9,就填入到密码框中,如果是点击退格键的话,就删除所对应密码框的内容。看到没,上文所用文本框数组列表派上了用场。这里值得指出,由于退格键点击效果与众不同,我这里应用代码设置他的样式。

      当用户最后一个密码框输入完成之后,就进行输入完成的回调,相应代码为:

        // 设置监听方法,在第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();
                        }
                        if (pass!=null) {
                            pass.inputFinish(); // 接口中要实现的方法,完成密码输入完成后的响应逻辑                        
                        }
                    }
                }
            });

      经过一番折腾以后,大功告成了,最终效果如下:

      项目地址为:http://pan.baidu.com/s/1o88FK2A

  • 相关阅读:
    02_离线计算系统_第2天(HDFS详解)
    01_离线计算系统_第1天(HADOOP快速入门)
    01_离线计算系统_第1天(HADOOP快速入门)
    第4天 java高级特性增强 ---有用 第一遍
    038_字符串的转义
    037_标准化日期代码
    036_js中的字符串比较大小
    035_jQaury中的each()循环
    034_json对象字符串长什么样子?
    033_SpringMVC返回String,view,Object的原理
  • 原文地址:https://www.cnblogs.com/manuosex/p/5400550.html
Copyright © 2011-2022 走看看