android自定义数字键盘

转载 2018年04月17日 10:15:28

前言

最近需要做一个自定义的数字键盘,开始使用了下系统自带的KeyBoardView,但是发现UI效果不是很理想,最后还是自己画一个自定义键盘,这样在UI方面更加方便。先看效果图吧:

这里写图片描述

思路

1.键盘4行*3列的布局分为12个单元格,6条直线分隔单元格。根据单元格宽高确定数字位置。
2.点击效果根据用户按下和抬起动作做不同标记。

思路说的有点模糊,直接看代码吧,代码里的注释很详细:

实现

1:自定义view–CustomNumKeyView

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CustomNumKeyView extends View {
    /**
     * 列
     */
    private static final int TOTAL_COL = 3;
    /**
     * 行
     */
    private static final int TOTAL_ROW = 4;

    private Paint HuiseBgPaint, linePaint;
    private Paint mTextPaint;
    private int mViewWidth; // 键盘宽度
    private int mViewHight; // 键盘高度
    private float mCellWidth, mCellHight; // 单元格宽度、高度
    private Row rows[] = new Row[TOTAL_ROW];
    private Bitmap bitmap; // 删除按钮图片

    public interface CallBack {
        void clickNum(String num);// 回调点击的数字
        void deleteNum();// 回调删除
    }

    private CallBack mCallBack;// 回调

    public void setOnCallBack(CallBack callBack) {
        mCallBack = callBack;
    }

    public CustomNumKeyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);

    }

    public CustomNumKeyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);

    }

    public CustomNumKeyView(Context context) {
        super(context);
        init(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawLine(canvas);
        for (int i = 0; i < TOTAL_ROW; i++) {
            if (rows[i] != null)
                rows[i].drawCells(canvas);
        }
    }

    /**
     * 画6条直线
     * @param canvas
     */
    private void drawLine(Canvas canvas) {
        canvas.drawLine(0, 0, mViewWidth, 0, linePaint);
        canvas.drawLine(0, mCellHight, mViewWidth, mCellHight, linePaint);
        canvas.drawLine(0, mCellHight * 2, mViewWidth, mCellHight * 2, linePaint);
        canvas.drawLine(0, mCellHight * 3, mViewWidth, mCellHight * 3, linePaint);
        canvas.drawLine(mCellWidth, 0, mCellWidth, mViewHight, linePaint);
        canvas.drawLine(mCellWidth * 2, 0, mCellWidth * 2, mViewHight, linePaint);


    }

    /**
     * 初始化画笔
     * @param canvas
     */
    private void init(Context context) {
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCutTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setTextSize(1.0f);
        linePaint.setColor(0x90000000);

        HuiseBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        HuiseBgPaint.setStyle(Paint.Style.FILL);
        HuiseBgPaint.setColor(Color.parseColor("#e9e9e9"));

        initDate();
    }

    private void initDate() {
        fillDate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHight = h;
        mCellWidth = mViewWidth / TOTAL_COL;
        mCellHight = mViewHight / TOTAL_ROW;
        mTextPaint.setTextSize(mCellHight / 3);

    }

    private Cell mClickCell = null;
    private float mDownX;
    private float mDownY;

    /*
     *
     * 触摸事件为了确定点击位置的数字
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownX = event.getX();
                mDownY = event.getY();
                int col = (int) (mDownX / mCellWidth);
                int row = (int) (mDownY / mCellHight);
                measureClickCell(col, row);
                break;
            case MotionEvent.ACTION_UP:
                if (mClickCell != null) {
                    // 在抬起后把状态置为默认
                    rows[mClickCell.i].cells[mClickCell.j].state = State.DEFAULT_NUM;
                    mClickCell = null;
                    invalidate();
                }
                break;
        }
        return true;
    }

    /**
     * 测量点击单元格
     * @param col 列
     * @param row 行
     */
    private void measureClickCell(int col, int row) {
        if (col >= TOTAL_COL || row >= TOTAL_ROW)
            return;
        if (rows[row] != null) {
            mClickCell = new Cell(rows[row].cells[col].num, rows[row].cells[col].state, rows[row].cells[col].i,
                    rows[row].cells[col].j);
            rows[row].cells[col].state = State.CLICK_NUM;
            if ("-5".equals(rows[row].cells[col].num)) {
                mCallBack.deleteNum();
            } else {
                mCallBack.clickNum(rows[row].cells[col].num);
            }
            invalidate();
        }
    }

    /**
     * 组 以一行为一组
     */
    private class Row {
        public int j;

        Row(int j) {
            this.j = j;
        }

        // 一行3个单元格
        public Cell[] cells = new Cell[TOTAL_COL];

        public void drawCells(Canvas canvas) {
            for (int i = 0; i < cells.length; i++) {
                if (cells[i] != null)
                    cells[i].drawSelf(canvas);
            }

        }
    }

    // 单元格
    private class Cell {
        public String num;
        public State state;
        /**
         * i = 行 j = 列
         */
        public int i;
        public int j;

        public Cell(String num, State state, int i, int j) {
            super();
            this.num = num;
            this.state = state;
            this.i = i;
            this.j = j;
        }

        // 绘制一个单元格 如果颜色需要自定义可以修改
        public void drawSelf(Canvas canvas) {
            switch (state) {
                case CLICK_NUM:
                    // 绘制点击效果灰色背景
                    canvas.drawRect((float) (mCellWidth * j), (float) (mCellHight * i),
                            (float) (mCellWidth * (j + 1)), (float) (mCellHight * (i + 1)), HuiseBgPaint);
                    break;
            }
            if ("-5".equals(num)) {
                // 绘制删除图片
                canvas.drawBitmap(bitmap, (float) (mCellWidth * 2.5 - bitmap.getWidth() / 2), (float) (mCellHight * 3.5 - bitmap.getHeight() / 2), HuiseBgPaint);
            } else {
                // 绘制数字
                canvas.drawText(num, (float) ((j + 0.5) * mCellWidth - mTextPaint.measureText(num) / 2),
                        (float) ((i + 0.5) * mCellHight + mTextPaint.measureText(num, 0, 1) / 2),
                        mTextPaint);
            }


        }
    }

    /**
     *  cell的state
     */
    private enum State {
        DEFAULT_NUM, CLICK_NUM;
    }

    private List<String> numKeys = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "0");

    /**
     * 填充数字
     */
    private void fillDate() {
        int postion = 0;
        for (int i = 0; i < TOTAL_ROW; i++) {
            rows[i] = new Row(i);
            for (int j = 0; j < TOTAL_COL; j++) {
                if (i == 3 && j == 0) {
                    rows[i].cells[j] = new Cell(".", State.DEFAULT_NUM, i, j);
                    continue;
                } else if (i == 3 && j == 2) {
                    rows[i].cells[j] = new Cell("-5", State.DEFAULT_NUM, i, j);
                    continue;
                } else {
                    rows[i].cells[j] = new Cell(numKeys.get(postion), State.DEFAULT_NUM, i, j);
                    postion++;
                }
            }
        }
        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_cancel);
    }

    /**
     * 随机键盘
     * @param isRandom
     */
    public void setRandomKeyBoard(boolean isRandom) {
        if (isRandom) {
            Collections.shuffle(numKeys);
            initDate();
            invalidate();
        }
    }

}

