Android自定义九宫格输入框

Android 自定义软键盘实现 数字九宫格 fillDate();// 一行3个单元格i++) {= null)// 单元格/**super();this.i = i;this.j = j;// 绘制一个单元格 如果颜色需要自定义可以修改。 阅读详情

在这里插入图片描述

效果

九宫格

实现

  • 绘制宫格分割线
    这里我们用一个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>
Vue3车牌号输入组件:模拟输入框+自定义键盘,自动识别新能源 在移动端H5表单中,车牌号输入是一个典型的特殊场景:字符结构固定、汉字/字母/数字混合,且不同车型(燃油车与新能源车)的位数不一。如果直接调用系统键盘,用户往往需要反复切换分页与输入法,体验极差。更可靠的方案是采用模拟输入框 + 自定义键盘的组件化设计:用 div 渲染车牌位,通过 JS 维护当前值与光标,按位置过滤 I/O 等非法字符,并在第 3 位输入 D/F 时自动切换为新能源绿牌样式。这种方案能从源头规避 iOS/Android 系统键盘的兼容性差异,减少输入步骤,同时提升整体流畅度。在车辆预约、缴 阅读详情

相关推荐

自定义微信小程序tabBar组件上边框的颜色

背景: 在微信小程序的实际开发过程中,有时候我们需要修改微信小程序提供的 tabBar 组件顶部边框的颜色,以满足项目需求 解决方案: 方式一: 通过tabBar组件自带的 borderStyle 属性来控制边框的颜色,将边框的颜色设置为白色,如下代码: "borderStyle":"white", 全部代码: app.json文件 "tabBar":{ "color":"#7B7E82", "selectedColor":"#333333", ...

郭宝的博客 4436

android中九宫格布局的实现

前段时间研究了下android中九宫格布局的实现。纵观现在的应用程序,九宫格是非常常见的一种布局方式。很多优秀的手机应用程序都采用了这一布局。下面就android中九宫格布局方式的实现和大家做一个简单的介绍。 首先是main.xml的布局方式如下: xml version="1.0" encoding="utf-8"?>  RelativeLayout  xmlns:android="ht

heirenheiren的专栏 2万+

深入探索安卓Android输入法开发——从源码到实现

用户自定义纠正词库可以显著提升输入法的个性化水平。例如,专业术语、网络新词或个人姓名等,标准词库中可能不存在,用户通过自定义词库可以快速输入这些词汇。在Android平台上,实现用户自定义纠正词库应用,需要设计存储结构来保存用户的自定义词汇,并在输入时进行匹配。简单的实现可以使用SharedPreferences或SQLite数据库来存储自定义词库数据。以下是一个使用SharedPreferences存储用户自定义词库的基本示例:// 将用户自定义词添加到词库。

weixin_42612405的博客 1905

android动态9宫格菜单,Android 九宫格的实现方法

1、xml代码:复制代码 代码如下:android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_weight="1.0"android:background="@drawable/yellow">android:layout_...

weixin_34469962的博客 2155

Android 自定义控件 EditText输入框两边加减按钮Button Demo

自己封装的一个EditText两边放加减按钮Button来控制输入框的数值

Android验证码输入框(超炫酷)

Android验证码输入框,炫酷的动画

Android studio 如何设计一个较为好看的用户名,密码输入框

欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的这里写代码片快捷键 相当于一个注册页面 ———- 快捷键 加粗 Ctrl +...

chengxunzun的博客 1万+

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

主要为大家详细介绍了Android高级xml布局之输入框EditText设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

Android开发: 美化输入框EditText

美化输入框代码

幼稚园六级学渣博客 5392

YOLOv5实战:无人机巡检图片差异对比与违建标记(附完整代码)

本文详细介绍了如何利用YOLOv5目标检测技术实现无人机巡检图片差异对比与违建标记。通过图像对齐、目标检测、差异分析和可视化标记四个步骤,构建高效的违建识别系统,显著提升城市管理效率。文章包含完整代码实现和性能优化技巧,为计算机视觉在无人机巡检中的应用提供实用指南。

weixin_42535720的博客 282

基于R语言的DICE模型实践技术应用;预测不同减排路径下的经济增长、碳排放量、气候变化程度以及社会福利变化

DICE模型是一个动态综合气候经济模型,由诺贝尔经济学奖得主William Nordhaus开发,用于评估气候变化对经济的影响以及不同减排政策的经济成本和效益。以下是一个关于DICE模型在气候变化影响评估中的实际应用案例,结合R语言代码进行讲解。

KY_chenzhao的博客 869

自定义输入密码控件

无

qq_23911165的博客 778

集成电路模拟版图入门-版图基础学习笔记(一)

集成电路设计模拟版图入门笔记,了解版图的定义、意义、工具、设计流程。认识版图及版图组成的两大部件,版图编辑器有哪些,电路图编辑器,了解工艺厂商等。

weixin_52955333的博客 2万+

Android密码字符为真,Android仿支付宝密码输入框与数字键盘

1.概述Android自定义密码输入框,通过自定义输入6位显示框和自定义9宫格数字键盘,实现仿支付宝数字键盘输入功能等。代码已托管到github,有需要的话可以去我的github下载。大家也可以自定义如下:关闭图标、文字内容、颜色、大小,弹框样式等。先看效果图:2.效果实现2.1. 拆分控件之标题栏包含一个关闭按钮,和一个标题文本,就是一个简单的ImageView和TextView,图标和文本(颜...

weixin_42533622的博客 378

9 HAL库驱动框架简述(STM32HAL库)

HAL库外设的使用步骤总结如下:1、定义并填充xxx外设句柄结构体。2、如果遵循HAL库规范,通过HAL_xxx_MspInit()函数,实现外设底层资源的初始化,包括但不限于GPIO、时钟、DMA、中断等资源的初始化。3、调用HAL库的对应外设初始化函数,形如:HAL_xxx_Init()。4、初始化完成,开始使用外设。5、使用方法具体查看对应外设的HAL库驱动包中的说明:补充:HAL库使用主线外设初始化外设使用。

qq_25218501的博客 1982

在 ABAP 平台上搭建 OAuth 2.0 Server:架构、流程、权限与落地实战

摘要:本文为SAP ABAP开发人员提供将ABAP平台配置为OAuth 2.0授权服务器的实战指南。重点介绍两种授权流程(授权码和SAML Bearer)的实现方案,包括核心事务配置(SOAUTH2/SAML2)、授权对象(S_SCOPE)管理以及端点交互规范。通过具体配置清单和三类典型集成场景(第三方Web应用访问OData、企业集成平台调用、BTP应用对接)的落地示例,帮助读者快速构建安全的OAuth 2.0服务架构。文档强调SSL/TLS基础安全、scope最小授权原则以及授权与令牌端点的标准交互模式

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 312

Android界面篇【android的九宫格式实现】

今天在devdiv论坛里看到有坛友问到九宫格的实现,我把我在项目中用的经验分享一下。 代码地址:http://download.youkuaiyun.com/detail/xyz_lmn/5151879 xml代码:      xmlns:app="http://schemas.android.com/apk/res/com.google.android.gx5wea

zhixiang2010的专栏 1511

uniapp - H5网页打包运行报错Failed to load resource: net::ERR_FILE_NOT_FOUND(uniApp打包成H5部署到服务器,打包h5白屏并报错页面空白)

Failed to load resource: net::ERR_FILE_NOT_FOUND,uniapp 坑之打包之后白屏,uniapp打包h5,HBuilderX 打包H5后空白报错 Failed to load resource: net::ERR FILE NOT_FOUND,UNI-APP H5应用白屏(空白页)解决方案,白屏并报错Failed to load resource: net::ERR_FILE_NOT_FOUND,uniapp开发,打包成H5部署到服务器,uniapp打包之后首页

🏆 前端领域优质创作者 3579

Android仿支付宝密码输入框(自定义数字键盘)

1.概述 Android自定义密码输入框,通过自定义输入显示框和自定义输入键盘,实现仿支付宝数字键盘等。代码已托管到github,有需要的话可以去我的github下载。 可以自定义关闭图标、文字内容、颜色、大小,弹框样式等。 先看效果图: 2.效果实现 2.1. 拆分控件之标题栏 包含一个关闭按钮,和一个标题文本,就是一个简单的ImageView和TextV...

小ぃぃ强 554

【C++/嵌入式梳理】bootloader

【C++/嵌入式笔试面试八股】bootloader

Hi 1210

多线程开发的基本概念

在Android开发中,我们常常会遇到多线程开发的需求。由于Android中的,我们不能在主线程处理耗时逻辑,否则会导致卡顿,甚至出现ANR(应用无响应)等异常情况。因此,我们需要将网络请求等耗时操作放到中去执行,完成后再更新UI。多线程开发因此成为Android开发中的一个重要部分。随着Android开发技术的不断进步,从早期的使用Handler,到后来的RxJava,再到如今的Kotlin协程,切换线程以及并发编程的代码写起来是越来越简洁了。

喻志强的博客 1020

【html5】input框默认调用九宫格数字键盘

&lt;input type="number" pattern="\d*"&gt;安卓默认可以调出九宫格但ios需要加上pattern="\d*"

Jerryman_GHJ的博客 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

android 拍摄视频后返回九宫格,抖音九宫格不同视频怎么拍 九个不同的视频在一个画面播放...

关于抖音怎么合拍这个问题,小编觉得这些类似抖音怎么无痕合拍?无缝视频合拍怎么弄?抖音合拍怎么弄三个画面?抖音视频上下互动怎么合拍等问题,都可以直接在抖音APP中实现痘印怎么合拍的问题,没有啥挑战性哦,所以小编要介绍的抖音9个人一起合拍怎么拍呢的问题,不是直接拍的哦,而是利用后期技术,制作制作无缝合拍视频哦,也就是九个不同的竖视频制作成九宫格视频,不是抖音怎么合拍视频哦,来看看吧!需要先通过上方的链...

weixin_29505163的博客 609

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

H5嵌入原生开发小结----兼容安卓与ios的填坑之路

一开始听说开发H5,以为就是做适配现代浏览器的移动网页,心想不用管IE了,欧也。到今天,发现当初too young too simple,兼容IE和兼容安卓与IOS,后者让你更抓狂。接下来数一下踩过的坑。主要分UI展示,键盘,输入框等等。解决bug最苦恼的问题不是没有解决方案,而是你没有找到真正的原因。再就是现象难以重现,每次都要发布代码,然后到手机app中去测试,模拟。这些地方会耗费大量的精力。

精选资讯文章 1654

Unity3D android 拉起android软键盘

Unity3D android 拉起android软键盘 最近公司项目有一个手机VR展厅业务,用U3D做VR场景还可以做到,后面要加个2D的线下预定页面,就涉及到3D 2D界面转换,首先考虑u3d作为插件,不考虑升级客户端,更新U3D资源来升级,所以PASS掉原生activity跳转方案,准备单独用U3D来实现2D界面,页面实现完成后发现U3D 的inputfield拉起android 软键盘会先...

weixin_42461528的博客 2456
上一篇: 初入公司,应该这样使用Git
下一篇: 助力Android开发者(持续更新)
Android师哥
博客等级 码龄10年 3粉丝 14原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值