android文字动态环绕图片效果
目录
效果展示
代码分析
demo中的效果是手指拖动红色方块,文字自动排版,达到动态环绕的效果。
这里是通过继承View复写onDraw方法实现的。
package com.example.allen.flowtext; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class FlowTextView extends View { private String text = ""; private Paint paint; private Paint imgPaint; //图片宽高 private static int IMG_WIDTH = 170; private static int IMG_HEIGHT = 170; //文字高度,和文字宽度(所有文字的) private int textHeight, textWidth; //控件宽高(这里是重点表示排版的算法逻辑,onMeasure方法就没做定义,直接写死以充满整个父控件) private int width, height; //图片的矩形区域 private Rect imgRect; //图片的左下角坐标(控件坐标,左上角为0,0) private int rectX, rectY; //单个文字的宽高 private float wordWidth, wordHeight; //当前绘制到的位置坐标 private float currentX, currentY; public FlowTextView(Context context) { super(context); } //初始化,文字样式可以在此设置 public FlowTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); paint = new Paint(Paint.ANTI_ALIAS_FLAG); imgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); paint.setTextSize(50f); imgPaint.setColor(Color.RED); } public FlowTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);//主意布局中不可以为at_most width = getMeasuredWidth(); height = getMeasuredHeight(); measureTextHeight(); imgRect = new Rect(rectX, rectY, rectX + IMG_WIDTH, rectY + IMG_HEIGHT); currentX = 0; currentY = wordHeight; } public void setText(String text) { this.text = text; rectX = 200; rectY = 200; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); currentX = 0; currentY = wordHeight; for (int i = 0; i < text.length(); i++) { String str = text.substring(i, i + 1); if (currentX > width - wordWidth) {//换行 currentY += wordHeight; currentX = 0; } if (currentX <= imgRect.left && currentY < imgRect.bottom && currentY >= imgRect.top) { if (currentX + wordWidth > imgRect.left) { currentX = imgRect.right; } } if (currentY - wordHeight < imgRect.bottom && currentX < imgRect.right && currentX + wordWidth > imgRect.left) { if (currentY > imgRect.top) { currentY = imgRect.bottom + wordHeight; } } canvas.drawText(str, currentX, currentY, paint); currentX += wordWidth; } RectF rectF = new RectF(imgRect); canvas.drawRoundRect(rectF, 40f, 40f, imgPaint); } private boolean isDrag; private int offsetX, offsetY; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: int x = (int) event.getX(); int y = (int) event.getY(); if (imgRect.contains(x, y)) { isDrag = true; offsetX = x - rectX; offsetY = y - rectY; } break; case MotionEvent.ACTION_MOVE: int moveX = (int) event.getX(); int moveY = (int) event.getY(); if (isDrag) { rectX = moveX - offsetX; rectY = moveY - offsetY; if (rectX < 0) rectX = 0; if (rectY < 0) { rectY = 0; } if (rectX > width - IMG_WIDTH) { rectX = width - IMG_WIDTH; } if (rectY > height - IMG_HEIGHT) { rectY = height - IMG_HEIGHT; } } imgRect.left = rectX; imgRect.top = rectY; imgRect.right = imgRect.left + IMG_WIDTH; imgRect.bottom = imgRect.top + IMG_HEIGHT; invalidate(); break; case MotionEvent.ACTION_UP: isDrag = false; offsetX = 0; offsetY = 0; break; } return true; } private void measureTextHeight() { Rect rect = new Rect(); paint.getTextBounds(text, 0, text.length(), rect); textWidth = rect.width();//文字宽 textHeight = rect.height();//文字高 //单个文字宽高 wordWidth = textWidth * 1.0f / text.length(); wordHeight = textHeight * 1.0f; } }
重点是onDraw方法,绘制是以单个文字为单元,每次绘制时判断图片位置是否冲突。另外还多了个换行逻辑。