2020-08-11 14:48:10 +08:00
|
|
|
|
package com.lzy.ninegrid;
|
|
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
import android.content.res.TypedArray;
|
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
|
import android.support.annotation.NonNull;
|
|
|
|
|
|
import android.util.AttributeSet;
|
|
|
|
|
|
import android.util.DisplayMetrics;
|
|
|
|
|
|
import android.util.TypedValue;
|
|
|
|
|
|
import android.view.View;
|
|
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
|
import android.widget.ImageView;
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
|
2020-08-11 14:48:10 +08:00
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
public class NineGridView extends ViewGroup {
|
|
|
|
|
|
|
|
|
|
|
|
public static final int MODE_FILL = 0; //填充模式,类似于微信
|
|
|
|
|
|
public static final int MODE_GRID = 1; //网格模式,类似于QQ,4张图会 2X2布局
|
|
|
|
|
|
|
|
|
|
|
|
private static ImageLoader mImageLoader; //全局的图片加载器(必须设置,否者不显示图片)
|
|
|
|
|
|
|
|
|
|
|
|
private int singleImageSize = 250; // 单张图片时的最大大小,单位dp
|
|
|
|
|
|
private float singleImageRatio = 1.0f; // 单张图片的宽高比(宽/高)
|
|
|
|
|
|
private int maxImageSize = 9; // 最大显示的图片数
|
|
|
|
|
|
private int gridSpacing = 3; // 宫格间距,单位dp
|
|
|
|
|
|
private int mode = MODE_FILL; // 默认使用fill模式
|
|
|
|
|
|
|
|
|
|
|
|
private int columnCount; // 列数
|
|
|
|
|
|
private int rowCount; // 行数
|
|
|
|
|
|
private int gridWidth; // 宫格宽度
|
|
|
|
|
|
private int gridHeight; // 宫格高度
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
private List<NineGridViewWrapper> imageViews;
|
2020-08-11 14:48:10 +08:00
|
|
|
|
private List<ImageInfo> mImageInfo;
|
|
|
|
|
|
private NineGridViewAdapter mAdapter;
|
|
|
|
|
|
|
|
|
|
|
|
public NineGridView(Context context) {
|
|
|
|
|
|
this(context, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public NineGridView(Context context, AttributeSet attrs) {
|
|
|
|
|
|
this(context, attrs, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public NineGridView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
|
super(context, attrs, defStyleAttr);
|
|
|
|
|
|
|
|
|
|
|
|
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
|
|
|
|
|
gridSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gridSpacing, dm);
|
|
|
|
|
|
singleImageSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, singleImageSize, dm);
|
|
|
|
|
|
|
|
|
|
|
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NineGridView);
|
|
|
|
|
|
gridSpacing = (int) a.getDimension(R.styleable.NineGridView_ngv_gridSpacing, gridSpacing);
|
|
|
|
|
|
singleImageSize = a.getDimensionPixelSize(R.styleable.NineGridView_ngv_singleImageSize, singleImageSize);
|
|
|
|
|
|
singleImageRatio = a.getFloat(R.styleable.NineGridView_ngv_singleImageRatio, singleImageRatio);
|
|
|
|
|
|
maxImageSize = a.getInt(R.styleable.NineGridView_ngv_maxSize, maxImageSize);
|
|
|
|
|
|
mode = a.getInt(R.styleable.NineGridView_ngv_mode, mode);
|
|
|
|
|
|
a.recycle();
|
|
|
|
|
|
|
|
|
|
|
|
imageViews = new ArrayList<>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
|
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
|
|
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
|
|
|
|
|
int height = 0;
|
|
|
|
|
|
int totalWidth = width - getPaddingLeft() - getPaddingRight();
|
|
|
|
|
|
if (mImageInfo != null && mImageInfo.size() > 0) {
|
|
|
|
|
|
if (mImageInfo.size() == 1) {
|
|
|
|
|
|
gridWidth = singleImageSize > totalWidth ? totalWidth : singleImageSize;
|
|
|
|
|
|
gridHeight = (int) (gridWidth / singleImageRatio);
|
|
|
|
|
|
//矫正图片显示区域大小,不允许超过最大显示范围
|
|
|
|
|
|
if (gridHeight > singleImageSize) {
|
|
|
|
|
|
float ratio = singleImageSize * 1.0f / gridHeight;
|
|
|
|
|
|
gridWidth = (int) (gridWidth * ratio);
|
|
|
|
|
|
gridHeight = singleImageSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// gridWidth = gridHeight = (totalWidth - gridSpacing * (columnCount - 1)) / columnCount;
|
|
|
|
|
|
//这里无论是几张图片,宽高都按总宽度的 1/3
|
|
|
|
|
|
gridWidth = gridHeight = (totalWidth - gridSpacing * 2) / 3;
|
|
|
|
|
|
}
|
|
|
|
|
|
width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
|
|
|
|
|
|
height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
|
|
|
|
|
|
}
|
|
|
|
|
|
setMeasuredDimension(width, height);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
|
|
|
|
if (mImageInfo == null) return;
|
|
|
|
|
|
int childrenCount = mImageInfo.size();
|
|
|
|
|
|
for (int i = 0; i < childrenCount; i++) {
|
2020-09-02 15:33:38 +08:00
|
|
|
|
NineGridViewWrapper childrenView = (NineGridViewWrapper) getChildAt(i);
|
|
|
|
|
|
|
2020-08-11 14:48:10 +08:00
|
|
|
|
int rowNum = i / columnCount;
|
|
|
|
|
|
int columnNum = i % columnCount;
|
|
|
|
|
|
int left = (gridWidth + gridSpacing) * columnNum + getPaddingLeft();
|
|
|
|
|
|
int top = (gridHeight + gridSpacing) * rowNum + getPaddingTop();
|
|
|
|
|
|
int right = left + gridWidth;
|
|
|
|
|
|
int bottom = top + gridHeight;
|
|
|
|
|
|
childrenView.layout(left, top, right, bottom);
|
2020-09-02 15:33:38 +08:00
|
|
|
|
|
2020-08-11 14:48:10 +08:00
|
|
|
|
if (mImageLoader != null) {
|
2020-09-02 15:33:38 +08:00
|
|
|
|
childrenView.setType(mImageInfo.get(i).type);
|
2020-08-11 14:48:10 +08:00
|
|
|
|
mImageLoader.onDisplayImage(getContext(), childrenView, mImageInfo.get(i).thumbnailUrl);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置适配器
|
|
|
|
|
|
*/
|
2020-08-11 14:48:10 +08:00
|
|
|
|
public void setAdapter(@NonNull NineGridViewAdapter adapter) {
|
|
|
|
|
|
mAdapter = adapter;
|
|
|
|
|
|
List<ImageInfo> imageInfo = adapter.getImageInfo();
|
|
|
|
|
|
|
|
|
|
|
|
if (imageInfo == null || imageInfo.isEmpty()) {
|
|
|
|
|
|
setVisibility(GONE);
|
|
|
|
|
|
return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setVisibility(VISIBLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int imageCount = imageInfo.size();
|
|
|
|
|
|
if (maxImageSize > 0 && imageCount > maxImageSize) {
|
|
|
|
|
|
imageInfo = imageInfo.subList(0, maxImageSize);
|
|
|
|
|
|
imageCount = imageInfo.size(); //再次获取图片数量
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//默认是3列显示,行数根据图片的数量决定
|
|
|
|
|
|
rowCount = imageCount / 3 + (imageCount % 3 == 0 ? 0 : 1);
|
|
|
|
|
|
columnCount = 3;
|
|
|
|
|
|
//grid模式下,显示4张使用2X2模式
|
|
|
|
|
|
if (mode == MODE_GRID) {
|
|
|
|
|
|
if (imageCount == 4) {
|
|
|
|
|
|
rowCount = 2;
|
|
|
|
|
|
columnCount = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//保证View的复用,避免重复创建
|
|
|
|
|
|
if (mImageInfo == null) {
|
|
|
|
|
|
for (int i = 0; i < imageCount; i++) {
|
|
|
|
|
|
ImageView iv = getImageView(i);
|
|
|
|
|
|
if (iv == null) return;
|
|
|
|
|
|
addView(iv, generateDefaultLayoutParams());
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
int oldViewCount = mImageInfo.size();
|
|
|
|
|
|
int newViewCount = imageCount;
|
|
|
|
|
|
if (oldViewCount > newViewCount) {
|
|
|
|
|
|
removeViews(newViewCount, oldViewCount - newViewCount);
|
|
|
|
|
|
} else if (oldViewCount < newViewCount) {
|
|
|
|
|
|
for (int i = oldViewCount; i < newViewCount; i++) {
|
|
|
|
|
|
ImageView iv = getImageView(i);
|
|
|
|
|
|
if (iv == null) return;
|
|
|
|
|
|
addView(iv, generateDefaultLayoutParams());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//修改最后一个条目,决定是否显示更多
|
2020-09-02 15:33:38 +08:00
|
|
|
|
// if (adapter.getImageInfo().size() > maxImageSize) {
|
|
|
|
|
|
// View child = getChildAt(maxImageSize - 1);
|
|
|
|
|
|
// if (child instanceof NineGridViewWrapper) {
|
|
|
|
|
|
// NineGridViewWrapper imageView = (NineGridViewWrapper) child;
|
|
|
|
|
|
// imageView.setMoreNum(adapter.getImageInfo().size() - maxImageSize);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
2020-08-11 14:48:10 +08:00
|
|
|
|
mImageInfo = imageInfo;
|
|
|
|
|
|
requestLayout();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获得 ImageView 保证了 ImageView 的重用
|
|
|
|
|
|
*/
|
|
|
|
|
|
private NineGridViewWrapper getImageView(final int position) {
|
|
|
|
|
|
NineGridViewWrapper imageView;
|
2020-08-11 14:48:10 +08:00
|
|
|
|
if (position < imageViews.size()) {
|
|
|
|
|
|
imageView = imageViews.get(position);
|
|
|
|
|
|
} else {
|
2020-09-02 15:33:38 +08:00
|
|
|
|
imageView = mAdapter.generateImageView(getContext(), mAdapter.getImageInfo().get(position).getType());
|
2020-08-11 14:48:10 +08:00
|
|
|
|
imageView.setOnClickListener(new OnClickListener() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
|
mAdapter.onImageItemClick(getContext(), NineGridView.this, position, mAdapter.getImageInfo());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
imageViews.add(imageView);
|
|
|
|
|
|
}
|
|
|
|
|
|
return imageView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置宫格间距
|
|
|
|
|
|
*/
|
2020-08-11 14:48:10 +08:00
|
|
|
|
public void setGridSpacing(int spacing) {
|
|
|
|
|
|
gridSpacing = spacing;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置只有一张图片时的宽
|
|
|
|
|
|
*/
|
2020-08-11 14:48:10 +08:00
|
|
|
|
public void setSingleImageSize(int maxImageSize) {
|
|
|
|
|
|
singleImageSize = maxImageSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置只有一张图片时的宽高比
|
|
|
|
|
|
*/
|
2020-08-11 14:48:10 +08:00
|
|
|
|
public void setSingleImageRatio(float ratio) {
|
|
|
|
|
|
singleImageRatio = ratio;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-02 15:33:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置最大图片数
|
|
|
|
|
|
*/
|
2020-08-11 14:48:10 +08:00
|
|
|
|
public void setMaxSize(int maxSize) {
|
|
|
|
|
|
maxImageSize = maxSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int getMaxSize() {
|
|
|
|
|
|
return maxImageSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void setImageLoader(ImageLoader imageLoader) {
|
|
|
|
|
|
mImageLoader = imageLoader;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static ImageLoader getImageLoader() {
|
|
|
|
|
|
return mImageLoader;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public interface ImageLoader {
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 需要子类实现该方法,以确定如何加载和显示图片
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param context 上下文
|
|
|
|
|
|
* @param imageView 需要展示图片的ImageView
|
|
|
|
|
|
* @param url 图片地址
|
|
|
|
|
|
*/
|
|
|
|
|
|
void onDisplayImage(Context context, ImageView imageView, String url);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param url 图片的地址
|
|
|
|
|
|
* @return 当前框架的本地缓存图片
|
|
|
|
|
|
*/
|
|
|
|
|
|
Bitmap getCacheImage(String url);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|