Android知识Android开发经验谈Android开发

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

2017-07-04  本文已影响506人  ayuhani

文章同步自 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,多写一些这方面的文章。

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

欢迎关注我的微信公众号
上一篇下一篇

猜你喜欢

热点阅读