最近研究了好几天EditText输入文本的时候,在输入内容的时候都会有一条中间的线跟着,相当于文本作废的功能,妈蛋描述不清楚,上图。
我找这个功能找了好久找不到,实在没办法自己定义。刚开始在onDraw方法里画线,但是,你得确定文字的起始坐标,结束坐标,而且换行的时候
文字的高度就变了。还有的时候你输入的内容什么都有,可能输入一半就自动换行了。总之没处理好。
后来翻了好多源码才知道EditText 有个Editable 而且这个Editable 有个setSpan方法。我想这通过span入手去添加文字上面的线条。
不说废话了,粘贴上源码!
public class CenterLineEditText extends EditText {
private Paint mPaint;
private Context mContext;
int beforcount;
private Editable editable;//通过TextWatcher事件获取到最新的Editable对象
private CenterLineSpan span;//文字划线的span
public CenterLineEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public CenterLineEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CenterLineEditText(Context context) {
super(context);
init(context);
}
private void init(Context context){
mContext = context;
addTextChangedListener(watcher);//添加TextWatcher事件
span = new CenterLineSpan();//初始化文字线条的span
}
TextWatcher watcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
beforcount = count;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
//每次用户输入文本完毕就会调用这个方法,设置editable字段的值,设置span对象
editable = s;
s.setSpan(span,0,s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
};
//调用这个外部接口就可以设置文字上面的线条的有无
public void setIsDrawLine(boolean isDrawLine){
span.setIsDrawLine(isDrawLine);
if(editable != null){
editable.setSpan(span,0,editable.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (!isDrawLine){//当传回来的是false 调用editable 的removeSpan方法 就可以去掉线了 通过span.setIsDrawLine方法 可以让CenterLIneSpan 不再划线了。
editable.removeSpan(span);
}
}
}
真正划线的代码 全都在CenterLineSpan类里面 其实这个类也很简单
下面上源码,
public class CenterLineSpan implements LineBackgroundSpan {
private int color ;
private boolean isDrawline = false;
public static String TAG = CenterLineSpan.class.getName();
public CenterLineSpan(int color){
this.color = color;
}
public CenterLineSpan(){
this.color = Color.RED;
}
public void setIsDrawLine(boolean isDrawline){
this.isDrawline = isDrawline;
}
private void drawCenterLine(Paint p, CharSequence text, int start, int end, int top, int baseline, Canvas c){
if(isDrawline){
int oldColor = p.getColor();
CharSequence curtext = text.subSequence(start,end);//获取每一行的文本 start 每一行的开始文字 end 每一行的结束位置
// Log.e(TAG,"curtext:"+curtext.toString());
float rightwidth = getTextWidth(p,curtext.toString());//获取每一行的文本内容的宽度 因为每个字符宽度不一样 所以必须每一个字符宽度相加获取值
// Log.e(TAG,"rightwidth:"+rightwidth);
Rect rect = new Rect();
p.getTextBounds(text.toString(),0,text.length(),rect);//获取文本最左边的开始位置
p.setColor(color);//设置下划线的颜色
float centerY = (top+baseline)/2;//设置每一行的高度的Y轴坐标值
c.drawLine(rect.left,centerY,rightwidth,centerY,p);//划线
p.setColor(oldColor);
}else{
//isDrawLine false 则什么也不做
}
}
@Override
public void drawBackground(Canvas c, Paint p, int left, int right, int top, int baseline, int bottom, CharSequence text, int start, int end, int lnum) {
drawCenterLine(p,text,start,end,top,baseline,c);
}
public static int getTextWidth(Paint paint, String str) {
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
paint.getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
return iRet;
}
}
尽管不是很难,但是这些函数都不是很熟,所以只能一个一个慢慢的去瞎试,总算试出来了。所以我想说,甭管多难,天天去想想找找办法,问题总会解决的。