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

 我们先来照图分析一下:

(1)限制输入6位,每一位都有自己的框格,每个格显示一位;

(2)有回退/取消支付按钮;

(3)有忘记密码链接;

(4)自定义的只能输入数字的键盘输入区;

(5)在6位输完后自动进行密码校验和支付交易。如上图左边是iOS支付宝支付密码输入控件,右边是我模仿实现的效果。


首先,我们需要一个页面来完成以上的静态布局,.xml代码如下:

  
  
  
      
  
          
  
              
              
  
              
          
  
          
  
          
          
  
              
              
  
              
  
              
  
              
  
              
  
              
  
              
  
              
  
              
  
              
  
              
          
  
          
          
      
  
      
      
  
  其中需要圆角背景shape_input_area.xml:
  
  
      
      
      
 
    需要数字按钮的背景selector_gride.xml:
  
  
      
          
              
          
      
      
          
              
          
      
      
          
              
          
      
  
  需要回退键背景selector_key_del.xml:
  
  
      
          
              
          
      
      
          
              
          
      
      
          
              
          
      
  
   下面来完成我们的自定义控件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> 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>();  
        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 map = new HashMap();  
            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:
  
  
  
      
      
 

  好了,到此我们的自定义控件——模仿支付宝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();  
//            }  
//        });  
        /************** 第二种用法————结束 ****************/  
    }  
}  

  在第一种方法中我们用到的布局文件:
  
  
  
      
 
安卓实现支付宝6位密码输入界面_第1张图片 安卓实现支付宝6位密码输入界面_第2张图片


你可能感兴趣的:(安卓开发)