我有一个应用程序,可以分页大文本,并为每个单词或句子设置多个跨度.我正在使用ReplacementSpan为每个单词绘制背景.我不能使用BackgroundSpan,因为它太简单了,不能让我控制画布.由于ReplacementSpan扩展了MetricAffectingSpan,它影响了文本的布局,完全打破了我的分页.我正在使用StaticLayout来计算每个页面的文本,而StaticLayout不允许跨越,因此它可以计算跨越大小影响的先验.
ReplacementSpan有替代品吗?如何在不影响文本大小和布局的情况下绘制我想要的背景?
这是我的replacementspan的代码:
public class BackgroundColorWithoutLineHeightSpan extends ReplacementSpan {
private static final float DP_ACTIVE = ViewsUtils.dpToPx(4);
private static final int DP_OUTSIDE_PADDING = (int) ViewsUtils.dpToPx(6);
private static final float DP_PHRASE = ViewsUtils.dpToPx(4);
private static final float DP_ROUNDED = ViewsUtils.dpToPx(3);
private final int mColor;
private final int mTextHeight;
private int mBorderColor;
private boolean mIsSelected;
private boolean mIsPhrase;
public BackgroundColorWithoutLineHeightSpan(int color,int textHeight,boolean isPhrase) {
mColor = color;
mTextHeight = textHeight;
mIsPhrase = isPhrase;
}
public BackgroundColorWithoutLineHeightSpan(int color,boolean isSelected,int borderColor,boolean isPhrase) {
mColor = color;
mTextHeight = textHeight;
mIsSelected = isSelected;
mBorderColor = borderColor;
mIsPhrase = isPhrase;
}
@Override
public int getSize(@NonNull Paint paint,CharSequence text,int start,int end,Paint.FontMetricsInt fm) {
return Math.round(measureText(paint,text,start,end));
}
@Override
public void draw(@NonNull Canvas canvas,float x,int top,int y,int bottom,Paint paint) {
canvas.save();
Rect newRect = canvas.getClipBounds();
newRect.inset(-DP_OUTSIDE_PADDING,-DP_OUTSIDE_PADDING);
canvas.clipRect(newRect,Region.Op.REPLACE);
float measuredText = measureText(paint,end);
int paintColor = paint.getColor();
if (!mIsSelected) {
RectF rect;
rect = new RectF(x,top,x + measuredText,top + mTextHeight);
paint.setStrokeWidth(0.0f);
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rect,DP_ROUNDED,paint);
} else {
RectF rect;
if (mIsPhrase) {
rect = new RectF(x - DP_PHRASE,top - DP_PHRASE,x + measuredText + DP_PHRASE,top + mTextHeight + DP_PHRASE);
} else {
rect = new RectF(x - DP_ACTIVE,top - DP_ACTIVE,x + measuredText + DP_ACTIVE,top + mTextHeight + DP_ACTIVE);
}
paint.setStrokeWidth(0.0f);
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rect,paint);
RectF border;
if (mIsPhrase) {
border = new RectF(x - DP_PHRASE,top + mTextHeight + DP_PHRASE);
} else {
border = new RectF(x - DP_ACTIVE,top + mTextHeight + DP_ACTIVE);
}
paint.setColor(mBorderColor);
paint.setStrokeWidth(4.0f);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(border,paint);
}
paint.setStyle(Paint.Style.FILL);
paint.setColor(paintColor);
canvas.drawText(text,end,x,y,paint);
canvas.restore();
}
private float measureText(Paint paint,int end) {
return paint.measureText(text,end);
}
}
最佳答案
尝试这个简单的跨度,它在所有跨度上绘制纯红色背景(即使它是多行跨度)但你可以绘制任何你喜欢的:
原文链接:https://www.f2er.com/android/430041.htmlclass LBS implements LineBackgroundSpan {
private final TextView tv;
private int start;
private int end;
public LBS(TextView tv,int end) {
this.tv = tv;
this.start = start;
this.end = end;
}
@Override
public void drawBackground(Canvas c,Paint p,int left,int right,int baseline,int lnum) {
Layout layout = tv.getLayout();
int startLine = layout.getLineForOffset(this.start);
int endLine = layout.getLineForOffset(this.end);
if (startLine <= lnum && lnum <= endLine) {
if (startLine == lnum) {
left = (int) layout.getPrimaryHorizontal(this.start);
}
if (endLine == lnum) {
right = (int) layout.getPrimaryHorizontal(this.end);
}
int origColor = p.getColor();
p.setColor(Color.RED);
c.drawRect(left,right,bottom,p);
p.setColor(origColor);
}
}
}
测试代码(设置0和ssb.length()作为开始和结束不是非常有效,所以你可以优化它):
TextView tv = new TextView(this);
setContentView(tv);
tv.setTextSize(32);
SpannableStringBuilder ssb = new SpannableStringBuilder("Chop a handfull spinach,pork shoulder,and dill in a large cooker over medium heat,cook for six minutes and varnish with some bok choy.");
LBS span = new LBS(tv,30,100);
ssb.setSpan(span,ssb.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
Log.d(TAG,"onCreate text [" + ssb.subSequence(30,100) + "]");
编辑
class LBS implements LineBackgroundSpan {
TextView tv;
List
测试代码:
TextView tv = new TextView(this);
setContentView(tv);
tv.setTextSize(32);
String text = "Chop a handfull spinach,cook for six minutes and varnish with some bok choy.";
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
LBS span = new LBS(tv);
String[] words = {
"spinach,pork shoulder","cooker","with some bok choy",};
for (String word : words) {
int idx = text.indexOf(word);
span.add(idx,idx + word.length());
}
ssb.setSpan(span,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);