Android自定义九宫格输入框

本文实例为大家分享了Android自定义九宫格输入框的具体代码,供大家参考,具体内容如下

效果

实现

  • 绘制宫格分割线

这里我们用一个RectF类型的数组来装载数据。在onSizeChanged方法中获取到控件尺寸,经过计算,将81个位置合适的矩形保存到数组中。

  • 绘制点击效果

onTouchEvent方法中监听手指离开事件,当手指离开,获取到当前点击区域的RectF,并将状态同样保存到一个数组中。

  • 绘制输入内容

输入内容利用onTextChanged方法获取,同样保存到一个数组中。

  • PS

控件中没有考虑UI重建数据保存问题,使用中要注意这点~~~

这三个数组中数据一一对应,在onDraw中,根据三个数组中数据内容绘制界面。完成我们的自定义View。

源码

/**
 * 自定义九宫格输入框
 * attrs: customTableLineColor  宫格分割线颜色
 * attrs: customTableLineWidth  宫格分割线宽度
 * attrs: customTablePressColor 宫格选中时背景颜色
 * attrs: customTableSpace      大宫格间隔
 * attrs: customTableTextColor  宫格输入文字颜色
 * attrs: customTableTextSize   宫格输入文字大小
 * attrs: customTableAngle      宫格圆角尺寸
 * 默认值请查看 {@link CustomEditText#initAttrs(Context, AttributeSet)}
 */
public class CustomEditText extends AppCompatEditText {
    private static final String TAG = "CustomEditText";
    //宫格位置
    private final RectF[] mTableList = new RectF[81];
    //宫格状态
    private final Boolean[] mTableState = new Boolean[81];
    //宫格数据
    private final Integer[] mTableListNumber = new Integer[81];
    //绘制宫格画笔
    private Paint mPaint;
    //绘制宫格背景画笔
    private Paint mBackgroundPaint;
    //绘制文字画笔
    private TextPaint mTextPaint;
    //手指离开屏幕X轴坐标
    private float mTouchX;
    //手指离开屏幕Y轴坐标
    private float mTouchY;
    //表格内文字尺寸
    private float mTextSize;
    //表格内文字颜色
    private int mTextColor;
    //表格分割线颜色
    private int mTableLineColor;
    //选中对应宫格背景颜色
    private int mTablePressColor;
    //表格分割线宽度
    private float mTableLineWidht;
    //大宫格间隔
    private float mTableSpace;
    //宫格圆角尺寸
    private float mTableAngle;

    public CustomEditText(Context context) {
        this(context, null);
    }

