android字间距实现,textview字间距实现

搜索了一下关于android字间距,文章很多,但是真正能用的很少,刚好今天有这样的需求,参考了一下网上其它人的写法,自己写了一个,顺便开放源代码,供大家参考。

别人写的自定义的textview一般都有问题,少了一步计算textview控件的宽度的方法,少了一个计算文本居中对齐的方法所以写出来的文字是竖向排列的,

网上很多人说textView有一个属性android:textScaleX是调节字间距的,它的值是一个float型。这是错误的。真正的字间距需要自己去继承textview实现。

package com.huifeng.bufu.widget;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.huifeng.bufu.R;
import com.huifeng.bufu.tools.Tool;

import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.FontMetrics;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MyTextView extends TextView {
	private Context context;
	private String content;
	private int Twidth;
	private int Lwidth;
	private int xstart;
	private TextPaint paint;
	private int xPadding;
	private int yPadding;
	private int textHeight;
	private int xPaddingMin;
	private String strr;
	int count;
	// 记录每个字的二维数组
	int[][] position;

	public MyTextView(Context context) {
		super(context);
		this.context = context;
		init();
	}

	public MyTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		this.context = context;
		init();
	}

	public MyTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		init();
	}
	public void setText(String str) {
		//拿到你传进来的文本值
		this.strr=str;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);

		if (widthMode == MeasureSpec.EXACTLY
				|| widthMode == MeasureSpec.AT_MOST) {
			//获取你textview控件的宽,方便做文字对齐的,如果你的textview控件需要设置宽高,也是在这里设置的
			Lwidth = widthSize;
			Twidth = strr.length()*Tool.dpToPx(context, 30);//算出所有文本的总宽度,因为我这里就只有一行字,并且居中对齐
			xstart = (Lwidth-Twidth)/2;//算出第一个文字的其实位置
			Log.i("MyTextView", "Lwidth"+Lwidth);
			getPositions(strr);//获取每一个文字的位置信息
			this.postInvalidate();//绘制
		} else {

		}

	}

	public void init() {
		paint = new TextPaint();
		paint.setColor(getResources().getColor(R.color.red));
		paint.setTypeface(Typeface.DEFAULT);
		paint.setTextSize(Tool.dpToPx(context, 30));
		FontMetrics fm = paint.getFontMetrics();// 得到系统默认字体属性
		textHeight = (int) (Math.ceil(fm.descent - fm.top) + 2);// 获得字体高度
		// 字间距
		xPadding = dip2px(this.getContext(), 4f);
		// 行间距
		yPadding = dip2px(this.getContext(), 10f);
		// 比较小的字间距(字母和数字应紧凑)
		xPaddingMin = dip2px(this.getContext(), 2f);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		 super.onDraw(canvas);
		 //画出每一个文字
		if (!TextUtils.isEmpty(content)) {
			for (int i = 0; i < count; i++) {
				canvas.drawText(String.valueOf(content.charAt(i)),
						position[i][0], position[i][1], paint);
			}
		}
	}

	public void getPositions(String content) {
		this.content = content;
		char ch;
		// 输入点的 x的坐标
		int x = xstart+Tool.dpToPx(context, 30)/2;
		// 当前行数
		int lineNum = 1;
		count = content.length();
		// 初始化字体位置数组
		position = new int[count][2];
		for (int i = 0; i < count; i++) {
			ch = content.charAt(i);
			String str = String.valueOf(ch);

			// 根据画笔获得每一个字符的显示的rect 就是包围框(获得字符宽度)
			Rect rect = new Rect();
			paint.getTextBounds(str, 0, 1, rect);
			int strwidth = rect.width();
			// 对有些标点做些处理
			if (str.equals("《") || str.equals("(")) {
				strwidth += xPaddingMin * 2;
			}
			// 当前字的宽度
			float textWith = strwidth+xPadding;
			// 没画字前预判看是否会出界
			x += textWith;
			Log.i("MyTextView", "canvas"+x);
			// 出界就换行
			if (x > Lwidth) {
				lineNum++;// 真实的行数加一
				x = xstart+Tool.dpToPx(context, 30)/2;
			} else {
				// 回到预判前的位置
				x -= textWith;
			}
			// 记录每一个字的位置
			position[i][0] = x;
			position[i][1] = textHeight * lineNum + yPadding * (lineNum - 1);
			Log.i("MyTextView", "position[i][1]"+position[i][0]);
			// 判断是否是数字还是字母 (数字和字母应该紧凑点)
			// 每次输入完毕 进入下一个输入位置准备就绪
			if (isNumOrLetters(str)) {
				x += textWith + xPaddingMin;
			} else {
				x += textWith + xPadding;
			}
		}
		// 根据所画的内容设置控件的高度
		this.setHeight((textHeight + yPadding) * lineNum);
	}

	// 工具类:判断是否是字母或者数字需要的话可以引用
	public boolean isNumOrLetters(String str) {
		String regEx = "^[A-Za-z0-9_]+$";
		Pattern p = Pattern.compile(regEx);
		Matcher m = p.matcher(str);
		return m.matches();
	}

	// 工具类:在代码中使用dp的方法(因为代码中直接用数字表示的是像素)
	public static int dip2px(Context context, float dip) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dip * scale + 0.5f);
	}

}

有一点需要注意,一下,给这个控件setText的时候,一定要调用这个控件的setText(String str),而不是调用textview的setText(CharSequence text)这个方法,否则无法显示自定义的文本间距。


你可能感兴趣的:(ANDROID)