安卓支付键盘三种方式优劣

苍老师带你们过圣诞

闲来无聊研究了下微信支付键盘,大致有三种实现方式

第一种

  • 自定义view实现,主要用到onDraw和onTouchEvent这两个,这种实现起来是真的烦,很少有人用这种方式,不推荐(大屌除外)

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        mCanvas = canvas;
        Log.d(TAG, "onDraw: width=" + width + "\theight=" + height);
        // 画竖线
        mPaint.setColor(Color.BLACK);
        mAvgWidth = width / WIDTH_LINES;
        for (int i = 1; i < WIDTH_LINES; i++) {
            canvas.drawLine(mAvgWidth * i, 0, mAvgWidth * i, height, mPaint);
        }
        // 画横线
        mAvgHeight = height / HEIGHT_LINES;
        for (int i = 0; i < HEIGHT_LINES; i++) {
            canvas.drawLine(0, mAvgHeight * i, width, mAvgHeight * i, mPaint);
        }
        // 画数字
        mPaint.setTextSize(40);
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        // 画1-3
        drawNum(1, 1, "1", fontMetrics);
        drawNum(1, 2, "2", fontMetrics);
        drawNum(1, 3, "3", fontMetrics);
        // 画4-6
        drawNum(2, 1, "4", fontMetrics);
        drawNum(2, 2, "5", fontMetrics);
        drawNum(2, 3, "6", fontMetrics);
        // 画7-9
        drawNum(3, 1, "7", fontMetrics);
        drawNum(3, 2, "8", fontMetrics);
        drawNum(3, 3, "9", fontMetrics);
        // 画底部
        drawNum(4, 2, "0", fontMetrics);
        mPaint.setColor(Color.GRAY);
        //        canvas.drawRect(0, mAvgHeight * 3, mAvgWidth, mAvgHeight * 4, mPaint);
        //        canvas.drawRect(mAvgWidth * 2, mAvgHeight * 3, mAvgWidth * 3, mAvgHeight * 4, mPaint);
//        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.back);
//        int bWidth = bitmap.getWidth();
//        int bHeight = bitmap.getHeight();
//        canvas.drawBitmap(bitmap, (float) (mAvgWidth * 2.5 - bWidth / 2), (float) (mAvgHeight * 3.5 - bHeight / 2), mPaint);
    }
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartX = event.getX();
                mStartY = event.getY();
                if (mStartX <= mAvgWidth) {
                    if (mStartY <= mAvgHeight) {
                        Log.d(TAG, "onTouchEvent: " + "1");
                    } else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
                        Log.d(TAG, "onTouchEvent: " + "4");
                    } else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
                        Log.d(TAG, "onTouchEvent: " + "7");
                    } else {
                        Log.d(TAG, "onTouchEvent: " + " ");
                    }
                } else if (mStartX > mAvgWidth && mStartX <= mAvgWidth * 2) {
                    if (mStartY <= mAvgHeight) {
                        Log.d(TAG, "onTouchEvent: " + "2");
                    } else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
                        Log.d(TAG, "onTouchEvent: " + "5");
                    } else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
                        Log.d(TAG, "onTouchEvent: " + "8");
                    } else {
                        Log.d(TAG, "onTouchEvent: " + "0");
                    }
                } else {
                    if (mStartY <= mAvgHeight) {
                        Log.d(TAG, "onTouchEvent: " + "3");
                    } else if (mStartY > mAvgHeight && mStartY <= mAvgHeight * 2) {
                        Log.d(TAG, "onTouchEvent: " + "6");
                    } else if (mStartY > mAvgHeight * 2 && mStartY <= mAvgHeight * 3) {
                        Log.d(TAG, "onTouchEvent: " + "9");
                    } else {
                        Log.d(TAG, "onTouchEvent: " + "删除");
                    }
                }
                //                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                mStartX = 0;
                mStartY = 0;
                //                invalidate();
                break;
        }
        return true;
    }

第二种

  • 用keyboard和keyboardview实现,这种的缺陷是,你按住4,然后移动到1或者7,他显示的是1或者7,很显然不符合微信这种,微信是移动到1或7的时候直接取消当前这个,不推荐(你个渣渣,肯定没找到相应的API)

  1. 在res下面创建xml包


  2. 创建keyboard.xml文件
<?xml version="1.0" encoding="utf-8"?>
<Keyboard
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="1dp"
    android:keyHeight="8%p"
    android:keyWidth="33.3333%p"
    android:verticalGap="1dp">

    <Row>
        <Key
            android:keyLabel="1"/>
        <Key
            android:keyLabel="2"/>
        <Key
            android:keyLabel="3"/>
    </Row>

    <Row>
        <Key
            android:keyLabel="4"/>
        <Key
            android:keyLabel="5"/>
        <Key
            android:keyLabel="6"/>
    </Row>

    <Row>
        <Key
            android:keyLabel="7"/>
        <Key
            android:keyLabel="8"/>
        <Key
            android:keyLabel="9"/>
    </Row>

    <Row>
        <Key
            android:codes="-10"
            android:keyLabel=""
            />
        <Key
            android:keyLabel="0"/>
        <Key
            android:codes="-5"
            android:isRepeatable="true"/>
    </Row>