    public CustomEditText(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.editTextStyle);
    }

    public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initSet();
        initPaint();
    }

    /**
     * 初始化自定义属性
     */
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomEditText);
        mTextColor = typedArray.getColor(R.styleable.CustomEditText_customTableTextColor, Color.parseColor("#000000"));
        mTableLineColor = typedArray.getColor(R.styleable.CustomEditText_customTableLineColor, Color.parseColor("#000000"));
        mTablePressColor = typedArray.getColor(R.styleable.CustomEditText_customTablePressColor, Color.parseColor("#DDDDDD"));
        mTextSize = typedArray.getDimension(R.styleable.CustomEditText_customTableTextSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
        mTableLineWidht = typedArray.getDimension(R.styleable.CustomEditText_customTableLineWidth, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
        mTableSpace = typedArray.getDimension(R.styleable.CustomEditText_customTableSpace, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
        mTableSpace = typedArray.getDimension(R.styleable.CustomEditText_customTableSpace, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
        mTableAngle = typedArray.getDimension(R.styleable.CustomEditText_customTableAngle, 0);
        typedArray.recycle();
    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mBackgroundPaint = new Paint();
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setStyle(Paint.Style.FILL);
        mBackgroundPaint.setColor(mTablePressColor);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(mTableLineColor);
        mPaint.setStrokeWidth(mTableLineWidht);
        mPaint.setStyle(Paint.Style.STROKE);
        mTextPaint = new TextPaint();
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
    }

    /**
     * 初始化EditText基础设置
     */
    private void initSet() {
        //隐藏光标
        setCursorVisible(false);
        //设置输入类型
        setInputType(InputType.TYPE_CLASS_NUMBER);
        //限制输入一行
        setSingleLine(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < mTableList.length; i++) {
            RectF rectF = mTableList[i];
            if (mTableState[i]) {
                //绘宫格制背景
                canvas.drawRoundRect(rectF, mTableAngle, mTableAngle, mBackgroundPaint);
            }
            //绘制宫格分割线
            canvas.drawRoundRect(rectF, mTableAngle, mTableAngle, mPaint);
            Integer integer = mTableListNumber[i];
            if (integer != 0) {
                //测量文字尺寸
                Rect measureTextSize = measureTextSize(integer + "");
                //绘制输入内容
                canvas.drawText(integer + "", rectF.centerX(), rectF.centerY() + measureTextSize.height() / 2.0F, mTextPaint);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {//手指离开
            mTouchX = event.getX();
            mTouchY = event.getY();
            //检查输入内容和状态是否对应
            for (int i = 0; i < mTableListNumber.length; i++) {
                Integer integer = mTableListNumber[i];
                if (integer == 0) {
                    //背景应该为透明
                    if (mTableState[i]) {
                        mTableState[i] = false;
                    }
                }
            }
            //设置选中宫格
            for (int i = 0; i < mTableList.length; i++) {
                if (mTableList[i].contains(mTouchX, mTouchY)) {
                    mTableState[i] = true;
                    invalidate();
                    break;
                }
            }
        }
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            performClick();
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        String trim = text.toString().trim();
        if (!TextUtils.isEmpty(trim) && TextUtils.isDigitsOnly(trim)) {
            //保存输入内容
            if (trim.length() > 1) {
                trim = trim.substring(trim.length() - 1, trim.length());
            }
            for (int i = 0; i < mTableList.length; i++) {
                if (mTableList[i].contains(mTouchX, mTouchY)) {
                    mTableListNumber[i] = Integer.parseInt(trim);
                    //修改宫格背景状态
                    mTableState[i] = true;
                    //清空默认EditText输入内容
                    CustomEditText.this.setText("");
                    break;
                }
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //初始化宫格位置数据
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int measuredWidth = getMeasuredWidth();
        //表格实际显示的宽度
        int tableWidht = (int) (measuredWidth - mTableSpace * 2 - paddingLeft - paddingRight);
        //每个表格的宽度
        float singleTableWidth = tableWidht / 3.0F;
        for (int i = 0; i < 9; i++) {
            float top;
            float left;
            float bottom;
            float right;
            left = paddingLeft + (singleTableWidth * (i % 3)) + (mTableSpace * (i % 3));
            right = left + singleTableWidth;
            top = paddingTop + (singleTableWidth * (i / 3)) + (mTableSpace * (i / 3));
            bottom = top + singleTableWidth;
            //最大九个宫格的矩形
            RectF rectF = new RectF(left, top, right, bottom);
            float width = rectF.width();
            float singleTableWidthMin = width / 3.0F;
            for (int j = 0; j < 9; j++) {
                float topMin;
                float leftMin;
                float bottomMin;
                float rightMin;
                leftMin = singleTableWidthMin * (j % 3) + rectF.left;
                rightMin = leftMin + singleTableWidthMin;
                topMin = singleTableWidthMin * (j / 3) + rectF.top;
                bottomMin = topMin + singleTableWidthMin;
                //每个小宫格的矩形
                RectF rectFMin = new RectF(leftMin, topMin, rightMin, bottomMin);
                for (int k = 0; k < mTableList.length; k++) {
                    if (mTableList[k] == null) {
                        mTableList[k] = rectFMin;
                        mTableListNumber[k] = 0;
                        mTableState[k] = false;
                        break;
                    }
                }
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //强制控件为正方形
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }

    /**
     * 测量文字的尺寸
     *
     * @return 一个汉字的矩阵
     */
    private Rect measureTextSize(String content) {
        Rect mRect = null;
        if (!TextUtils.isEmpty(content)) {
            if (mTextPaint != null) {
                mRect = new Rect();
                mTextPaint.getTextBounds(content, 0, content.length(), mRect);
            }
        }
        return mRect;
    }
}

自定义属性

<resources>
    <declare-styleable name="CustomEditText">
        <attr name="customTableTextSize" format="dimension" />
        <attr name="customTableTextColor" format="color" />
        <attr name="customTableLineColor" format="color" />
        <attr name="customTableLineWidth" format="dimension" />
        <attr name="customTableSpace" format="dimension" />
        <attr name="customTablePressColor" format="color"/>
        <attr name="customTableAngle" format="integer"/>
    </declare-styleable>
</resources>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 解决Android软键盘弹出覆盖h5页面输入框问题

    之前我们在使用vue进行 h5 表单录入的过程中,遇到了Android软键盘弹出,覆盖 h5页面 输入框 问题,在此进行回顾并分享给大家: 系统:Android 条件:当输入框在可视区底部或者偏下的位置 触发条件:输入框获取焦点,弹出软键盘 表现:软键盘 覆盖 h5页面中的输入框 问题分析: 1.发现问题:当前页面中box为flex布局,内容为上下固定高,中间自适应(中间区域内容过多会出现滚动条,input框在wrapper的底部),input获取焦点,手机键盘弹出,input未上移到可视区内,

  • Android文本输入框(EditText)输入密码时显示与隐藏

    代码很简单,这里就不多废话了. 复制代码 代码如下: package cc.c; import android.app.Activity; import android.os.Bundle; import android.text.Selection; import android.text.Spannable; import android.text.method.HideReturnsTransformationMethod; import android.text.method.Passw

  • Android 自定义密码输入框实现代码

    效果 自定义密码输入框,项目的一个界面需求,我把这个自定义的输入框提取出来作为这次内容的题目. 输入前: 输入后: 输入1个字符就红一个圈圈,很简单的效果. 思路 1.自定义EditText. 2.背景为一个外圆环加内实心圆. 3.edittext的长度变化时候重新绘制背景或者红色环位置. 关键代码 代码其实也很简单,顺手拿资源的请到文末. 1.画背景 /** * 绘制背景外圆 */ private void drawOutRing(Canvas canvas) { mPaint.setColo

  • 5种方法完美解决android软键盘挡住输入框方法详解

    在开发中,经常会遇到键盘挡住输入框的情况,比如登录界面或注册界面,弹出的软键盘把登录或注册按钮挡住了,用户必须把软键盘收起,才能点击相应按钮,这样的用户体验非常不好.像微信则直接把登录按钮做在输入框的上面,但有很多情况下,这经常满足不了需求.同时如果输入框特别多的情况下,点击输入时,当前输入框没被挡住,但是当前输入框下面的输入框却无法获取焦点,必须先把键盘收起,再去获取下面输入框焦点,这样用户体验也非常不好,那有什么办法呢?  系统的adjustResize和adjustPan有什么区别,他们使

  • Android实现动态显示或隐藏密码输入框的内容

    本文实例展示了Android实现动态显示或隐藏密码输入框内容的方法,分享给大家供大家参考之用.具体方法如下: 该功能可通过设置EditText的setTransformationMethod()方法来实现隐藏密码或者显示密码. 示例代码如下: private Button mBtnPassword; private EditText mEtPassword; private boolean mbDisplayFlg = false; /** Called when the activity is

  • Android高级xml布局之输入框EditText设计

    今天给大家介绍一下如何实现一款简约时尚的安卓登陆界面.大家先看一下效果图 当用户输入时动态出现删除按钮 现在先罗列一下技术点: 1.如何使用圆角输入框和按钮背景 2.如何实现"手机号"."密码"后面的竖线 3.如何嵌套输入框的布局 4.如何监听输入框的输入事件及删除按钮的动态显示隐藏 1.如何使用圆角输入框和按钮背景 安卓为开发者准备了shape这个xml标签,用于自定义一些形状. 那么我就来定义一个白色的输入框背景.代码如下: <!-- 形状 -->

  • Android实现常见的验证码输入框实例代码

    前言 验证码输入框是很多APP必不可少的组件,之前在重构注册登录页面的时候,重新设计了UI,所以不能再简单的用EditText来做了,所以这篇文章将分享一下如何实现一个常见的验证码输入框.下面话不多说了,来一起看看详细的介绍吧. 正文 先搂一眼效果吧 不要把注意力都放在头顶的那一抹绿上,重点在输入框,可能大多数APP里都是采用6个方框的UI效果,我这里是按照我们设计的要求,用6根横线来划出6个数字的位置.一开始我想的是直接用6个TextView,然后传递焦点的做法,但是发现实现起来有一定的难度.

  • Android软键盘挡住输入框的终极解决方案

    前言 开发做得久了,总免不了会遇到各种坑. 而在Android开发的路上,『软键盘挡住了输入框』这个坑,可谓是一个旷日持久的巨坑--来来来,我们慢慢看. 入门篇 最基本的情况,如图所示:在页面底部有一个EditText,如果不做任何处理,那么在软键盘弹出的时候,就有可能会挡住EditText. 对于这种情况的处理其实很简单,只需要在AndroidManifest文件中对activity设置:android:windowSoftInputMode的值adjustPan或者adjustResize即

  • Android UI设计系列之自定义EditText实现带清除功能的输入框(3)

    最近公司的产品在陆续做升级,上级领导给的任务是优化代码结构以及项目架构,力争把项目写的精巧简练,于是我们满工程找冗余... 我们都知道每一个项目基本上都是有登陆页的,在登陆页中肯定是少不了输入框了,当我们在输入框中输入数据后如果输入的内容不正确或者是错误的或者是想重新输入,如果嗯键盘上的删除键就得一个一个的去删除,这时候我们或许就想要是能有一个标记当点击了这个标记能把我们刚刚输入的内容清空就好了.这样可以极大的提升用户体验,就拿QQ的登陆来说吧,效果如下: 当点击密码框右侧的小×图标时输入的内容

  • Android仿支付宝自定义密码输入框及安全键盘(密码键盘)

     0.前言 之前做过的项目里有运用到一个支付场景:用户办理业务时需要输入交易密码,并且可根据平台下发的支付方式进行选择.这与支付宝的密码输入方式十分相似,如果使用Android系统或者第三方软件的键盘,会有密码泄露的风险.因此,大多数的应用软件使用的是自定义的密码输入框及安全键盘. 由于密码输入方式需要实现一个从底部弹出的效果,因此总体上决定采用BottomSheetDialog来进行封装,同时为了提高安全性,还应该随机生成键盘上的数字,界面如下图所示:   首先新建一个PasswordInpu

随机推荐