这里主要就是要注意单元格的绘制坐标,代码应该很好理解。

键盘已经画好,接下来就是使用了:

2.MainActivity

package net.yangming.numkeyboard;

import android.graphics.drawable.ColorDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.InputType;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.PopupWindow;

public class MainActivity extends AppCompatActivity implements NumKeyView.OnKeyPressListener, CustomNumKeyView.CallBack {
    private EditText mEditText;
    private NumKeyView mKeyView;
    private CustomNumKeyView mCustomKeyView;
    private LinearLayout mLinearlayout;
    private PopupWindow mPop;
    private View mPopView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mLinearlayout = (LinearLayout) findViewById(R.id.linear);
        mEditText = (EditText) findViewById(R.id.edit);
        // 设置不弹出系统键盘
        mEditText.setInputType(InputType.TYPE_NULL);
        // 自己监听EditText的点击事件弹出我们自定义的键盘
        mEditText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mPop.showAtLocation(mLinearlayout, Gravity.BOTTOM, 0, 0);
            }
        });
        mPop = new PopupWindow();
//        mCustomKeyView=new CustomNumKeyView(this);
        mPopView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.custom_keyboardview, null);
        mPop.setContentView(mPopView);
        mPop.setTouchable(true);
        mPop.setFocusable(true);
        mPop.setBackgroundDrawable(new ColorDrawable());
        mPop.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        mPop.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        mCustomKeyView = (CustomNumKeyView) mPopView.findViewById(R.id.keyboardview);
        // 设置回调,并进行文本的插入与删除
        mCustomKeyView.setOnCallBack(this);
    }

    public void OnButtonClick(View view) {
        switch (view.getId()) {
            case R.id.btn_default:
                mCustomKeyView.setRandomKeyBoard(false);
                break;
            case R.id.btn_random:
                // 设置随机数字键盘
                mCustomKeyView.setRandomKeyBoard(true);
                break;
        }
    }

    @Override
    public void clickNum(String num) {
        if (mEditText.getText().length() < 6) {
            mEditText.append(num);
            //文本长度为6时隐藏键盘
            if (mEditText.getText().length() == 6) {
                mPop.dismiss();
            }
        }
    }

    @Override
    public void deleteNum() {
        int last = mEditText.getText().length();
        if (last > 0) {
            //删除最后一位
            mEditText.getText().delete(last - 1, last);
        }
    }
}

