package com.chaychan.viewlib.expandabletextview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
import com.chaychan.viewlib.R;
import java.util.ArrayList;
import java.util.List;
/**
* 两端对齐的text view,可以设置最后一行靠左,靠右,居中对齐
*
* @author YD
*/
public class AlignTextView extends TextView {
private float textHeight; // 单行文字高度
private float textLineSpaceExtra = 0; // 额外的行间距
private int width; // textView宽度
private List<String> lines = new ArrayList<String>(); // 分割后的行
private List<Integer> tailLines = new ArrayList<Integer>(); // 尾行
private Align align = Align.ALIGN_LEFT; // 默认最后一行左对齐
private boolean firstCalc = true; // 初始化计算
private float lineSpacingMultiplier = 1.0f;
private float lineSpacingAdd = 0.0f;
private int originalHeight = 0; //原始高度
private int originalLineCount = 0; //原始行数
private int originalPaddingBottom = 0; //原始paddingBottom
private boolean setPaddingFromMe = false;
// 尾行对齐方式
public enum Align {
ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT // 居中,居左,居右,针对段落最后一行
}
public AlignTextView(Context context) {
super(context);
setTextIsSelectable(false);
}
public AlignTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setTextIsSelectable(false);
lineSpacingMultiplier = attrs.getAttributeFloatValue("http://schemas.android" + "" +
".com/apk/res/android", "lineSpacingMultiplier", 1.0f);
int[] attributes = new int[]{android.R.attr.lineSpacingExtra};
TypedArray arr = context.obtainStyledAttributes(attrs, attributes);
lineSpacingAdd = arr.getDimensionPixelSize(0, 0);
originalPaddingBottom = getPaddingBottom();
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.AlignTextView);
int alignStyle = ta.getInt(R.styleable.AlignTextView_align, 0);
switch (alignStyle) {
case 1:
align = Align.ALIGN_CENTER;
break;
case 2:
align = Align.ALIGN_RIGHT;
break;
default:
align = Align.ALIGN_LEFT;
break;
}
ta.recycle();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//首先进行高度调整
if (firstCalc) {
width = getMeasuredWidth();
String text = getText().toString();
TextPaint paint = getPaint();
lines.clear();
tailLines.clear();
// 文本含有换行符时,分割单独处理
String[] items = text.split("\\n");
for (String item : items) {
calc(paint, item);
}
//使用替代textview计算原始高度与行数
measureTextViewHeight(text, paint.getTextSize(), getMeasuredWidth() -
getPaddingLeft() - getPaddingRight());
//获取行高
textHeight = 1.0f * originalHeight / originalLineCount;
textLineSpaceExtra = textHeight * (lineSpacingMultiplier - 1) + lineSpacingAdd;
//计算实际高度,加上多出的行的高度(一般是减少)
int heightGap = (int) ((textLineSpaceExtra + textHeight) * (lines.size() -
originalLineCount));
setPaddingFromMe = true;
//调整textview的paddingBottom来缩小底部空白
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
originalPaddingBottom + heightGap);
firstCalc = false;
}
}
@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
paint.setColor(getCurrentTextColor());
paint.drawableState = getDrawableState();
width = getMeasuredWidth();
Paint.FontMetrics fm = paint.getFontMetrics();
float firstHeight = getTextSize() - (fm.bottom - fm.descent + fm.ascent - fm.top);
int gravity = getGravity();
if ((gravity & 0x1000) == 0) { // 是否垂直居中
firstHeight = firstHeight + (textHeight - firstHeight) / 2;
}
int paddingTop = getPaddingTop();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
width = width - paddingLeft - paddingRight;
for (int i = 0; i < lines.size(); i++) {
float drawY = i * textHeight + firstHeight;
String line = lines.get(i);
// 绘画起始x坐标
float drawSpacingX = paddingLeft;
float gap = (width - paint.measureText(line));
float interval = gap / (line.length() - 1);
// 绘制最后一行
if (tailLines.contains(i)) {
interval = 0;
if (align == Align.ALIGN_CENTER) {
drawSpacingX += gap / 2;
} else if (align == Align.ALIGN_RIGHT) {
drawSpacingX += gap;
}
}
for (int j = 0; j < line.length(); j++) {
float drawX = paint.measureText(line.substring(0, j)) + interval * j;
canvas.drawText(line.substring(j, j + 1), drawX + drawSpacingX, drawY +
paddingTop + textLineSpaceExtra * i, paint);
}
}
}
/**
* 设置尾行对齐方式
*
* @param align 对齐方式
*/
public void setAlign(Align align) {
this.align = align;
invalidate();
}
/**
* 计算每行应显示的文本数
*
* @param text 要计算的文本
*/
private void calc(Paint paint, String text) {
if (text.length() == 0) {
lines.add("\n");
return;
}
int startPosition = 0; // 起始位置
float oneChineseWidth = paint.measureText("中");
int ignoreCalcLength = (int) (width / oneChineseWidth); // 忽略计算的长度
StringBuilder sb = new StringBuilder(text.substring(0, Math.min(ignoreCalcLength + 1,
text.length())));
for (int i = ignoreCalcLength + 1; i < text.length(); i++) {
if (paint.measureText(text.substring(startPosition, i + 1)) > width) {
startPosition = i;
//将之前的字符串加入列表中
lines.add(sb.toString());
sb = new StringBuilder();
//添加开始忽略的字符串,长度不足的话直接结束,否则继续
if ((text.length() - startPosition) > ignoreCalcLength) {
sb.append(text.substring(startPosition, startPosition + ignoreCalcLength));
} else {
lines.add(text.substring(startPosition));
break;
}
i = i + ignoreCalcLength - 1;
} else {
sb.append(text.charAt(i));
}
}
if (sb.length() > 0) {
lines.add(sb.toString());
}
tailLines.add(lines.size() - 1);
}
@Override
public void setText(CharSequence text, BufferType type) {
firstCalc = true;
super.setText(text, type);
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
if (!setPaddingFromMe) {
originalPaddingBottom = bottom;
}
setPaddingFromMe = false;
super.setPadding(left, top, right, bottom);
}
/**
* 获取文本实际所占高度,辅助用于计算行高,行数
*
* @param text 文本
* @param textSize 字体大小
* @param deviceWidth 屏幕宽度
*/
private void measureTextViewHeight(String text, float textSize, int deviceWidth) {
TextView textView = new TextView(getContext());
textView.setText(text);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(deviceWidth, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
originalLineCount = textView.getLineCount();
originalHeight = textView.getMeasuredHeight();
}
}