此控件是为了解决单行文本后面跟多张图片,当文字超长时省略号显示
此控件分几种情况只显示图片,只显示文字,图文混合显示(都是单行)任何情况下会自动计算单行显示最大数量
此控件要求多张图片高度必须是一致的,宽度不限制,
CustomTextImageMix customTextImageMix= (CustomTextImageMix) findViewById(R.id.tv_custom);
List<Integer> list=new ArrayList<>();
list.add(R.mipmap.mingqix1);
customTextImageMix.setImageIndexList(list);
<com.cx.wdiget.CustomTextImageMix
android:id="@+id/tv_custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/tv_3"
android:layout_toRightOf="@+id/tv_2"
android:visibility="visible"
imageText:imagePadding="@dimen/dimen_8dp"
imageText:textImagePadding="@dimen/dimen_8dp"
imageText:text="---------"
imageText:textColor="#00c0c7"
imageText:textSize="10sp" />
package com.cx.wdiget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
*
* 单行文本和多张图片混合展示
* (任意文字或者图片超长会自动计算合适的展示方式)
*
* 绘制的图片和文字默认是居中的
*
* Created by ChenXin on 2017/10/12
*/
public class CustomTextImageMix extends View {
/**展示的图片高度**/
private int bitmapHeight = ;
/**整个控件的宽度**/
private int viewWidth = ;
/**绘制字体的最大宽度**/
private float textMaxWidth = ;
/**文字展示的最小字数**/
private int minTextLength = ;
/**绘制的文本**/
private String mText;
/**文字的大小**/
private int mTextSize;
/**图片之间的间距**/
private int mImagePadding;
/**文字和第一张图片之间的间距**/
private int textImagePadding;
/**字体颜色(R.color.xx)**/
private int mTextColor;
/**图片引用id(R.mipmap.xx)**/
private List<Integer> mImageIndexList = new ArrayList<>();
/****/
private final String ELLIPSIS = "...";
private Paint paint;
private Paint.FontMetricsInt fontMetrics;
public CustomTextImageMix(Context context) {
this(context, null);
}
public CustomTextImageMix(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public CustomTextImageMix(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Custom_textImage, defStyleAttr, );
mText = typedArray.getString(R.styleable.Custom_textImage_text);
mTextSize = (int) typedArray.getDimension(R.styleable.Custom_textImage_textSize, R.dimen.dimen_11sp);
mTextColor = typedArray.getColor(R.styleable.Custom_textImage_textColor, Color.BLACK);
mImagePadding = (int) typedArray.getDimension(R.styleable.Custom_textImage_imagePadding, R.dimen.dimen_2dp);
textImagePadding = (int) typedArray.getDimension(R.styleable.Custom_textImage_textImagePadding, R.dimen.dimen_2dp);
minTextLength=typedArray.getInteger(R.styleable.Custom_textImage_minTextLength,);
paint = new Paint();
paint.setColor(mTextColor);
paint.setTextSize(mTextSize);
fontMetrics = paint.getFontMetricsInt();
typedArray.recycle();
}
/**
* 展示图片的数据集合
*
* @param imageIndexList 展示图片的id
*/
public void setImageIndexList(List<Integer> imageIndexList) {
if (imageIndexList != null) {
mImageIndexList = imageIndexList;
bitmapHeight = getBitmapHeight(mImageIndexList.get());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int textHeight=fontMetrics.bottom-fontMetrics.top;
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(bitmapHeight>textHeight?bitmapHeight:textHeight));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (TextUtils.isEmpty(mText) && mImageIndexList.size() == ) {
return;
}
viewWidth = getWidth();
executeOnDraw(canvas);
}
/**
* 绘制逻辑
*
* @param canvas canvas
*/
private void executeOnDraw(Canvas canvas) {
if (!TextUtils.isEmpty(mText) && mImageIndexList.size() == ) { //只绘制文字
textMaxWidth = viewWidth;
showText();
drawTextImage(canvas);
} else if (TextUtils.isEmpty(mText) && mImageIndexList.size() > ) {//只绘制图片
drawTextImage(canvas);
} else { //图片文字都有
float allImageWidth = getAllImageWidth();
float allTextWidth = paint.measureText(mText);
if (allImageWidth + allTextWidth <= viewWidth) { //图片文字刚好都能绘制
drawTextImage(canvas);
} else { //图片文字进行测量后绘制合适文字字数和图片数量
float minTextWidth = getMinTextWidth();
textMaxWidth = viewWidth - allImageWidth;
if (textMaxWidth <= || textMaxWidth < minTextWidth) {
mText = (mText.length() > minTextLength) ? mText.substring(, minTextLength) + ELLIPSIS : mText;
drawTextImage(canvas);
} else {
showText();
drawTextImage(canvas);
}
}
}
}
/**
* 执行图文绘制
* <p/>
* 这里绘制的文字和图片都是计算后能够允许绘制的
*
* @param canvas canvas
*/
private void drawTextImage(Canvas canvas) {
if (canvas == null) {
return;
}
Rect rect = new Rect();
boolean haveText = !TextUtils.isEmpty(mText);
if (haveText) {
paint.getTextBounds(mText, , mText.length(), rect);
//当图片的高度大于文字的高度时要以图片为中心文字和图片居中
//文字的baseLine=(viewHeight - (paint.descent() - paint.ascent())) / 2 - paint.ascent()
//viewHeight是控件的高度,如果我们绘制的控件要求刚好包裹,那么当图片高度大于字体高度时则viewHeight=BitmapHeight(居中)
//当字体的高度大于图片高度时viewHeight=TextHeight=(-fontMetrics.top+fontMetrics.bottom)
if (bitmapHeight > mTextSize) {
canvas.drawText(mText, rect.left, (bitmapHeight - (paint.descent() - paint.ascent())) / - paint.ascent(), paint);
} else {
canvas.drawText(mText, rect.left, -fontMetrics.top, paint);
}
}
float left = Math.abs(rect.left) + Math.abs(rect.right);
for (int i = ; i < mImageIndexList.size(); i++) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), mImageIndexList.get(i));
if (i == ) {
left = left + (haveText ? textImagePadding : );
} else {
left = left + bitmap.getWidth() + mImagePadding;
}
if (left <= viewWidth) {
//当图片高度大于文字时,绘制从顶点0开始绘制
//当文字高度大于图片高度时要图片和文字居中则绘制顶点Math.abs((-fontMetrics.top + fontMetrics.bottom) / 2 - bitmap.getHeight() / 2
canvas.drawBitmap(bitmap, left, (bitmapHeight > mTextSize) ? : Math.abs((-fontMetrics.top + fontMetrics.bottom) / - bitmap.getHeight() / ), paint);
}
}
}
/**
* 计算能显示的文字
* <p/>
* 当文字的总宽度大于了文字绘制的最大宽度,则需要截取文字加上省略号
* <p/>
* 计算后会生成新的绘制文字
*/
private void showText() {
if (TextUtils.isEmpty(mText) || textMaxWidth <= ) {
return;
}
float allTextWidth = paint.measureText(mText);//文字总宽度
if (allTextWidth > textMaxWidth) {
int showTextLength=paint.breakText(mText,true,textMaxWidth-getEllipsisWidth(),null);
mText=mText.substring(,showTextLength)+ELLIPSIS;
}
}
/**
* 计算文字绘制的最小宽度
* <p/>
* 当图片的宽度之和大于了整个view的宽度则必须预留绘制字体的最小宽度
*
* @return 文本绘制最小距离
*/
private float getMinTextWidth() {
float minWidth = ;
if (TextUtils.isEmpty(mText)) {
return minWidth;
}
int textLength = mText.length();
if (textLength <= minTextLength) {
minWidth = paint.measureText(mText);
} else {
minWidth = paint.measureText(mText.substring(, minTextLength) + ELLIPSIS);
}
return minWidth;
}
private float getEllipsisWidth() {
return paint.measureText(ELLIPSIS);
}
/**
* @return 获取所有需要展示的图片宽度和
*/
private int getAllImageWidth() {
int width = ;
if (mImageIndexList.size() <= ) {
return width;
}
boolean haveText = !TextUtils.isEmpty(mText);
for (int i = ; i < mImageIndexList.size(); i++) {
if (i == ) {
width = width + getBitmapWidth(mImageIndexList.get(i)) + (haveText ? textImagePadding : );
} else {
width = width + getBitmapWidth(mImageIndexList.get(i)) + mImagePadding;
}
}
return width;
}
/**
*
* 获取图片的宽度
*
* @param imageIndex 图片的id
* @return 图片宽度
*/
private int getBitmapWidth(int imageIndex) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), imageIndex, options); // 此时返回的bitmap为null
return options.outWidth;
} catch (Exception e) {
e.getLocalizedMessage();
}
return ;
}
/**
*
* 获取图片的高度
*
* @param imageIndex 图片的id
* @return 图片高度
*/
private int getBitmapHeight(int imageIndex) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), imageIndex, options); // 此时返回的bitmap为null
return options.outHeight;
} catch (Exception e) {
e.getLocalizedMessage();
}
return ;
}
private void writeLog(String msg) {
Log.v("TextImageView--:", msg);
}
}