图片+文本自动换行控件

编程入门 行业动态 更新时间:2024-10-19 00:26:10

图片+文本自动换行<a href=https://www.elefans.com/category/jswz/34/1769529.html style=控件"/>

图片+文本自动换行控件

做下自定义的练习。实现一个图片+文本自动换行的自定义控件,效果如下图所示:


第一步:设置自定义属性attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="ImageText"><attr name="src" format="reference" /><attr name="text" format="string|reference" /><attr name="textSize" format="dimension" /></declare-styleable></resources>

设置一下这三个属性,在这个自定义view会使用到。

src:drawable路径

text:文字内容

textSize:文字的sp大小

第二步:创建ImageTextView类继承View,定义一下构造方法

package com.example.androiddemo;import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
/*** 图片+文字自动换行view* @author lwd*/
public class ImageTextView extends View {public ImageTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public ImageTextView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ImageTextView(Context context) {this(context, null);}}

第三步:写一个使用这个自定义的布局文件:activity_main.xml

<LinearLayout xmlns:android=""xmlns:tools=""xmlns:ImageText=".example.androiddemo"android:id="@+id/layout_main"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"android:orientation="vertical" ><com.example.androiddemo.ImageTextViewandroid:id="@+id/imagetext1"android:layout_width="wrap_content"android:layout_height="wrap_content"ImageText:src="@drawable/test"ImageText:text="每个人都有自己的不容易,工作的压力,生活的烦恼。有太多的情绪,我们都是在用力克制着。因为我们知道,如果自己不坚强,没有人可以替我们勇敢。曾经看过一段话说,有这么几样东西,我们绝对不可以丢掉。扬在脸上的自信,长在心底的里善良,融进血液里的骨气,还有刻进生命里的坚强。"ImageText:textSize="18sp"android:background="#FFFFFFFF" /></LinearLayout>
现在这里没有对“\n”等特殊字符做处理。

第四步:在构造方法获取自定义属性

TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ImageText);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(R.styleable.ImageText_src, R.drawable.ic_launcher));
text = typedArray.getString(R.styleable.ImageText_text);
textSize = typedArray.getDimension(R.styleable.ImageText_textSize, 14);//textSize默认大小14

TypeArray使用完后,记得recycle(),还有无用的bitmap对象也进行recycle();

对获取到文本进行判空,为空时,赋值“”,其他两个属性有默认值。

创建画笔Paint,先设置paint.setTextSize(textSize);,再获取FontMetrics

paint.setTextSize(textSize);
paint.setAntiAlias(true);//抗锯齿
fm = paint.getFontMetrics();
baseLine = fm.descent - fm.ascent;

获取文本绘制矩形的宽和对图片进行缩放适配文字高度

Rect rect = new Rect();
//返回包围整个字符串的最小的一个Rect区域  
paint.getTextBounds(text, 0, text.length(), rect);textWidth = rect.width();//bitmap宽高
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();// 计算缩放比例.
float scaleHeight = (float) (((float) baseLine) / bitmapHeight);
float scaleWidth = scaleHeight;
// 取得想要缩放的matrix参数.
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片.
bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
// bitmap宽高
bmpHeight = bmp.getHeight();
bmpWidth = bmp.getWidth();
		
bitmap.recycle();
typedArray.recycle();

第五步:重写onMeasure,计算在AT_MOST的情况下View的width和height的值

1、确定图片+文本需要显示行数,图片+文本的宽/父容器的宽=显示行数

2、View的宽不能超过父容器的宽

3、view的高height,文本的行高:baseLine = fm.descent - fm.ascent; 第一行的时候,因为图片比文本高,采用图片的高度,第二行再加上文本的高度

4、EXACTLY和UNSPECIFIED的情况下,不计算。直接MeasureSpec.getSize();

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 如果自定义TextView中的宽高给的是确定的值,比如10dp、20dp、match_parent,这个时候不需要计算,给的多少就是多少int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 如果自定义TextView中的宽高给的是wrap_content,则需要计算宽高int heightMode = MeasureSpec.getMode(heightMeasureSpec);int lineCount = 0;//默认存在第0行(即默认存在一行)int parentWidth = 0;//父view宽try {ViewGroup mViewGroup = (ViewGroup) getParent();parentWidth = mViewGroup.getMeasuredWidth();//向下取整lineCount = (int) Math.floor((textWidth + getPaddingLeft() + getPaddingRight() + bmpWidth) / parentWidth);} catch (Exception e) {e.printStackTrace();}int width = MeasureSpec.getSize(widthMeasureSpec);// 2. 如果文字的大小给的是wrap_content,则需要计算大小if (widthMode == MeasureSpec.AT_MOST) {//width不超过父容器的宽度if (lineCount == 0) {width = textWidth + getPaddingLeft() + getPaddingRight() + bmpWidth;}else {width = parentWidth;}}int height = (int) (MeasureSpec.getSize(heightMeasureSpec) + baseLine * 0.3);if (heightMode == MeasureSpec.AT_MOST) {// 区域height = (int) (bmpHeight + ((baseLine + fm.leading)* lineCount) + getPaddingTop() + getPaddingBottom() + baseLine * 0.3);}viewWidth = width;// 设置控件的宽高,这里就是给文字设置宽高setMeasuredDimension(width, height);
}

第六步:重写onDraw,drawBitmap和drawText,对text分段装到一个String数组里面

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);float x = bmpWidth;float y = baseLine;canvas.drawBitmap(bmp, 0, 0, paint);String texts[] = autoSplit(text, paint, viewWidth);for (int i = 0; i < texts.length; i++) {if (i == 0) {canvas.drawText("" + texts[i], x, bmpHeight, paint);}else {x = 0;canvas.drawText("" + texts[i], x, bmpHeight + y, paint);y += baseLine + fm.leading; //添加字体行间距}}
}

在拆分第一行文本,文本宽度加上图片宽度与控件宽度比较

把拆分出来的文本最后一个文字摘出去,因为加上最后一个文字,最后这个文字会显示不全,放到下一行文本中。

private String[] autoSplit(String content, Paint paint, float viewWidth) {int length = content.length();int start = 0;int end = 1;int i = 0;int lines = (int) Math.ceil((textWidth + bmpWidth) / viewWidth);String[] lineTexts = new String[lines]; Rect rect = new Rect();int textLineWidth = 0;paint.getTextBounds(text, start, text.length(), rect);float textWidth = rect.width();//获取文字的显示宽度if ((textWidth + bmpWidth) <= viewWidth) {return new String[]{content};}while (start < end) {if (start == 0) {paint.getTextBounds(text, start, end, rect);textLineWidth = rect.width();if ((textLineWidth + bmpWidth) > viewWidth) {String subContent = (String) content.subSequence(start, end - 1);lineTexts[i++] = subContent;start = end - 1;}}else {paint.getTextBounds(text, start, end, rect);textLineWidth = rect.width();if (textLineWidth > viewWidth) {String subContent = (String) content.subSequence(start, end - 1);lineTexts[i++] = subContent;start = end - 1;}}if (end == length) {lineTexts[i] = (String) content.subSequence(start, end);break;}end += 1;}rect = null;return lineTexts;
}

完整代码传送门: 点击打开链接

更多推荐

图片+文本自动换行控件

本文发布于:2024-02-06 12:52:42,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1749169.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:控件   换行   文本   图片

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!