可以控制最多顯示多少個(gè)帖族,多余最大數(shù)量則在最后一行以文字提示,通過控制maxSize大小來控制最多顯示圖片數(shù)量挡爵。效果如下圖所示
-
app:maxSize="2"
-
app:maxSize="5"
-
app:maxSize="9"
只有一行顯示圖片竖般,多出來的圖在最后一張圖上顯示圖片總數(shù)量。
1 需要用到的知識(shí)
- MeasureSpec.getSize(widthMeasureSpec)
指的是總寬度茶鹃,包含padding的值 - setMeasuredDimension(width, height)
設(shè)置測(cè)量的尺寸涣雕。重寫onMeasure后需要調(diào)用該方法,否則自定義的控件不會(huì)顯示前计。 - generateDefaultLayoutParams()
使用默認(rèn)的布局參數(shù)胞谭,寬高都是wrap_content - textView.bringToFront()
將視圖圖層放在最上層顯示 - textView.setBackgroundColor(0x80000000)
設(shè)置背景半透明 - FontMetrics
FontMetrics為字體度量垃杖,指對(duì)于指定字號(hào)的某種字體男杈,在度量方面的各種屬性,其描述參數(shù)包括:
- baseline:字符基線
- ascent:字符最高點(diǎn)到baseline的推薦距離
- top:字符最高點(diǎn)到baseline的最大距離
- descent:字符最低點(diǎn)到baseline的推薦距離
- bottom:字符最低點(diǎn)到baseline的最大距離
- leading:行間距调俘,即前一行的descent與下一行的ascent之間的距離
參考圖片
- getTextBounds
獲取文本內(nèi)容矩形
2 問題
- 文本沒有居中伶棒,使用textView.setGravity(Gravity.CENTER)只能水平居中顯示旺垒。
解決方法:
//設(shè)置文字位置
// 1.用FontMetrics對(duì)象計(jì)算高度
Paint.FontMetricsInt fontMetricsInt = textView.getPaint().getFontMetricsInt();
int textHeight = fontMetricsInt.bottom - fontMetricsInt.top;//文本高度
int paddingTop = (mImageSize - textHeight) / 2;
//方法一:設(shè)置居中,setGravity(Gravity.CENTER)只顯示為水平居中,所以需要設(shè)置padding
textView.setPadding(0, paddingTop, 0, paddingTop);
textView.setGravity(Gravity.CENTER);
//方法二:設(shè)置居中
// Rect bounds = new Rect();
// textView.getPaint().getTextBounds(text, 0, text.length(), bounds);
// int textWidth = bounds.right - bounds.left;
// int paddingLeft = (mImageSize - textWidth) / 2;
// textView.setPadding(paddingLeft, paddingTop, 0, 0);
3 完全代碼
ThreeImageView.java
package com.yds.jianshulib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.yds.jianshulib.R;
import java.util.ArrayList;
import java.util.List;
/**
* Created by yds
* on 2020/3/11.
*/
public class ThreeImageView<T> extends ViewGroup {
private Context mContext;
private int mGap;//圖片間距
private int mSingleImgSize;//單張圖片尺寸
private int mMaxSize = 3;//最大圖片數(shù)
private List<ImageView> mImageViewList = new ArrayList<>();
private List<T> mImgDataList;
private int mImageSize;//圖片大小
private int mRowCount;//行數(shù)肤无,用于后續(xù)擴(kuò)展
private int mColumnCount;//列數(shù)
private TextView textView;
public ThreeImageView(Context context) {
this(context, null);
}
public ThreeImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ThreeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
this.mContext = context;
//自定義xml屬性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ThreeImageView);
this.mGap = (int) typedArray.getDimension(R.styleable.ThreeImageView_imgGap, 0);
this.mSingleImgSize = typedArray.getDimensionPixelSize(R.styleable.ThreeImageView_singleImgSize, -1);
this.mMaxSize = typedArray.getInteger(R.styleable.ThreeImageView_maxSize, 3);
typedArray.recycle();
}
private void layoutChildrenView() {
if (mImgDataList == null) return;
int showChildrenCount = getNeedShowCount(mImgDataList.size());
layoutMaxCountChildrenView(showChildrenCount);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
layoutChildrenView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取總寬度
int width = MeasureSpec.getSize(widthMeasureSpec);
//獲取總高度
int height = MeasureSpec.getSize(heightMeasureSpec);
//控件內(nèi)容的總寬度
int totalWidth = width - getPaddingLeft() - getPaddingRight();
if (mImgDataList != null && mImgDataList.size() > 0) {
//如果圖片只有一個(gè)且單個(gè)圖片尺寸不為-1
if (mImgDataList.size() == 1 && mSingleImgSize != -1) {
//圖片尺寸取總寬度與單個(gè)圖片寬度中的較小值
mImageSize = mSingleImgSize > totalWidth ? totalWidth : mSingleImgSize;
} else {
//如果圖片不止有一個(gè)先蒋,則圖片尺寸為(總寬度-圖片間總間距)/圖片數(shù)量
mImageSize = (totalWidth - mGap * (mColumnCount - 1)) / mColumnCount;
}
//(圖片尺寸*行數(shù))+總間距+上內(nèi)邊距+下內(nèi)邊距 設(shè)置行數(shù)是為后續(xù)擴(kuò)展
height = mImageSize * mRowCount + mGap * (mRowCount - 1) + getPaddingTop() + getPaddingBottom();
}
//設(shè)置測(cè)量的尺寸
setMeasuredDimension(width, height);
}
private void layoutMaxCountChildrenView(int childrenCount) {
int left = 0, top = 0, right=0, bottom=0;
for (int i = 0; i < childrenCount; i++) {
ImageView childrenView = (ImageView) getChildAt(i);
childrenView.setScaleType(ImageView.ScaleType.CENTER_CROP);
left = getPaddingLeft()+i%3*mImageSize+i%3*mGap;
top = getPaddingTop()+i/3*mImageSize+i/3*mGap;
right = left+mImageSize;
bottom = top + mImageSize;
childrenView.layout(left,top,right,bottom);
Glide.with(mContext).load(mImgDataList.get(i)).into(childrenView);
}
showImageAndText(left,top,right,bottom);
}
private void showImageAndText(int left,int top,int right,int bottom){
if (mImgDataList.size() > mMaxSize) {
if (textView != null) {
textView.bringToFront();
//設(shè)置字體大小
String text = "共" + mImgDataList.size() + "張圖";
int textSize = px2sp(mContext, mImageSize / 6);
textView.setTextSize(textSize);
textView.setText(text);
//設(shè)置文本顏色及背景半透明
textView.setTextColor(Color.WHITE);
textView.setBackgroundColor(0x80000000);
//設(shè)置文字位置
// 1.用FontMetrics對(duì)象計(jì)算高度
Paint.FontMetricsInt fontMetricsInt = textView.getPaint().getFontMetricsInt();
int textHeight = fontMetricsInt.bottom - fontMetricsInt.top;//文本高度
int paddingTop = (mImageSize - textHeight) / 2;
//方法一:設(shè)置居中,setGravity(Gravity.CENTER)只顯示為水平居中,所以需要設(shè)置padding
textView.setPadding(0, paddingTop, 0, paddingTop);
textView.setGravity(Gravity.CENTER);
//方法二:設(shè)置居中
// Rect bounds = new Rect();
// textView.getPaint().getTextBounds(text, 0, text.length(), bounds);
// int textWidth = bounds.right - bounds.left;
// int paddingLeft = (mImageSize - textWidth) / 2;
// textView.setPadding(paddingLeft, paddingTop, 0, 0);
textView.layout(left, top, right, bottom);
//這里設(shè)置只會(huì)顯示水平居中宛渐,所以需要上面的padding
}
}
}
/**
* 獲取需要顯示的數(shù)量
*
* @param size
* @return
*/
private int getNeedShowCount(int size) {
//如果size大于最大顯示數(shù)量竞漾,則用最大顯示數(shù)量
if (mMaxSize > 0 && size > mMaxSize) {
return mMaxSize;
} else {
//如果size小于最大顯示數(shù)量,則用size顯示數(shù)量
return size;
}
}
/**
* 設(shè)置圖片數(shù)據(jù)
*
* @param list
*/
public void setImagesData(List<T> list) {
mImgDataList = list;
removeAllViews();
if (list == null || list.size() == 0) {
//如果圖片列表為空窥翩,則隱藏控件
this.setVisibility(GONE);
} else {
//如果圖片列表不為空业岁,則顯示
this.setVisibility(VISIBLE);
}
//獲取需要顯示的數(shù)量
int showCount = getNeedShowCount(list.size());
//計(jì)算參數(shù),根據(jù)需要顯示的數(shù)量計(jì)算行數(shù)和列數(shù)
int[] params = calculateParam(showCount);
mRowCount = params[0];//行數(shù)
mColumnCount = params[1];//列數(shù)
for (int i = 0; i < showCount; i++) {
ImageView iv = getImageView(i);
if (iv == null) {
return;
}
addView(iv, generateDefaultLayoutParams());
if (i == mMaxSize - 1 && list.size() > mMaxSize) {
textView = new TextView(mContext);
addView(textView, generateDefaultLayoutParams());
}
}
requestLayout();
}
protected int[] calculateParam(int imageSize) {
int[] params = new int[2];
params[0] = imageSize / 3 + (imageSize % 3 == 0 ? 0 : 1);
params[1] = 3;
return params;
}
private ImageView getImageView(final int position) {
if (position < mImageViewList.size()) {
return mImageViewList.get(position);
} else {
ImageView imageView = new ImageView(mContext);
mImageViewList.add(imageView);
return imageView;
}
}
public void setGap(int gap) {
this.mGap = gap;
}
public int getGap() {
return mGap;
}
/**
* 設(shè)置只有一張圖片時(shí)的尺寸大小
*
* @param singleImgSize 單張圖片的尺寸大小
*/
public void setSingleImgSize(int singleImgSize) {
mSingleImgSize = singleImgSize;
}
/**
* 設(shè)置最大圖片數(shù)
*
* @param maxSize 最大圖片數(shù)
*/
public void setMaxSize(int maxSize) {
mMaxSize = maxSize;
}
private int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
}
res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ThreeImageView">
<attr name="singleImgSize" format="dimension"/>
<attr name="imgGap" format="dimension"/>
<attr name="maxSize" format="integer"/>
</declare-styleable>
</resources>
使用
<com.yds.jianshulib.widget.ThreeImageView
android:id="@+id/image_three"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:imgGap="10dp"
app:maxSize="3"
android:paddingLeft="10dp"
android:paddingRight="10dp"
app:singleImgSize="50dp"
android:paddingBottom="10dp"
/>
List<Integer> mList = new ArrayList<>();
mList.add(R.drawable.test01);
mList.add(R.drawable.test02);
mList.add(R.drawable.test03);
mList.add(R.drawable.test04);
mImageView = findViewById(R.id.image_three);
mImageView.setImagesData(mList);
源碼地址:https://github.com/Yedongsheng/Jianshu
源碼地址:https://github.com/ydslib/MultiImageView