Android自定义密码输入框和数字键盘
作者:ganchuanpu 发布时间:2022-02-04 11:14:00
标签:Android,输入框,数字键盘
实现了一个自定义的密码输入框和自定义数字键盘,用作用户支付密码设置界面。先上效果图如下,方格样式,以及点击空白处隐藏软键盘。
控件实现清单:
1)集成于EditText的输入框控件:PasswordInputView.java
2)数字键盘工具类:NumKeyboardUtil.java
3)xml文件:number.xml
4)attrs样式
5)layout文件
具体内容:
PasswordInputView.java
public class PasswordInputView extends EditText{
private int textLength;
private int borderColor;
private float borderWidth;
private float borderRadius;
private int passwordLength;
private int passwordColor;
private float passwordWidth;
private float passwordRadius;
private Paint passwordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final int defaultSplitLineWidth = 1;
public PasswordInputView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = getResources();
final int defaultBorderColor = res.getColor(R.color.line_color);
final float defaultBorderWidth = res.getDimension(R.dimen.dimen_1px);
final float defaultBorderRadius = res.getDimension(R.dimen.dimen_6);
final int defaultPasswordLength = 6;
final int defaultPasswordColor = res.getColor(R.color.normal_text_color);
final float defaultPasswordWidth = res.getDimension(R.dimen.dimen_6);
final float defaultPasswordRadius = res.getDimension(R.dimen.dimen_6);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordInputView, 0, 0);
try {
borderColor = a.getColor(R.styleable.PasswordInputView_borderColor, defaultBorderColor);
borderWidth = a.getDimension(R.styleable.PasswordInputView_borderWidth, defaultBorderWidth);
borderRadius = a.getDimension(R.styleable.PasswordInputView_borderRadius, defaultBorderRadius);
passwordLength = a.getInt(R.styleable.PasswordInputView_passwordLength, defaultPasswordLength);
passwordColor = a.getColor(R.styleable.PasswordInputView_passwordColor, defaultPasswordColor);
passwordWidth = a.getDimension(R.styleable.PasswordInputView_passwordWidth, defaultPasswordWidth);
passwordRadius = a.getDimension(R.styleable.PasswordInputView_passwordRadius, defaultPasswordRadius);
} finally {
a.recycle();
}
borderPaint.setStrokeWidth(borderWidth);
borderPaint.setColor(borderColor);
passwordPaint.setStrokeWidth(passwordWidth);
passwordPaint.setStyle(Paint.Style.FILL);
passwordPaint.setColor(passwordColor);
setSingleLine(true);
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
// 分割线
borderPaint.setColor(borderColor);
borderPaint.setStrokeWidth(defaultSplitLineWidth);
for (int i = 1; i < passwordLength; i++) {
float x = width * i / passwordLength;
canvas.drawLine(x, 0, x, height, borderPaint);
}
// 密码
float cx, cy = height/ 2;
float half = width / passwordLength / 2;
for(int i = 0; i < textLength; i++) {
cx = width * i / passwordLength + half;
canvas.drawCircle(cx, cy, passwordWidth, passwordPaint);
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
this.textLength = text.toString().length();
invalidate();
}
public int getBorderColor() {
return borderColor;
}
public void setBorderColor(int borderColor) {
this.borderColor = borderColor;
borderPaint.setColor(borderColor);
invalidate();
}
public float getBorderWidth() {
return borderWidth;
}
public void setBorderWidth(float borderWidth) {
this.borderWidth = borderWidth;
borderPaint.setStrokeWidth(borderWidth);
invalidate();
}
public float getBorderRadius() {
return borderRadius;
}
public void setBorderRadius(float borderRadius) {
this.borderRadius = borderRadius;
invalidate();
}
public int getPasswordLength() {
return passwordLength;
}
public void setPasswordLength(int passwordLength) {
this.passwordLength = passwordLength;
invalidate();
}
public int getPasswordColor() {
return passwordColor;
}
public void setPasswordColor(int passwordColor) {
this.passwordColor = passwordColor;
passwordPaint.setColor(passwordColor);
invalidate();
}
public float getPasswordWidth() {
return passwordWidth;
}
public void setPasswordWidth(float passwordWidth) {
this.passwordWidth = passwordWidth;
passwordPaint.setStrokeWidth(passwordWidth);
invalidate();
}
public float getPasswordRadius() {
return passwordRadius;
}
public void setPasswordRadius(float passwordRadius) {
this.passwordRadius = passwordRadius;
invalidate();
}
}
NumKeyboardUtil 数字软键盘工具类
public class NumKeyboardUtil {
private KeyboardView keyboardView;
private Keyboard k;// 数字键盘
private PasswordInputView ed;
public NumKeyboardUtil(Activity act, Context ctx, PasswordInputView edit) {
this.ed = edit;
k = new Keyboard(ctx, R.xml.number);
keyboardView = (KeyboardView) act.findViewById(R.id.keyboard_view);
keyboardView.setKeyboard(k);
keyboardView.setEnabled(true);
keyboardView.setPreviewEnabled(true);
keyboardView.setOnKeyboardActionListener(listener);
}
private OnKeyboardActionListener listener = new OnKeyboardActionListener() {
@Override
public void swipeUp() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeDown() {
}
@Override
public void onText(CharSequence text) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onPress(int primaryCode) {
}
//一些特殊操作按键的codes是固定的比如完成、回退等
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = ed.getText();
int start = ed.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
}else if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 完成
hideKeyboard();
} else { //将要输入的数字现在编辑框中
editable.insert(start, Character.toString((char) primaryCode));
}
}
};
public void showKeyboard() {
keyboardView.setVisibility(View.VISIBLE);
}
public void hideKeyboard() {
keyboardView.setVisibility(View.GONE);
}
public int getKeyboardVisible() {
return keyboardView.getVisibility();
}
}
number.xml
注意该文件需要放在项目下的res目录下的xml目录(没有就建个)里面
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0px"
android:keyHeight="42dip"
android:keyWidth="31%p"
android:verticalGap="0px" >
<Row>
<Key
android:codes="49"
android:keyLabel="1" />
<Key
android:codes="50"
android:keyLabel="2" />
<Key
android:codes="51"
android:keyLabel="3" />
</Row>
<Row>
<Key
android:codes="52"
android:keyLabel="4" />
<Key
android:codes="53"
android:keyLabel="5" />
<Key
android:codes="54"
android:keyLabel="6" />
</Row>
<Row>
<Key
android:codes="55"
android:keyLabel="7" />
<Key
android:codes="56"
android:keyLabel="8" />
<Key
android:codes="57"
android:keyLabel="9" />
</Row>
<Row>
<Key
android:codes="-3"
android:keyLabel="完成" />
<Key
android:codes="48"
android:keyLabel="0" />
<Key
android:codes="-5"
android:keyIcon="@drawable/sym_keyboard_delete" />
</Row>
</Keyboard>
attrs.xml里面的样式:
<!-- 支付密码输入框 -->
<declare-styleable name="PasswordInputView">
<attr name="borderWidth" format="dimension"/>
<attr name="borderColor" format="color"/>
<attr name="borderRadius" format="dimension"/>
<attr name="passwordLength" format="integer"/>
<attr name="passwordWidth" format="dimension"/>
<attr name="passwordColor" format="color"/>
<attr name="passwordRadius" format="dimension"/>
</declare-styleable>
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_bg_color" >
<include
android:id="@+id/title_ll"
layout="@layout/common_actionbar"/>
<TextView
android:id="@+id/trader_pwd_set_tips_textview"
style="@style/normal_text_style"
android:layout_below="@+id/title_ll"
android:layout_marginTop="25dip"
android:layout_centerHorizontal="true"
android:text="@string/trade_pwd_set_tips_text" />
<ImageView
android:id="@+id/line1_imageview"
style="@style/line_horizontal_style"
android:layout_below="@+id/trader_pwd_set_tips_textview"
android:layout_marginTop="26dip"
android:contentDescription="@string/content_description" />
<com.acoe.demo.widget.PasswordInputView
android:id="@+id/trader_pwd_set_pwd_edittext"
android:layout_width="match_parent"
android:layout_height="41dip"
android:layout_below="@+id/line1_imageview"
android:maxLength="6"
android:background="@android:color/white" />
<ImageView
android:id="@+id/line2_imageview"
style="@style/line_horizontal_style"
android:layout_below="@+id/trader_pwd_set_pwd_edittext"
android:contentDescription="@string/content_description" />
<Button
android:id="@+id/trader_pwd_set_next_button"
style="@style/main_button_style"
android:layout_below="@+id/line2_imageview"
android:layout_marginTop="25dip"
android:text="@string/trade_pwd_set_next_text" />
<android.inputmethodservice.KeyboardView
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="240dip"
android:layout_alignParentBottom="true"
android:paddingTop="30dip"
android:paddingLeft="13dip"
android:paddingRight="13dip"
android:focusable="true"
android:focusableInTouchMode="true"
android:visibility="invisible"/>
</RelativeLayout>
Activity代码片段:
//=======在Activity成员变量中声明部分代码=======
/** 控件 */
private PasswordInputView edtPwd;
//=======在Activity实例化控件部分代码=======
// 初始化控件
edtPwd = (PasswordInputView) findViewById(R.id.trader_pwd_set_pwd_edittext);
edtPwd.setInputType(InputType.TYPE_NULL); // 屏蔽系统软键盘
// 自定义软键盘
if (keyboardUtil == null) keyboardUtil = new NumKeyboardUtil(this, this, edtPwd);
edtPwd.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
keyboardUtil.showKeyboard();
return false;
}
});
//=======在Activity中重写onTouchEvent()方法,实现点击空白处隐藏软键盘=======
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
if(getCurrentFocus()!=null && getCurrentFocus().getWindowToken()!=null){
keyboardUtil.hideKeyboard();
}
}
return super.onTouchEvent(event);
}
ps:如果把该密码输入框和其他类型输入框并用时要注意两者之间焦点变化时将系统软键盘和自定义的数字键盘隐藏,我的做法是给密码输入框绑定OnFacusChangeListener事件,来控制就好。如下:
edtPwd.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 如果系统键盘是弹出状态,先隐藏
((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(getCurrentFocus()
.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
keyboardUtil.showKeyboard();
} else {
keyboardUtil.hideKeyboard();
}
}
});


