实现适配SpannableString的两端对齐的TextView_android textview 两端对齐_GODxxMAN的博客-CSDN博客
在此基础上增加了省略号显示
package cn.com.ccf.rtx.widget;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.text.Layout;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.CharacterStyle;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import cn.com.ccf.rtx.R;
//两端对齐
public class AlignTextView extends androidx.appcompat.widget.AppCompatTextView {
private final String TAG = AlignTextView.class.getSimpleName();
private boolean alignOnlyOneLine;
public AlignTextView(Context context) {
this(context, null);
}
public AlignTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AlignTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AlignTextView);
alignOnlyOneLine = typedArray.getBoolean(R.styleable.AlignTextView_alignOnlyOneLine, false);
ColorStateList colorStateList = typedArray.getColorStateList(R.styleable.AlignTextView_android_textColor);
setTextColor(colorStateList==null?ColorStateList.valueOf(Color.GRAY):colorStateList);
int maxLines = typedArray.getInt(R.styleable.AlignTextView_android_maxLines, 0);
int textSize = typedArray.getDimensionPixelSize(R.styleable.AlignTextView_android_textSize, 14);
float textSizeSP = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, textSize, getResources().getDisplayMetrics());
TextPaint textPaint = getPaint();
textPaint.setTextSize(textSize);
if (maxLines>0){
setEllipsize(TextUtils.TruncateAt.END);
setMaxLines(maxLines);
}
typedArray.recycle();
}
@Override
public void setTextColor(int color) {
super.setTextColor(color);
getPaint().setColor(color);
}
@Override
public void setTextColor(ColorStateList colors) {
super.setTextColor(colors);
getPaint().setColor(colors.getDefaultColor());
}
protected void onDraw(Canvas canvas) {
CharSequence content = getText();
if (content instanceof String){
String text = (String) content;
Layout layout = getLayout();
for (int i = 0; i < layout.getLineCount(); ++i) {
int lineBaseline = layout.getLineBaseline(i) + getPaddingTop();
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
if (alignOnlyOneLine && layout.getLineCount() == 1) {//只有一行
String line = text.substring(lineStart, lineEnd);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
// this.drawScaledText(canvas, line, lineBaseline, width);
if (width > getWidth() - getPaddingLeft() - getPaddingRight()) {
// 文本超出控件宽度,需要绘制省略号
line = TextUtils.ellipsize(line, getPaint(), getWidth() - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString();
canvas.drawText(line, getPaddingLeft(), lineBaseline, getPaint());
} else {
this.drawScaledText(canvas, line, lineBaseline, width);
}
} else if (i == layout.getLineCount() - 1) {//最后一行
//canvas.drawText(text.substring(lineStart), getPaddingLeft(), lineBaseline, getPaint());
String line = text.substring(lineStart);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
if (width > getWidth() - getPaddingLeft() - getPaddingRight()) {
// 文本超出控件宽度,需要绘制省略号
line = TextUtils.ellipsize(line, getPaint(), getWidth() - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString();
canvas.drawText(line, getPaddingLeft(), lineBaseline, getPaint());
} else {
canvas.drawText(line, getPaddingLeft(), lineBaseline, getPaint());
}
break;
} else {//中间行
String line = text.substring(lineStart, lineEnd);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
this.drawScaledText(canvas, line, lineBaseline, width);
}
}
}else if (content instanceof Spanned){
Spanned text = (Spanned) content;
Layout layout = getLayout();
for (int i = 0; i < layout.getLineCount(); ++i) {
int lineBaseline = layout.getLineBaseline(i) + getPaddingTop();
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
ImageSpan[] imageSpans = text.getSpans(lineStart, lineEnd, ImageSpan.class);
if (imageSpans.length > 0){//只适用于一张图片一行
imageSpans[0].draw(canvas,text,lineStart,lineEnd,getPaddingLeft(),0,0,layout.getLineBaseline(i),getSpannedPaint(text,lineStart));
}else if (alignOnlyOneLine && layout.getLineCount() == 1) {//只有一行
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
this.drawScaledText(canvas, text, lineStart, lineEnd, lineBaseline, width, true);
} else if (i == layout.getLineCount() - 1) {//最后一行
//canvas.drawText(text, lineStart, text.length(), getPaddingLeft(), lineBaseline, getPaint());
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
this.drawScaledText(canvas, text, lineStart, lineEnd, lineBaseline, width,false);
break;
} else {//中间行
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
boolean forceNextLine = text.charAt(lineEnd-1) == 10;
if (forceNextLine){
this.drawScaledText(canvas, text, lineStart, lineEnd, lineBaseline, width,false);
}else {
this.drawScaledText(canvas, text, lineStart, lineEnd, lineBaseline, width, true);
}
}
}
}else {
super.onDraw(canvas);
}
}
private void drawScaledText(Canvas canvas, String line, float baseLineY, float lineWidth) {
if (line.length() < 1) {
return;
}
float x = getPaddingLeft();
boolean forceNextLine = line.charAt(line.length() - 1) == 10;
int length = line.length() - 1;
if (forceNextLine || length == 0) {
canvas.drawText(line, x, baseLineY, getPaint());
return;
}
float d = (getMeasuredWidth() - lineWidth - getPaddingLeft() - getPaddingRight()) / length;
for (int i = 0; i < line.length(); ++i) {
String c = String.valueOf(line.charAt(i));
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, baseLineY, this.getPaint());
x += cw + d;
}
}
private void drawScaledText(Canvas canvas, Spanned text, int start, int end, float baseLineY, float lineWidth, boolean isAlign) {
if ((end - start) < 0) {
return;
}
float x = getPaddingLeft();
int length = end - start;
if (length == 0){
canvas.drawText(text, start, end, x, baseLineY, getSpannedPaint(text,start));
return;
}
float d;//每个字符间需要添加的间隔
if (isAlign){
d = (getMeasuredWidth() - lineWidth - getPaddingLeft() - getPaddingRight()) / length;
}else {
d = 0;
}
for (int i = 0; i < length; ++i) {
float cw = StaticLayout.getDesiredWidth(text,start + i,start + i+1, getSpannedPaint(text,start + i));
canvas.drawText(text, start + i,start + i + 1, x, baseLineY, getSpannedPaint(text,start + i));
x += cw + d;
}
}
/**
* 获取单个字符的式样
* @param text Spanned
* @param index 字符的索引
* @return TextPaint
*/
private TextPaint getSpannedPaint(Spanned text, int index){
TextPaint textPaint = new TextPaint();
textPaint.set(getPaint());
CharacterStyle[] characterSpans = text.getSpans(index, index+1, CharacterStyle.class);
if (characterSpans.length > 0){
for (CharacterStyle span:characterSpans){
span.updateDrawState(textPaint);
}
}
return textPaint;
}
}
<declare-styleable name="AlignTextView"> <attr name="alignOnlyOneLine" format="boolean"/> <attr name="android:textColor" format="color"/> <attr name="android:maxLines" format="integer"/> <attr name="android:ellipsize" format="integer"/> <attr name="android:textSize" format="dimension"/> </declare-styleable>