此控件是為了解決單行文本後面跟多張圖檔,當文字超長時省略号顯示
此控件分幾種情況隻顯示圖檔,隻顯示文字,圖文混合顯示(都是單行)任何情況下會自動計算單行顯示最大數量
此控件要求多張圖檔高度必須是一緻的,寬度不限制,
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);
}
}