android多圖顯示,多出圖片以文字提示

可以控制最多顯示多少個(gè)帖族,多余最大數(shù)量則在最后一行以文字提示,通過控制maxSize大小來控制最多顯示圖片數(shù)量挡爵。效果如下圖所示

  • app:maxSize="2"


    image.png
  • app:maxSize="5"


    image.png
  • app:maxSize="9"


    image.png

只有一行顯示圖片竖般,多出來的圖在最后一張圖上顯示圖片總數(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之間的距離

參考圖片


image.png
  • getTextBounds
    獲取文本內(nèi)容矩形

2 問題

  1. 文本沒有居中伶棒,使用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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寇蚊,一起剝皮案震驚了整個(gè)濱河市笔时,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仗岸,老刑警劉巖允耿,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扒怖,居然都是意外死亡较锡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門盗痒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來念链,“玉大人,你說我怎么就攤上這事积糯〉嗄梗” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵看成,是天一觀的道長(zhǎng)君编。 經(jīng)常有香客問我,道長(zhǎng)川慌,這世上最難降的妖魔是什么吃嘿? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮梦重,結(jié)果婚禮上兑燥,老公的妹妹穿的比我還像新娘。我一直安慰自己琴拧,他們只是感情好降瞳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般挣饥。 火紅的嫁衣襯著肌膚如雪除师。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天扔枫,我揣著相機(jī)與錄音汛聚,去河邊找鬼。 笑死短荐,一個(gè)胖子當(dāng)著我的面吹牛倚舀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忍宋,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瞄桨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了讶踪?” 一聲冷哼從身側(cè)響起芯侥,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乳讥,沒想到半個(gè)月后柱查,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡云石,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年唉工,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汹忠。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淋硝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宽菜,到底是詐尸還是另有隱情谣膳,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布铅乡,位于F島的核電站继谚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏阵幸。R本人自食惡果不足惜花履,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挚赊。 院中可真熱鬧诡壁,春花似錦、人聲如沸荠割。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至纽帖,卻和暖如春宠漩,著一層夾襖步出監(jiān)牢的瞬間举反,已是汗流浹背懊直。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留火鼻,地道東北人室囊。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像魁索,于是被迫代替她去往敵國(guó)和親融撞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容