答案 0 :(得分:1)
您可以使用DynamicLayout和SpannableStringBuilder而不是TextView来完成它。
首先,您需要知道ImageView的界限,如果将DynamicLayout和ImageView放在自定义的ViewGroup中会更容易,因为这会将它们放在相同的坐标空间中。
second ,使用方法 getLineForVertical 根据Bound rect的顶值获取DynamicLayout中的第一行。并使用DynamicLayout方法获取与Bound rect的左值最接近的偏移量< strong> getOffsetForHorizontal ,然后在偏移后插入一个空格字符,并创建一个ImageSpan,其中一个空的drawable的宽度为Bound rect的宽度,并将ImageSpan放在SpannableStringBuilder中,并使span开始于offset并以偏移+ 1。
第三次,行++并重复第二步,直到getLineTop(line)值大于Bound rect的底部。
我为你写了一个演示,你可以在里面移动Rectangle来看看DynamicLayout如何为Rectangle重新布局,但是确保你不要将矩形移到DynamicLayout之外,它会崩溃。我没有解决这个原因,它只是一个演示。
public class DynamicRichText extends View {
private DynamicLayout mLayout;
private Point mCirclePosition;
private int mCircleRadius;
private Rect mRect;
private TextPaint mTextPaint;
private int latestFirstLine;
private int latestLastLine;
private int latestOffsetStart;
private int latestOffsetEnd;
private SpannableStringBuilder mText;
public DynamicRichText(Context context){
this(context, null);
}
public DynamicRichText(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public DynamicRichText(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
mText = new SpannableStringBuilder("abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz");
mRect = new Rect();
mCirclePosition = new Point();
mCircleRadius = 120;
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(80);
mTextPaint.setColor(0xFF0099CC);
}
@Override
public boolean onTouchEvent(MotionEvent event){
if(event.getActionMasked() == MotionEvent.ACTION_MOVE){
mCirclePosition.x = (int) event.getX();
mCirclePosition.y = (int) event.getY();
mRect.left = mCirclePosition.x - mCircleRadius;
mRect.right = mCirclePosition.x + mCircleRadius;
mRect.top = mCirclePosition.y - mCircleRadius;
mRect.bottom = mCirclePosition.y + mCircleRadius;
resolveLayout();
invalidate();
}
return true;
}
private void resolveLayout(){
Object[] spans = mText.getSpans(latestOffsetStart, latestOffsetEnd, Object.class);
for(int i = 0; i < spans.length; i++){
int start = mText.getSpanStart(spans[i]);
if(spans[i] instanceof ImageSpan) mText.delete(start, start + 1);
mText.removeSpan(spans[i]);
}
int line = mLayout.getLineForVertical(mRect.top);
int offsetStart = mLayout.getOffsetForHorizontal(line, mRect.left) - 1;
latestOffsetStart = offsetStart;
while(mLayout.getLineTop(line) < mRect.bottom){
offsetStart = mLayout.getOffsetForHorizontal(line, mRect.left) - 1;
int lineHeight = mLayout.getLineBottom(line) - mLayout.getLineTop(line);
mText.insert(offsetStart, " ");
ColorDrawable emptyDrawable = new ColorDrawable(0x0);
emptyDrawable.setBounds(0, 0, mRect.width() + (int) mTextPaint.getTextSize(), lineHeight);
ImageSpan emptySpan = new ImageSpan(emptyDrawable);
mText.setSpan(emptySpan, offsetStart, offsetStart + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
line++;
}
latestOffsetEnd = offsetStart + 1;
}
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh){
mCirclePosition = new Point(w / 2, h / 2);
mLayout = new DynamicLayout(mText, mText, mTextPaint, w, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
}
@Override
public void onDraw(Canvas canvas){
mTextPaint.setColor(0xFF000000);
canvas.drawRect(mRect, mTextPaint);
mTextPaint.setColor(0xFF0099CC);
mLayout.draw(canvas);
}
}
如果您将其更改为扩展ViewGroup或其他布局窗口小部件。并根据ImageView的bound创建Rect。您可以在xml中使用此小部件