</Keyboard>
  1. 自定义view继承KeyboardView
  • 绘制空格键和删除键
 @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        List<Keyboard.Key> keys = getKeyboard().getKeys();
        for (Keyboard.Key key : keys) {
            //绘制空白键
            if (key.codes[0] == KEYCODE_EMPTY) {
                drawKeyBackGround(key, canvas);
            } else if (key.codes[0] == Keyboard.KEYCODE_DELETE) {
                //绘制删除键背景
                drawKeyBackGround(key, canvas);
                //                //绘制按键图片
                drawkeyDelete(key, canvas);
            }
        }
        mCanvas = canvas;
    }

    private void drawKeyBackGround(Keyboard.Key key, Canvas canvas) {
        Drawable drawable = mContext.getResources().getDrawable(R.drawable.keyboard_empty);
        // 选择器效果
        int[] state = key.getCurrentDrawableState();
        drawable.setState(state);
        // TODO: 2017/12/21 减去key的间距,很难控制,而且有按键问题
        //        drawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
        drawable.setBounds(key.x, key.y + mSpace, key.x + key.width, key.y + key.height + mSpace);
        drawable.draw(canvas);
    }

    private void drawkeyDelete(Keyboard.Key key, Canvas canvas) {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, dm);
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 11, dm);
        int[] state = key.getCurrentDrawableState();
        mDeleteDrawable.setState(state);
        mDeleteDrawable.setBounds(key.x + width, key.y + height, key.x + key.width - width, key.y + key.height - height);
        mDeleteDrawable.draw(canvas);
    }
  • key的回调
@Override
    public void onKey(int primaryCode, int[] keyCodes) {
        Log.d(TAG, "onKey: " + primaryCode);
        if (primaryCode == Keyboard.KEYCODE_DELETE && mOnkeyPressListener != null) {
            if (mOnkeyPressListener != null) {
                mOnkeyPressListener.onDeleteKey();
            }
        } else if (primaryCode != KEYCODE_EMPTY) {
            if (mOnkeyPressListener != null) {
                Log.d(TAG, "数字: " + Character.toString((char) primaryCode));
                mOnkeyPressListener.onInertKey(Character.toString((char) primaryCode));
            }
        }
    }
  1. xml中布局
  <cn.gongwebo.payview.widget.KeyView
        android:id="@+id/keyview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:keyBackground="@drawable/keyboard_num"
        android:keyTextColor="@android:color/black"
        android:shadowColor="@color/white"
        android:shadowRadius="0.0"
        app:keyView_delete="@drawable/keyboard_delete"/>

需要注意的如果没有在KeyView设置以下两行代码,会导致字体模糊

第三种

  • 用ViewGroup添加,我认为是三种里面最符合微信的,推荐

  1. item的布局
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl"
    android:layout_width="match_parent"
    android:layout_height="60dp">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="18sp"
        tools:text="1"/>

    <!--头部的黑边-->
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/black"/>

    <!--右边的黑边-->
    <View
        android:id="@+id/view_right"
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="@color/black"/>

    <ImageView
        android:id="@+id/iv_delete"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_centerInParent="true"
        android:visibility="gone"
        tools:src="@drawable/delete_normal"/>
</RelativeLayout>
  1. 对item的操作
  @Override
    public void onBindViewHolder(KeyBoardViewHolder holder, int position) {
        final Integer code = mList.get(position);
        // 数字
        TextView tv = holder.tv;
        // 点击
        View view = holder.view;
        // 删除
        ImageView iv_delete = holder.iv_delete;
        iv_delete.setVisibility(code == DELETE ? View.VISIBLE : View.GONE);
        if (code == EMPTY) {
            view.setBackgroundResource(R.drawable.keyboard_empty);
        } else if (code == DELETE) {
            view.setBackgroundResource(R.drawable.keyboard_empty);
            iv_delete.setBackgroundResource(R.drawable.keyboard_delete);
        } else {
            view.setBackgroundResource(R.drawable.keyboard_num);
            tv.setText(mList.get(position) + "");
        }
        // 最右边的不显示
        if (holder.getPosition() % 3 == 2) {
            holder.view_right.setVisibility(View.GONE);
        }
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mKeyBoardAdapterListener != null) {
                    mKeyBoardAdapterListener.click(code);
                }
            }
        });
    }
  1. 动画效果
@OnClick({R.id.iv_close, R.id.fl_close, R.id.payview})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.iv_close:
                dismiss();
                break;
            case R.id.fl_close:
                if (!keyHide) {
                    Animation exit = AnimationUtils.loadAnimation(getActivity(), R.anim.exit_anim);
                    mLlKey.setAnimation(exit);
                    mLlKey.startAnimation(exit);
                    exit.setFillAfter(true);
                    keyHide = true;
                    // 影藏的时候要等动画执行完
                    exit.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {

                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            // 因为是补间动画所以把控件隐藏
                            mRv.setVisibility(View.GONE);
                            mFlClose.setVisibility(View.GONE);
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {

                        }
                    });
                }
                break;
            case R.id.payview:
                if (keyHide) {
                    Animation enter = AnimationUtils.loadAnimation(getActivity(), R.anim.enter_anim);
                    mLlKey.setAnimation(enter);
                    mLlKey.startAnimation(enter);
                    enter.setFillAfter(true);
                    keyHide = false;
                    // 因为是补间动画所以把控件显示
                    mRv.setVisibility(View.VISIBLE);
                    mFlClose.setVisibility(View.VISIBLE);
                }
                break;
        }
    }

传送门https://gitee.com/gongwenbo/payKeyboard.git

结尾:自己感觉有很多不足的地方,望大伙多多指点

我都看你怎么久了,不发言好意思吗!!!
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容