在项目开发中多次出现相同的编辑框模块,且样式和要求基本相同,为了让代码利用率更高,跟同事讨论之后对编辑框进行了自定义,这些模块可以单独复用到其他项目,感觉使用起来还不错,现在分享给大家。
自定义的编辑框的基本操作流程,无非就是了解原本编辑框的基本属性和方法,然后进行扩展,从而实现或满足自己的基本需求,这也符合面向对象的要求,继承、封装、多态。下面就直接上代码:
第一步:自定义个基类继承相对应的布局结构
public abstract class EditTextVerifyBase extends RelativeLayout {
protected EditText inputEt;//输入框
protected TextView errMsgTv;//错误提示消息
protected int maxLength;//输入框最大长度
protected int maxInputLength;
protected boolean isNeed;//是否必须输入
protected boolean needCheck;//是否需要校验
protected boolean couldClear; //是否允许清空输入框
protected int startCheckLength;//开始字符校验的长度 默认开始7 子类可以调整
//新增是否需要设置不可编辑
protected boolean isFocusable = true;
protected boolean isFocusableInTouchMode = true;
protected String nullMsg;
protected String errMsg;
protected String overLengthMsg;//超过长度时候 报的错误
protected String hint;
protected TextWatcher textWatcher;
protected ImageView clearBtn;
protected String releTitle;//关联控件的 text 作为错误信息输出提示
protected boolean showErrorMsg;//是否需要显示 错误信息
protected EditTextVerifyInterface editTextVericyInterface;
public EditTextVerifyBase(Context context, AttributeSet attrs) {
super(context, attrs);
startCheckLength = 1;
LayoutInflater.from(context).inflate(R.layout.edit_text_vericfy_layout,this,true);
inputEt = (EditText) findViewById(R.id.inputEt);
errMsgTv = (TextView) findViewById(R.id.errMsgTv);
clearBtn = (ImageView)findViewById(R.id.clearBtn);
//属性一栏
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.edittextverify);
showErrorMsg = true;
if(attributes!=null) {
isNeed = attributes.getBoolean(R.styleable.edittextverify_isNeed,true);
needCheck = attributes.getBoolean(R.styleable.edittextverify_needCheck,true);
maxLength = attributes.getInteger(R.styleable.edittextverify_maxLength,0);
hint = attributes.getString(R.styleable.edittextverify_hint);
//默认 可以清空输入框
couldClear = attributes.getBoolean(R.styleable.edittextverify_couldClear,true);
releTitle = attributes.getString(R.styleable.edittextverify_releTitle);
isFocusable = attributes.getBoolean(R.styleable.edittextverify_isFocusable,true);
isFocusableInTouchMode = attributes.getBoolean(R.styleable.edittextverify_isFocusableInTouchMode,true);
if(attributes.hasValue(R.styleable.edittextverify_maxInputLength)){
maxInputLength = attributes.getInt(R.styleable.edittextverify_maxInputLength,0);
InputFilter[] fa= new InputFilter[1];
fa[0] = new InputFilter.LengthFilter(maxInputLength);
inputEt.setFilters(fa);
}
if(StringUtils.isEmpty(releTitle)){
releTitle="";
}
if(couldClear){
clearBtn.setVisibility(VISIBLE);
}else{
clearBtn.setVisibility(GONE);
}
inputEt.setHint(hint);//设置输入框默认显示
initEvent();
inputEt.addTextChangedListener(textWatcher);//添加监听事件
if(!isFocusable && !isFocusableInTouchMode){
inputEt.setFocusableInTouchMode(isFocusable);
inputEt.setFocusable(isFocusableInTouchMode);
}
}
}
public void initEvent(){
textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(couldClear){
clearBtn.setVisibility(VISIBLE);
}
checkError();
if(editTextVerifyInterface!=null){
editTextVerifyInterface.onChangedListener(s,start,before,count);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
clearBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
inputEt.setText("");//清空输入框
}
});
}
private boolean checkNull(boolean hasError){
int visible = VISIBLE;
if(isNeed && StringUtils.isEmpty(inputEt.getText().toString())&&!hasError){ //校验是否为空
errMsgTv.setText(nullMsg);
hasError = true;
visible = VISIBLE;
}
if(hasError) {
errMsgTv.setVisibility(visible);
}else{
errMsgTv.setVisibility(GONE);
}
return hasError;
}
private boolean checkError(){
Editable editable = inputEt.getText();
int visible = VISIBLE;
boolean hasError = false;
if(!StringUtils.isEmpty(editable.toString())&&startCheckLength<=editable.length()){
//需要校验 并且 字符开始校验长度 小于 字符长度
//长度校验
String textValue = editable.toString();
//去除收尾空格空格功能
if(maxLength!=0&&textValue.trim().length()>maxLength){
//超过设置的最大长度
errMsgTv.setText(overLengthMsg);
visible = VISIBLE;
hasError = true;
}else if(needCheck&&!verify(editable.toString())){
errMsgTv.setText(errMsg);
visible = VISIBLE;
hasError = true;
}else{
visible = GONE;
hasError = false;
}
}else{
visible = GONE;
hasError = false;
}
if(hasError) {
errMsgTv.setVisibility(visible);
}else{
errMsgTv.setVisibility(GONE);
}
return hasError;
}
/**
* 需要子类 从新定义规则
* @param text
* @return
*/
abstract boolean verify(String text);
public void setNullMsg(String errMsg){
this.nullMsg = errMsg;
}
public void setErrMsg(String errMsg){
this.errMsg = errMsg;
}
public void setOverLengthMsg(String errMsg){
this.overLengthMsg = errMsg;
}
public boolean getHasError(){
boolean hasError = checkError();
hasError = checkNull(hasError);
return hasError;
}
/**
* 返回去除收尾空格的 文本
* @return
*/
public String getText(){
return this.inputEt.getText().toString().trim();
}
public void setText(String text){
this.inputEt.setText(text);
}
/**
* 是否需要显示错误信息
* @param showErrorMsg
*/
public void setShowErrorMsg(boolean showErrorMsg){
this.showErrorMsg = showErrorMsg;
}
public void setOnFocusChangeListener(OnFocusChangeListener onFocusChangeListener){
inputEt.setOnFocusChangeListener(onFocusChangeListener);
}
public int getId(){
return inputEt.getId();
}
public String getReleTitle() {
return releTitle;
}
public int getMaxLength(){
return maxLength;
}
public void setFocusableFalse(){
inputEt.setFocusable(false);
inputEt.setFocusableInTouchMode(false);
clearBtn.setVisibility(View.GONE);
}
public void setEditTextVerifyInterface(EditTextVerifyInterface editTextVerifyInterface){
this.editTextVerifyInterface = editTextVerifyInterface;
}
public interface EditTextVerifyInterface{
void onChangedListener(CharSequence s, int start, int before, int count);
}
}
对应的布局
<?xml version="1.0" encoding="utf-8"?>
<!-- 自定义校验 textView -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
//输入框
<EditText
android:id="@+id/inputEt"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginRight="40dp"
android:background="@null"
android:textSize="@dimen/edit_second_paragraph"
android:layout_weight="8"
android:paddingLeft="5px"
android:layout_alignParentTop="true"
android:textCursorDrawable="@drawable/et_cursor"
android:textColor="@color/Grey2"
android:textColorHint="@color/Grey3" />
//右边清除按钮
<ImageView
android:id="@+id/clearBtn"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:visibility="visible"
android:layout_alignParentRight="true"
android:paddingRight="5dp"
android:paddingLeft="5px"
android:src="@drawable/poor"
/>
//错误提示语
<TextView
android:id="@+id/errMsgTv"
android:layout_below="@+id/inputEt"
android:layout_alignParentLeft="true"
android:layout_alignLeft="@+id/inputEt"
android:layout_alignRight="@+id/inputEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="@color/Red"
android:textSize="@dimen/text_error_word"
android:padding="6px"
android:visibility="gone"/>
</RelativeLayout>
对应的style
<declare-styleable name="edittextverify">
<attr name="hint" format="string" /> <!-- 输入框 hint 显示 -->
<attr name="isNeed" format="boolean" /> <!-- 是否必输入 默认必须 -->
<attr name="needCheck" format="boolean" /> <!-- 是否需要校验 默认必须 -->
<attr name="maxLength" format="integer" /> <!--输入框 长度 0 不校验长度 默认0 -->
<attr name="couldClear" format="boolean" />
<attr name="maxInputLength" format="integer" />
<attr name="releTitle" format="string"/>
<attr name="isFocusable" format="boolean"/><!--输入框是否获得焦点 -->
<attr name="isFocusableInTouchMode" format="boolean"/>
</declare-styleable>
第二步:对第一步方法继承封装(举出一个项目中的实例,其余的根据个人需求进行封装改造)
银行卡的应用包含卡号以及合法性的校验(如下是需要用到的代码,其余就不粘贴了)
public class EditTextVerifyBankCard extends EditTextVerifyBase {
public EditTextVerifyBankCard(Context context, AttributeSet attrs) {
super(context, attrs);
setErrMsg(releTitle+"格式错误");
setNullMsg(releTitle+"不能为空");
setOverLengthMsg(releTitle+"不能超过"+maxLength+"位");
}
@Override
boolean verify(String text) {
return ToolsUtil.checkBankCard(text);
}
}
下面的代码是封装在ToolsUtil一个综合工具包下面,便于管理
/**
* 校验银行卡卡号
*
* @param cardId
* @return
*/
public static boolean checkBankCard(String cardId) {
if (StringUtils.isEmpty(cardId)) {
return false;
}
char bit = getBankCardCheckCode(cardId
.substring(0, cardId.length() - 1));
if (bit == 'N') {
return false;
}
return cardId.charAt(cardId.length() - 1) == bit;
}
/**
* 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
*
* @param nonCheckCodeCardId
* @return
*/
public static char getBankCardCheckCode(String nonCheckCodeCardId) {
if (nonCheckCodeCardId == null
|| nonCheckCodeCardId.trim().length() == 0
|| !nonCheckCodeCardId.matches("\\d+")) {
// 如果传的不是数据返回N
return 'N';
}
char[] chs = nonCheckCodeCardId.trim().toCharArray();
int luhmSum = 0;
for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
int k = chs[i] - '0';
if (j % 2 == 0) {
k *= 2;
k = k / 10 + k % 10;
}
luhmSum += k;
}
return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
}
第三步:准备工作整理好之后,开始应用到实际布局
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_gravity="center">
<TextView
android:id="@+id/tv_bankCardShow"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="银行卡号"
android:textColor="@color/Black"
android:textSize="@dimen/edit_second_paragraph" />
<包名路径.EditText.EditTextVerifyBankCard
android:id="@+id/et_bank_num"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:layout_toLeftOf="@+id/iv_bank_pic"
android:layout_toRightOf="@+id/tv_bankCardShow"
android:gravity="left"
etv:hint="请输入银行卡号"
etv:isNeed="true"
etv:maxLength="30"
etv:needCheck="true"
etv:couldClear = "false"
etv:releTitle="常用银行卡号" />
<ImageView
android:id="@+id/iv_bank_pic"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:src="@drawable/camera_upload"
android:visibility="visible" />
</RelativeLayout>
第四步:在类里面的操作判断,在失去焦点之后会进行相应的校验
EditTextVerifyBankCard etBankNum = getViewById(R.id.et_bank_num);//银行卡号码
if (etBankNum.getHasError()){
return ;
}
上述方法还可以用在姓名、身份证、手机号等等方面的校验,需要自己根据需求进行封装,欢迎各路大神进行批评指点,记得留言呦