猜你喜欢
- 由于机器内存坏了,换了个内存,重新安装了一个64位的Fedora16,把原来的32位的Fedora15格掉了。于是在重新安装Android
- 什么是耦合性耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、
- 引用开源框架通过AsyncHttpClient进行文件上传,具体内容如下一、步骤:1.添加权限(访问网络权限和读写权限)2.获取上传文件路径
- 字符串的操作是C#程序设计中十分重要的一个组成部分,本文就以实例形式展现了C#实现移除字符串末尾指定字符的方法。相信对大家学习C#程序设计有
- 1、线程的控制很常见,如文件传送到一半时,需要暂停文件传送,或终止文件传送,这实际上就是控制线程的运行。2、线程有创建、可运行、运行中、阻塞
- 前言:理论和代码必须结合起来才能真正的掌握一、this概念:this代表着当前对象的引用,也是当前函数所属对象的引用。直白的说,哪个对象调用
- C# 输出参数out什么是输出参数方法声明时,使用out修饰符声明的形参,成为输出参数。输出参数的特点1、输出参数不创建新的储存位置。2、输
- 前言CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调、流
- 函数式接口1.1 函数式接口概述函数式接口:有且仅有一个抽象方法的接口Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可
- 本文实例为大家分享了Android实现层叠卡片式banner的具体代码,供大家参考,具体内容如下效果图如下:背景由于公司VIP模块项目需要,
- 本文实例为大家分享了Android实现房贷计算器的具体代码,供大家参考,具体内容如下fangdai(activity)package com
- 使用场景EntityListeners在jpa中使用,如果你是mybatis是不可以用的它的意义对实体属性变化的跟踪,它提供了保存前,保存后
- spring.thymeleaf.cache=false不起作用配置是清除缓存,实现热部署。也就是修改了html后不用重启,刷新页面就能看到
- 一、背景SpringBoot 为我们快速开发提供了很好的架子,使得我们只需要少量配置就能开始我们的开发工作,但是当我们需要打包上传部署时,却
- 批量添加一对多中间表建立中间表A,一个id对应多个lid;传入两条参数long id;//单个数值List lid;//集合数值dao层语句
- 本文实例为大家分享了Unity3D网格功能生成球体网格模型的具体代码,供大家参考,具体内容如下前面已经讲过怎样使用mesh生成一个自己的网格
- springboot去除控制台打印的debug日志1.创建logback-spring.xml文件文件内容如下<?xml versio
- 员工管理系统要求如下:通过面向对象的编程思想,实现员工信息的增删改查,存储结构为数组。限定数组长度为100。实现页面:添加员工查找员工修改员
- 显示一个计时器开始计时,当计时器到达15s的时候,停止计时。此时页面多一个重置按钮,可再次进行计时。页面布局<LinearLayout
- 前言随着使用 Spring 进行开发的个人和企业越来越多,Spring 也慢慢从一个单一简洁的小框架变成一个大而全的开源软件,Spring