Android自定義密碼輸入框和數(shù)字鍵盤
實(shí)現(xiàn)了一個(gè)自定義的密碼輸入框和自定義數(shù)字鍵盤,用作用戶支付密碼設(shè)置界面。先上效果圖如下,方格樣式,以及點(diǎn)擊空白處隱藏軟鍵盤。

控件實(shí)現(xiàn)清單:
1)集成于EditText的輸入框控件:PasswordInputView.java
2)數(shù)字鍵盤工具類:NumKeyboardUtil.java
3)xml文件:number.xml
4)attrs樣式
5)layout文件
具體內(nèi)容:
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 數(shù)字軟鍵盤工具類
public class NumKeyboardUtil {
private KeyboardView keyboardView;
private Keyboard k;// 數(shù)字鍵盤
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 { //將要輸入的數(shù)字現(xiàn)在編輯框中
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
注意該文件需要放在項(xiàng)目下的res目錄下的xml目錄(沒有就建個(gè))里面
<?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實(shí)例化控件部分代碼=======
// 初始化控件
edtPwd = (PasswordInputView) findViewById(R.id.trader_pwd_set_pwd_edittext);
edtPwd.setInputType(InputType.TYPE_NULL); // 屏蔽系統(tǒng)軟鍵盤
// 自定義軟鍵盤
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()方法,實(shí)現(xiàn)點(diǎn)擊空白處隱藏軟鍵盤=======
@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:如果把該密碼輸入框和其他類型輸入框并用時(shí)要注意兩者之間焦點(diǎn)變化時(shí)將系統(tǒng)軟鍵盤和自定義的數(shù)字鍵盤隱藏,我的做法是給密碼輸入框綁定OnFacusChangeListener事件,來控制就好。如下:
edtPwd.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// 如果系統(tǒng)鍵盤是彈出狀態(tài),先隱藏
((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(getCurrentFocus()
.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
keyboardUtil.showKeyboard();
} else {
keyboardUtil.hideKeyboard();
}
}
});
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 有道詞典的簡(jiǎn)單實(shí)現(xiàn)方法介紹
本篇文章小編為大家介紹,Android 有道詞典的簡(jiǎn)單實(shí)現(xiàn)方法介紹。需要的朋友參考下2013-04-04
Android使用Jetpack WindowManager開發(fā)可折疊設(shè)備(過程分享)
這篇文章主要介紹了Android使用Jetpack WindowManager開發(fā)可折疊設(shè)備,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11
Android開發(fā)中多進(jìn)程共享數(shù)據(jù)簡(jiǎn)析
這篇文章主要為大家簡(jiǎn)單分析Android開發(fā)中多進(jìn)程共享數(shù)據(jù),怎么做才能讓這兩邊共享數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-04-04
Android學(xué)習(xí)教程之圖片毛玻璃效果(4)
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)教程之圖片毛玻璃效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android Service服務(wù)不被停止詳解及實(shí)現(xiàn)
這篇文章主要介紹了Android Service服務(wù)不被停止詳解及實(shí)現(xiàn)的相關(guān)資料,有很多應(yīng)用在設(shè)置運(yùn)行中會(huì)被直接停止掉,這里就提供一個(gè)方法一直運(yùn)行,需要的朋友可以參考下2016-11-11
Android HelloChart開源庫圖表之折線圖的實(shí)例代碼
這篇文章主要介紹了Android HelloChart開源庫圖表之折線圖的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,一起跟隨小編過來看看吧2018-05-05
Android View滑動(dòng)的實(shí)現(xiàn)分析示例
View滑動(dòng)是Android實(shí)現(xiàn)自定義控件的基礎(chǔ),同時(shí)在開發(fā)中難免會(huì)遇到View的滑動(dòng)處理,其實(shí)不管是那種滑動(dòng)方法,基本思路是類似的;當(dāng)點(diǎn)擊事件傳到View時(shí),系統(tǒng)記下觸摸點(diǎn)的坐標(biāo),手指移動(dòng)時(shí)系統(tǒng)記下移動(dòng)后的左邊并算出偏移量,通過偏移量來修改View的坐標(biāo)2022-08-08
Android 使用Vitamio打造自己的萬能播放器(1)——準(zhǔn)備
本文主要介紹Android Vitamio,在Android開發(fā)視頻播放器的時(shí)候,大家經(jīng)常會(huì)遇到系統(tǒng)版本和不同的Android手機(jī)不同導(dǎo)致開發(fā)的軟件不能完美適用,這里給大家介紹個(gè)播放器插件可以適應(yīng)所有Android設(shè)備2016-07-07

