美文网首页Android知识Android开发经验谈Android开发
Android 仿「微信」「支付宝」的支付密码布局

Android 仿「微信」「支付宝」的支付密码布局

作者: ayuhani | 来源:发表于2017-07-04 11:36 被阅读506次

    文章同步自 CSDN:http://blog.csdn.net/qq_24867873/article/details/74231623

    引言

    在上一篇文章 Android 仿「微信」自定义数字键盘 中,我们实现了自定义的数字键盘,这篇文章就在其基础上,简单实现微信和支付宝的支付布局(一定要先看上一篇文章)。实现效果:

    1. 密码输入布局的实现

    数字键盘已经有了,剩下的主要是密码输入的布局。这里想到了一个简单的思路,利用 6 个 ImageView 来显示小黑点就可以了,每次按下数字键显示一个小黑点,按下删除键则隐藏一个小黑点。

    布局文件非常简单,6 个横向排列的 FrameLayout 分别放入一个 ImageView,之后会给出源码。代码部分的实现:

    /**
     * 密码输入布局(6位密码)
     * Created by ayuhani on 2017/6/29.
     */
    public class PasswordView extends RelativeLayout {
    
        private String[] numbers;   // 用来保存输入的密码
        private ImageView[] points; // 用来保存每个小黑点
        private FrameLayout[] frameLayouts;
    
        public PasswordView(Context context) {
            this(context, null);
        }
    
        public PasswordView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            numbers = new String[6];
            points = new ImageView[6];
            frameLayouts = new FrameLayout[6];
    
            LayoutInflater.from(context).inflate(R.layout.layout_password, this);
            points[0] = findViewById(R.id.iv_0);
            points[1] = findViewById(R.id.iv_1);
            points[2] = findViewById(R.id.iv_2);
            points[3] = findViewById(R.id.iv_3);
            points[4] = findViewById(R.id.iv_4);
            points[5] = findViewById(R.id.iv_5);
    
            // 这里获取外层的FrameLayout,是因为之后要给它们添加点击事件
            frameLayouts[0] = findViewById(R.id.fl_0);
            frameLayouts[1] = findViewById(R.id.fl_1);
            frameLayouts[2] = findViewById(R.id.fl_2);
            frameLayouts[3] = findViewById(R.id.fl_3);
            frameLayouts[4] = findViewById(R.id.fl_4);
            frameLayouts[5] = findViewById(R.id.fl_5);
        }
    
        // 获取保存6位密码的数组
        public String[] getNumbers() {
            return numbers;
        }
    
        // 获取保存小黑点的数组
        public ImageView[] getPoints() {
            return points;
        }
    
        // 获取小黑点密码父布局的数组(用来添加点击事件)
        public FrameLayout[] getFrameLayouts() {
            return frameLayouts;
        }
    
        // 获取6位支付密码
        public String getPassword() {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < numbers.length; i++) {
                if (numbers[i] != null) {
                    builder.append(numbers[i]);
                }
            }
            return builder.toString();
        }
    
        // 清空密码
        public void clear() {
            for (int i = 0; i < numbers.length; i++) {
                numbers[i] = null;
            }
            for (int i = 0; i < points.length; i++) {
                points[i].setVisibility(GONE);
            }
        }
    }
    

    逻辑非常简单,注释写的也很详细了。接下来只需要与上篇文章写的数字键盘结合在一起,搭建一个类似微信支付的布局就可以了。

    2. 利用 PopupWindow 实现仿微信的支付布局

    同样的,xml 也不贴出来了,因为真的没有必要...... 搭完大概是这样子的:

    我们自定义类继承自 PopupWindow,关联上面的布局文件:

    /**
     * 仿微信支付布局
     * Created by ayuhani on 2017/6/29.
     */
    public class WeChatPayWindow extends PopupWindow implements KeyboardAdapter.OnKeyboardClickListener {
    
        private ImageView ivClose;  // 关闭按钮
        private ImageView ivIcon;   // 头像
        private TextView tvTitle;   // 标题
        private TextView tvMessage; // 消费详情
        private TextView tvPrice;   // 价格
        private PasswordView passwordView;
        private KeyboardView keyboardView;
        private List<String> datas;
        private String[] numbers;
        private ImageView[] points;
        private int currentIndex;   // 当前即将要输入密码的格子的索引
        public OnPasswordFinishedListener listener;
    
    
        public WeChatPayWindow(Context context) {
            super(context);
            init(context);
        }
    
        private void init(Context context) {
            View contentView = LayoutInflater.from(context).inflate(R.layout.layout_wechat_pay, null);
            setContentView(contentView);
            setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
            setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
            setFocusable(true);
            setClippingEnabled(false); // 让PopupWindow同样覆盖状态栏
            setBackgroundDrawable(new ColorDrawable(0xAA000000)); // 加上一层黑色透明背景
            initView(contentView);
        }
    
        private void initView(View contentView) {
            // 获取布局中的各个控件
            ivClose = contentView.findViewById(R.id.iv_close);
            ivIcon = contentView.findViewById(R.id.iv_icon);
            tvTitle = contentView.findViewById(R.id.tv_title);
            tvMessage = contentView.findViewById(R.id.tv_message);
            tvPrice = contentView.findViewById(R.id.tv_price);
            passwordView = contentView.findViewById(R.id.password_view);
            keyboardView = contentView.findViewById(R.id.keyboard_view);
            ivClose.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    dismiss();
                }
            });
            keyboardView.setOnKeyBoardClickListener(this);
            datas = keyboardView.getDatas();
            numbers = passwordView.getNumbers();
            points = passwordView.getPoints();
    
            // 这里给每个FrameLayout添加点击事件,当键盘被收起时点击空白输入框,再次弹出键盘
            // 微信也是这样的,但我觉得并没有什么意义
            for (int i = 0; i < passwordView.getFrameLayouts().length; i++) {
                final int finalI = i;
                passwordView.getFrameLayouts()[i].setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if (points[finalI].getVisibility() != View.VISIBLE && !keyboardView.isVisible()){
                            keyboardView.show();
                        }
                    }
                });
            }
        }
    
        // 可以自定义一些方法
        
        public WeChatPayWindow setIcon(String url) {
            // 设置头像
            return this;
        }
    
        public WeChatPayWindow setTitle(CharSequence title) {
            tvTitle.setText(title);
            return this;
        }
    
        public WeChatPayWindow setMessage(CharSequence message) {
            tvMessage.setText(message);
            return this;
        }
    
        public WeChatPayWindow setPrice(CharSequence price) {
            tvPrice.setText(price);
            return this;
        }
    
        // 弹出PopupWindow
        public void show(View rootView) {
            showAtLocation(rootView, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
        }
    
        @Override
        public void onKeyClick(View view, RecyclerView.ViewHolder holder, int position) {
            switch (position) {
                case 9: // 点击小数点没有作用,最好是把小数点隐藏掉,我这里偷懒了
                    break;
                default:
                    if (currentIndex >= 0 && currentIndex < numbers.length) {
                        numbers[currentIndex] = datas.get(position);
                        points[currentIndex].setVisibility(View.VISIBLE);
                        currentIndex++; // 当前位置的密码输入后,位置加一
    
                        if (currentIndex == numbers.length && listener != null) {
                            // 已经输入了六位数的密码了,回调方法
                            listener.onFinish(passwordView.getPassword());
                        }
                    }
            }
        }
    
        @Override
        public void onDeleteClick(View view, RecyclerView.ViewHolder holder, int position) {
            // 点击删除按钮
            if (currentIndex > 0 && currentIndex < numbers.length) {
                currentIndex--;
                numbers[currentIndex] = "";
                points[currentIndex].setVisibility(View.GONE);
            }
        }
    
        // 写一个回调接口,输入密码完成后调用
        public interface OnPasswordFinishedListener {
            void onFinish(String password);
        }
    
        public void setOnPasswordFinishedListener(OnPasswordFinishedListener listener) {
            this.listener = listener;
        }
    }
    

    在 Activity 里面显示就可以了。动态图:

    3. 仿支付宝支付布局的实现

    支付宝支付时有选择支付方式、指纹支付等高级功能,我这里则只是简单的实现了密码输入,和上面的实现一样,只是布局不同,所以我也不贴代码了,直接看效果吧:

    思路很简单,实现起来也不麻烦~ 这篇文章就到此结束了,之后打算好好学习自定义 View,多写一些这方面的文章。

    ->->->点击下载源码<-<-<-

    欢迎关注我的微信公众号

    相关文章

      网友评论

        本文标题:Android 仿「微信」「支付宝」的支付密码布局

        本文链接:https://www.haomeiwen.com/subject/hoithxtx.html