这次做的项目设计给的效果图是这样的
不选中时线为灰色,获取焦点后高亮变化,若判断错误后将底部线条文字及清楚按钮都变成红色,同时从界面上面要滑动出错误文字提示。
为了改变EditText线条颜色真是尝试了各种办法,但是小女子能力有限,最后用一种笨方法实现了。。
自定义了一个ClearEditText继承EditText实现onFocusChangeListener接口,在自定义view里大概做的事情就是
1、清除背景,注意版本判断
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN) {
setBackground(null);
} else {
setBackgroundDrawable(null);
}
2、重写onFocusChange方法,判断当前是错误状态还是正常状态,从而设置颜色及图片资源(其中正常状态时分选中和未选中直接使用selector定义一个xml文件即可)
@Override
public void onFocusChange(View v, booleanhasFocus) {
if(hasFocus&&this.getText().toString().trim().length()>0){
setClearIconVisible(true);//设置右侧清楚按钮为显示
}else{
setClearIconVisible(false);//不显示清楚按钮
}
if(!hasFocus && errorState){//若在显示错误样式时失去焦点,则变成正常状态
errorState=false;
showBottomLine(true);
}
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
* @param visible
*/
public void setClearIconVisible(booleanvisible) {
Drawable right = visible ? mClearDrawable
: null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],right,
getCompoundDrawables()[3]);
}
/**
* 显示底部线条
* @param normal
*/
public void showBottomLine(booleannormal){
if(normal){//正常状态
setTextColor(textColor);
Drawable right = (getText().length() >
0) ? mClearDrawable:
null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],right,
mBottomLineNormal);
}else{//错误状态
setTextColor(textErrorColor);
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],mErrorClearDrawable,
mBottomLineError);//在设置错误的红色底部线条时将右侧清楚按钮也换成红色X号图片
}
}
注:其中drawable图片初始化时必须设置bounds否则不显示,用法如下
mClearDrawable= getCompoundDrawables()[2];
if (mClearDrawable==
null) {
mClearDrawable= getResources().getDrawable(R.drawable.search_clear);
}
mClearDrawable.setBounds(0,0, mClearDrawable.getIntrinsicWidth(),mClearDrawable.getIntrinsicHeight());//必须设置,否则不显示
3、设置TextWatcher,今天编辑内容发生变化后恢复正常状态
//设置输入框里面内容发生改变的监听
addTextChangedListener(newTextWatcher() {
/**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence s, intstart, int
count,
int after) {
setClearIconVisible(s.length() > 0);
show(s);
if (null !=errorView
&& errorView.getVisibility() == View.VISIBLE) {//若设置了自定义的屏幕上方的view且为显示状态则隐藏
errorView.clearErrorMessage();
}
if(errorState){
errorState=false;
showBottomLine(true);//设置文字颜色、底部和右侧图片为正常状态的图片
}
}
@Override
public void beforeTextChanged(CharSequence s, intstart, int
count, intafter) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
4、其中屏幕上方错误文字提示是自定义的Relativlayout布局(因为怕亲耐的设计同学还要其它的内容没有直接使用TextView,呵呵),我命名为ErrorView,添加设置清除错误提示的方法,在设置的同时开启动画下滑显示,在清除的时候上滑隐藏。
//显示动画
mShowAction = new
TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f,
Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
-1.0f,
Animation.RELATIVE_TO_SELF,
0.0f);
mShowAction.setDuration(500);
//隐藏动画
mHiddenAction = new
TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
0.0f,
Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
-1.0f);
mHiddenAction.setDuration(500);
mHiddenAction.setAnimationListener(new
Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
tv_message.setText("");
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
public void setErrorMessage(String errorMessage){
tv_message.setText(errorMessage);
startAnimation(mShowAction);
setVisibility(View.VISIBLE);
}
public void clearErrorMessage(){
startAnimation(mHiddenAction);
ErrorView.this.setVisibility(View.INVISIBLE);
}
5,在自定义EditText中添加设置ErroView的方法,并重写setError方法,若设置了ErroView就用它显示,若没有则用默认方式。
public void setErrorView(ErrorView errorView) {
this.errorView
= errorView;
}
@Override
public void setError(CharSequence error) {
if(null
!= errorView){
errorState=true;
errorView.setErrorMessage(error.toString());
showBottomLine(false);
}else{
super.setError(error);
}
}
6、在使用的时候设置ErrorView,如edittext1.setErrorView(errorView);
当需要显示错误的时候edittext1.setError("你输入的号码有误");即可
源代码本来想上传的没找到地方。。。想粘贴上来文章又不全。。。上面写的应该都能看懂了吧,再粘一次试试。package com.jimubox.jimustock.view.weight;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.widget.EditText;
import com.jimubox.jimustock.R;
import com.jimubox.jimustock.constant.SPConstant;
import com.jimubox.jimustock.utils.SPUtility;
public class ClearEditText extends
EditText implements OnFocusChangeListener {
/**
* 删除按钮的引用
*/
private Drawable mClearDrawable;
private Drawable mBottomLineNormal;//底部线条
private Drawable mBottomLineError;//错误时显示
/**
* 控件是否有焦点
*/
private boolean hasFoucs;
/**
* 是否开启6222 2316 1256和138 8888 8888
* 银行卡号和电话号码显示方式
* 默认显示银行卡号显示方式
*/
public boolean showType;
/**
* 开启电话号码显示方式
*/
public boolean showMobileType;
//是否输入
private boolean isRun
= false;
//输入的内容
private String inputStr
= "";
private ErrorView errorView;
private boolean errorState;
private int textColor;
private int textErrorColor;
private Drawable mErrorClearDrawable;
private Context context;
public ClearEditText(Context context,
AttributeSet attrs) {
//这里构造方法也很重要,不加这个很多属性不能再XML里面定义
this(context,
attrs, android.R.attr.editTextStyle);
this.context=context;
}
public ClearEditText(Context context,
AttributeSet attrs, int defStyle) {
super(context,
attrs, defStyle);
init(context);
}
private void init(Context context) {
this.context=context;
errorState=false;
//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
mClearDrawable = getCompoundDrawables()[2];
if (mClearDrawable
== null) {
mClearDrawable = getResources().getDrawable(R.drawable.search_clear);
}
mClearDrawable.setBounds(0,
0, mClearDrawable.getIntrinsicWidth(),
mClearDrawable.getIntrinsicHeight());
if(mBottomLineNormal==null){
mBottomLineNormal = getResources().getDrawable(R.drawable.edittext_bg);
}
if(mBottomLineError
== null){
mBottomLineError = getResources().getDrawable(R.drawable.line4);
}
mBottomLineNormal.setBounds(0,
0, mBottomLineNormal.getIntrinsicWidth(),
mBottomLineNormal.getIntrinsicHeight());
mBottomLineError.setBounds(0,
0, mBottomLineError.getIntrinsicWidth(),
mBottomLineError.getIntrinsicHeight());
if(mErrorClearDrawable
== null){
mErrorClearDrawable = getResources().getDrawable(R.drawable.close_red);
}
mErrorClearDrawable.setBounds(0,
0, mErrorClearDrawable.getIntrinsicWidth(),
mErrorClearDrawable.getIntrinsicHeight());
if(SPUtility.getBoolean2SP(context,
SPConstant.SP_THEME_WHITE)){
textColor=getResources().getColor(R.color.mainTextColor_white);
}else {
textColor=getResources().getColor(R.color.mainTextColor);
}
textErrorColor=getResources().getColor(R.color.red_statusColor);
showBottomLine(true);
if (Build.VERSION.SDK_INT
>= Build.VERSION_CODES.JELLY_BEAN) {
setBackground(null);
} else {
setBackgroundDrawable(null);
}
//默认设置隐藏图标
setClearIconVisible(false);
//设置焦点改变的监听
setOnFocusChangeListener(this);
//设置输入框里面内容发生改变的监听
addTextChangedListener(new
TextWatcher() {
/**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence s, int
start, int count,
int after) {
// if(hasFoucs){
setClearIconVisible(s.length() > 0);
// }
show(s);
if (null !=
errorView && errorView.getVisibility() == View.VISIBLE) {
errorView.clearErrorMessage();
}
if(errorState){
errorState=false;
showBottomLine(true);
}
}
@Override
public void beforeTextChanged(CharSequence s, int
start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
/**
* 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
* 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和
* EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向就没有考虑
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (getCompoundDrawables()[2] !=
null) {
boolean touchable = event.getX() > (getWidth() - getTotalPaddingRight())
&& (event.getX() < ((getWidth() - getPaddingRight())));
if (touchable) {
this.setText("");
}
}
}
return super.onTouchEvent(event);
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
* @param visible
*/
public void setClearIconVisible(boolean
visible) {
Drawable right = visible ? mClearDrawable
: null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],
right, getCompoundDrawables()[3]);
}
/**
* 开启银行卡号和电话号码显示方式
*/
private void show(CharSequence s){
if(showType){//开启了银行卡号、电话号码显示方式
if(isRun){
isRun = false;
return;
}
isRun = true;
inputStr = "";
String newStr = s.toString();
newStr = newStr.replace(" ",
"");
int index = 0;
if(showMobileType){//电话号码显示方式
if((index +
3)< newStr.length()){
inputStr += (newStr.substring(index,
index + 3)+
" ");
index += 3;
}
}
while((index +
4)< newStr.length()){
inputStr += (newStr.substring(index,
index + 4)+
" ");
index += 4;
}
inputStr += (newStr.substring(index,
newStr.length()));
this.setText(inputStr);
this.setSelection(inputStr.length());
}
}
@Override
public void onFocusChange(View v, boolean
hasFocus) {
if(hasFocus&&this.getText().toString().trim().length()>0){
setClearIconVisible(true);
}else{
setClearIconVisible(false);
}
if(!hasFocus && errorState){
errorState=false;
showBottomLine(true);
}
}
public ErrorView getErrorView() {
return errorView;
}
public void setErrorView(ErrorView errorView) {
this.errorView
= errorView;
}
@Override
public void setError(CharSequence error) {
if(null
!= errorView){
errorState=true;
errorView.setErrorMessage(error.toString());
showBottomLine(false);
}else{
super.setError(error);
}
}
/**
* 显示底部线条
* @param normal
*/
public void showBottomLine(boolean
normal){
if(normal){
setTextColor(textColor);
Drawable right = (getText().length() >
0) ? mClearDrawable
: null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],
right, mBottomLineNormal);
}else{
setTextColor(textErrorColor);
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1],
mErrorClearDrawable, mBottomLineError);
}
}
}
ErrorView的代码
package com.jimubox.jimustock.view.weight;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.jimubox.jimustock.R;
/**
* Created by tangkaili on 15/6/10.
*/
public class ErrorView extends
RelativeLayout{
private Context context;
private TextView tv_message;
private ImageView iv_clean;
private TranslateAnimation mShowAction;
private TranslateAnimation mHiddenAction;
public ErrorView(Context context) {
super(context);
init(context);
}
public ErrorView(Context context,
AttributeSet attrs) {
super(context,
attrs);
init(context);
}
public ErrorView(Context context,
AttributeSet attrs, int defStyle) {
super(context,
attrs, defStyle);
init(context);
}
public void init(Context context){
this.context=context;
View view = LayoutInflater.from(context).inflate(R.layout.errorview_layout,null);
tv_message = (TextView)view.findViewById(R.id.error_text);
iv_clean = (ImageView)view.findViewById(R.id.error_clear);
iv_clean.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v) {
clearErrorMessage();
}
});
this.addView(view);
setVisibility(View.INVISIBLE);
//显示动画
mShowAction = new
TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f,
Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
-1.0f,
Animation.RELATIVE_TO_SELF,
0.0f);
mShowAction.setDuration(500);
//隐藏动画
mHiddenAction = new
TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
0.0f,
Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF,
-1.0f);
mHiddenAction.setDuration(500);
mHiddenAction.setAnimationListener(new
Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
tv_message.setText("");
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
public void setErrorMessage(String errorMessage){
tv_message.setText(errorMessage);
startAnimation(mShowAction);
setVisibility(View.VISIBLE);
}
public void clearErrorMessage(){
startAnimation(mHiddenAction);
ErrorView.this.setVisibility(View.INVISIBLE);
}
}