3.custom_keyboardview

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <net.yangming.numkeyboard.CustomNumKeyView
        android:id="@+id/keyboardview"
        android:layout_width="match_parent"
        android:layout_height="200dp" />
</LinearLayout>

好了,自定义键盘就完成了 >_<

ps:
我这里只是做了最简单的键盘,主要是讲解实现的方法和思路。你们可以根据自己的需求画出不同的UI效果和点击效果。

Android 仿「微信」自定义数字键盘

最终效果:实现这个自定义键盘的思路很简单: 1. 要写出一个数字键盘的布局; 2. 与 Edittext 结合使用,对每个按键的点击事件进行处理; 3. 禁用系统软键盘。有了思路,实现起来就不难...
  • qq_24867873
  • qq_24867873
  • 2017-06-27 10:43:37
  • 1080

android 纯自定义数字键盘输入

  • 2017年06月30日 10:52
  • 19.63MB
  • 下载

android 自定义纯数字键盘输入

很久没更新博客了,最近在做一个新项目,遇到了很多坑,现将遇到的坑学到的东西一个个记录下来,方便自己和大家共同学习。后面还会抽出时间将项目中遇到的其他问题一一上传分析。项目中需要使用自定义数字键盘输入金...
  • LiuWaiter
  • LiuWaiter
  • 2017-06-30 10:59:13
  • 1083

Android 自定义数字键盘(三)自定义输入框

Android 自定义数字键盘(一) Android 自定义数字键盘(二)随机数字 Demo地址:https://github.com/danfengfirst/KeyDemo 这篇博客是...
  • danfengw
  • danfengw
  • 2016-12-27 17:05:04
  • 2404

Android 自定义数字键盘(一)

看了一个自定义键盘的Demo感觉比网上那种自己绘制的那种要方便很多,就学习了一下,刚开始觉得应该挺麻烦的,还继承一个KeyBoardView,不过学习完了觉得还好,至少还能看懂,另外感觉收获还是挺多的...
  • danfengw
  • danfengw
  • 2016-12-22 18:11:50
  • 3814

Android自定义数字键盘

好久没有写Android的文章了,有两三个月多了吧,刚开始搞微信小程序,后来又开搞ReactNative,现在又兴奋的开搞AI机器学习的东西,感觉挺有意思的,不过AI与其它的东西相比要难很多,需要补很...
  • xiehuimx
  • xiehuimx
  • 2017-09-09 21:35:58
  • 1014

Android自定义数字键盘(支持随机数字)

前言也是最近想写个demo玩玩,不知道写哪个方面的好,就随便写了一个自定义的键盘,比较简单,但是做了封装,支持jitpack库依赖(这也是我一次开源自己的库,比较水的一个开源项目,仅供学习使用)。概述...
  • Simon_Crystin
  • Simon_Crystin
  • 2017-09-06 15:49:49
  • 1226

Android 自定义数字键盘(二)随机数字

先看Android 自定义数字键盘(一) 将下面部分代码复制到自定义的继承KeyboardView的类里面,使用时设置是否为true就可以了private List keylabels= Array...
  • danfengw
  • danfengw
  • 2016-12-23 11:02:50
  • 1317

android自定义view(自定义数字键盘)

序言:在上周的项目中,需要做一个密码锁的功能,然后密码下面还得有键盘,就类似支付宝支付的时候那样:当然了,我们项目的需求简单点,纯数字的就可以了,然后上周就百度了自定义键盘,随便找了一个修改修改就用到...
  • lovecyg123
  • lovecyg123
  • 2017-02-05 17:46:20
  • 790

android自定义控件-----自定义数字价格键盘

饿饿,好久没写android了,最近看到数字价格键盘挺有意思的就写来玩玩,省的做游戏java方面都要手生了!(话不多说,开始了)首先给图吧(绅士礼仪0。0)数字随机键盘价格数字键盘全键盘一、画键盘的x...
  • li15225271052
  • li15225271052
  • 2017-08-27 18:01:04
  • 654
收藏助手
不良信息举报
您举报文章:android自定义数字键盘
举报原因:
原因补充:

(最多只允许输入30个字)