在日常开发中有时需要实现在一个输入框中输入字并且同步显示已输入字符的长度,以方便查看此输入框最大能输入多少字符,现在已输入多少字符。实现效果如下:
主要实现步骤及相关代码:
1.首先创建一个类继承EditText,实现构造方法;
2.定义相关属性:在《项目名称》\src\main\res\values\attrs.xml文件中:
3.初始化设置的相关属性:
/**
* @param context
* @param attrs 初始化属性
*/
private void initAttribute(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WordsNumEditText);
try {
mNumTextSize = (int) ta.getDimension(R.styleable.WordsNumEditText_numTextSize, DensityUtils.sp2px(context, 12));//字体大小
mNumTextColor = ta.getColor(R.styleable.WordsNumEditText_numTextColor, Color.parseColor("#b1b1b1"));//字体颜色
grivity = ta.getInt(R.styleable.WordsNumEditText_numTextGravity, grivity);//显示的位置,left从左向右扩展,right从右向左扩展显示,
maxLength = getMaxLength();//获取设置的最大显示字数
paddingLeft = getPaddingLeft();
paddingRight = getPaddingRight();
bottom = DensityUtils.dip2px(context, 10);
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + DensityUtils.dip2px(context, 10));
} finally {
ta.recycle();
}
initPaint();//初始化画笔
}
其中获取editText的maxLength属性值的方法详情如下:
/**
* @return length
* 获取editText的MaxLength的属性值
*/
public int getMaxLength() {
int length = 0;
try {
InputFilter[] inputFilters = this.getFilters();
for (InputFilter filter : inputFilters) {
Class> c = filter.getClass();
if (c.getName().equals("android.text.InputFilter$LengthFilter")) {
Field[] f = c.getDeclaredFields();
for (Field field : f) {
if (field.getName().equals("mMax")) {
field.setAccessible(true);
length = (Integer) field.get(filter);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return length;
}
3.初始化画笔,需根据设置的grivity属性确定画笔滑动的方向:
/**
* 创建一个画笔
*
* @param paintColor 画笔颜色
* @param textSize 文字大小
* @param style 画笔样式
* @param roundWidth 画笔宽度
* @return
*/
private Paint createLeftPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(roundWidth);
paint.setDither(true);
paint.setTextSize(textSize);
paint.setTextAlign(Paint.Align.LEFT);//这是grivity为left的时候,若grivity是right,则设置为 Paint.Align.RIGHT
paint.setStyle(style);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
return paint;
}
4.在onDraw()中实现画“数字”的逻辑:
/**
* @param canvas 画输入框中 字数/最大字数
*/
private void drawNumberText(Canvas canvas) {
int length = getText().length();
String str = length + "/" + maxLength;
int x = 0;
if (grivity == GRAVITY_LEFT) {
x = 0 + paddingLeft;
} else {
x = width - paddingRight;
}
int y = height - bottom;
canvas.drawText(str, x, y, textPaint);
}
其中width和height需要在onMeasure()中实时计算:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
最后附上完整代码及demo地址(名称有些繁琐,莫见怪哈):https://github.com/ErieCorner/DesplayInputCharacterLengthEdittextModule.git
public class DeplayInputCharacterLenghtEditText extends EditText {
public DeplayInputCharacterLenghtEditText(Context context) {
super(context);
initAttribute(context, null);
}
public DeplayInputCharacterLenghtEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initAttribute(context, attrs);
}
public DeplayInputCharacterLenghtEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttribute(context, attrs);
}
private int mNumTextColor = Color.parseColor("#b1b1b1");
private int mNumTextSize = 12;
public final static int GRAVITY_LEFT = 1;//字数显示在左边,当数字位数增多时向右扩展
public final static int GRAVITY_RIGHT = 2;//字数显示在右边,当数字位数增多时向左扩展
private int grivity = GRAVITY_RIGHT;
private Context context;
private Paint textPaint;
private int width;
private int height;
private int maxLength;
private int paddingLeft = 0;
private int paddingRight = 0;
private int bottom = 0;
/**
* 初始化画笔
*/
private void initPaint() {
if (grivity == GRAVITY_LEFT) {
textPaint = createLeftPaint(mNumTextColor, mNumTextSize, Paint.Style.FILL, 2);
} else {
textPaint = createRightPaint(mNumTextColor, mNumTextSize, Paint.Style.FILL, 2);
}
}
/**
* @param context
* @param attrs 初始化属性
*/
private void initAttribute(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DeplayInputCharacterLenghtEditText);
try {
mNumTextSize = (int) ta.getDimension(R.styleable.DeplayInputCharacterLenghtEditText_numTextSize, DensityUtils.sp2px(context, 12));
mNumTextColor = ta.getColor(R.styleable.DeplayInputCharacterLenghtEditText_numTextColor, Color.parseColor("#b1b1b1"));
grivity = ta.getInt(R.styleable.DeplayInputCharacterLenghtEditText_numTextGravity, grivity);
maxLength = getMaxLength();
} finally {
ta.recycle();
}
paddingLeft = getPaddingLeft();
paddingRight = getPaddingRight();
bottom = DensityUtils.dip2px(context, 10);
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + DensityUtils.dip2px(context, 10));
initPaint();
}
/**
* 判断是否为emoji表情
*
* @param codePoint 要校验的字符
* @return 是否为表情
*/
private boolean isEmojiCharacter(char codePoint) {
return !((codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) ||
(codePoint == 0xD) || ((codePoint >= 0x20) && codePoint <= 0xD7FF)) ||
((codePoint >= 0xE000) && (codePoint <= 0xFFFD));
}
/**
* 创建一个画笔
*
* @param paintColor 画笔颜色
* @param textSize 文字大小
* @param style 画笔样式
* @param roundWidth 画笔宽度
* @return
*/
private Paint createLeftPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(roundWidth);
paint.setDither(true);
paint.setTextSize(textSize);
paint.setTextAlign(Paint.Align.LEFT);
paint.setStyle(style);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
return paint;
}
/**
* 创建一个画笔
*
* @param paintColor 画笔颜色
* @param textSize 文字大小
* @param style 画笔样式
* @param roundWidth 画笔宽度
* @return
*/
private Paint createRightPaint(int paintColor, int textSize, Paint.Style style, int roundWidth) {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(roundWidth);
paint.setDither(true);
paint.setTextSize(textSize);
paint.setTextAlign(Paint.Align.RIGHT);
paint.setStyle(style);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawNumberText(canvas);
}
/**
* @param canvas 画输入框中 字数/最大字数
*/
private void drawNumberText(Canvas canvas) {
int length = getText().length();
String str = length + "/" + maxLength;
int x = 0;
if (grivity == GRAVITY_LEFT) {
x = 0 + paddingLeft;
} else {
x = width - paddingRight;
}
int y = height - bottom;
canvas.drawText(str, x, y, textPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
postInvalidate();
}
/**
* @return length
* 获取editText的MaxLength的属性值
*/
public int getMaxLength() {
int length = 0;
try {
InputFilter[] inputFilters = this.getFilters();
for (InputFilter filter : inputFilters) {
Class> c = filter.getClass();
if (c.getName().equals("android.text.InputFilter$LengthFilter")) {
Field[] f = c.getDeclaredFields();
for (Field field : f) {
if (field.getName().equals("mMax")) {
field.setAccessible(true);
length = (Integer) field.get(filter);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return length;
}
}