1、当图片只有一个的时候,就直接显示这样大图
2、当图片在2-4个的时候,图片就会被分成2列,图片的尺寸大致是控件宽度的一半
3、当图片数量 >4 个是收,图片主要分为三列显示
这样一来就可以根据这样的规律来进行计算了。
我的算法原理是将这些图片通过算法进行组合到一起,形成一个新的Bitmap,这样你需要用的时候直接拿到这个Bitmap使用就可以了。
主要的核心算法如下:
//计算九宫格的图片
public Bitmap formatNineCellBitmap(List<Bitmap> bitmapList) {
if (bitmapList == null || bitmapList.size() == 0) {
return null;
}
int length = bitmapList.size();
//最多显示9张
if (length > 9) {
length = 9;
}
int bitmapSize = builder.bitmapSize;
//图片画板的内间距
int paddingSize = builder.paddingSize;
//每张图片之间的间距
int itemMargin = builder.itemMargin;
//每张需要绘制图片的宽高
int cellSize;
switch (length) {
case 1:
cellSize = bitmapSize - paddingSize * 2;
break;
case 2:
case 3:
case 4:
cellSize = (bitmapSize - paddingSize * 2 - itemMargin) / 2;
break;
default: //默认是三列的图标展示
cellSize = (bitmapSize - paddingSize * 2 - itemMargin * 2) / 3;
}
//画布
Bitmap outBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(outBitmap);
//先画合成之后的背景颜色,默认是白色
canvas.drawColor(builder.backgroundColor);
//这个主要是用来计算绘制图片的起始位置
int left = paddingSize, top = paddingSize;
int moveSize = cellSize + itemMargin;
for (int i = 0; i < length; i++) {
Bitmap dealBitmap = scaleAndCenterInsideBitmap(bitmapList.get(i), cellSize);
if (dealBitmap != null) {
switch (length) {
case 1:
left = paddingSize;
top = paddingSize;
break;
case 2:
left = paddingSize + moveSize * i;
top = (bitmapSize - cellSize) / 2;
break;
case 3:
if (i == 0) {
left = (bitmapSize - cellSize) / 2;
} else {
left = paddingSize + moveSize * (i % 2);
}
top = paddingSize + moveSize * ((i + 1) / 2);
break;
case 4:
left = paddingSize + moveSize * (i % 2);
top = paddingSize + moveSize * (i / 2);
break;
case 5:
if (i <= 1) {
left = (bitmapSize - cellSize * 2 - paddingSize * 2) / 2 + moveSize * (i % 2);
} else {
left = paddingSize + moveSize * (i % 3);
}
top = paddingSize + (bitmapSize - cellSize * 2) / 2 + moveSize * ((i + 1) / 3);
break;
case 6:
left = paddingSize + moveSize * (i % 3);
top = paddingSize + (bitmapSize - cellSize * 2) / 2 + moveSize * (i / 3);
break;
case 7:
if (i == 0) {
left = (bitmapSize - cellSize - paddingSize * 2) / 2;
} else if (i <= 3) {
left = paddingSize + moveSize * ((i - 1) % 3);
} else {
left = paddingSize + moveSize * ((i - 1) % 3);
}
top = paddingSize + moveSize * ((i + 2) / 3);
break;
case 8:
if (i <= 1) {
left = (bitmapSize - cellSize * 2 - paddingSize * 2) / 2 + moveSize * (i % 3);
} else if (i <= 4) {
left = paddingSize + moveSize * ((i - 2) % 3);
} else {
left = paddingSize + moveSize * ((i - 2) % 3);
}
top = paddingSize + moveSize * ((i + 1) / 3);
break;
case 9:
left = paddingSize + moveSize * (i % 3);
top = paddingSize + moveSize * (i / 3);
break;
}
canvas.drawBitmap(dealBitmap, left, top, null);
}
}
return outBitmap;
}
复制代码
//将图片缩放换成指定宽高,并且CenterInside模式
private Bitmap scaleAndCenterInsideBitmap(Bitmap sourceBitmap, int size) {
float sourceWidth = sourceBitmap.getWidth();
float sourceHeight = sourceBitmap.getHeight();
float rate = sourceWidth / sourceHeight;
float destRate = 1;
Bitmap outBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(outBitmap);
Bitmap resizeBitmap;
Matrix matrix = new Matrix();
if (rate < destRate) {
//图片过高,需要裁掉部分高度
float scale = size / sourceWidth;
matrix.setScale(scale, scale);
resizeBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, (int) sourceWidth, (int) sourceHeight, matrix, true);
float cropHeight = (sourceHeight - sourceWidth) * scale;
canvas.drawBitmap(resizeBitmap, 0, -cropHeight / 2, null);
} else {
//图片过宽,需要裁掉部分宽度
float scale = size / sourceHeight;
matrix.setScale(scale, scale);
resizeBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, (int) sourceWidth, (int) sourceHeight, matrix, true);
float cropWidth = (sourceWidth - sourceHeight) * scale;
canvas.drawBitmap(resizeBitmap, -cropWidth / 2, 0, null);
}
return outBitmap;
}复制代码
上述是主要的核心算法,主要根据传入图片的数量进行计算来确定每张图片显示和摆放的位置,这个使用起来简单高效。
下面是算法的封装,将这个类直接复制到你的项目中就可以使用了。
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/***
* @date 创建时间 2018/9/18 14:40
* @author 作者: W.YuLong
* @description 将图片聚合成9宫格
*/
public class NineCellBitmapUtil {
private Builder builder;
private NineCellBitmapUtil(Builder builder) {
this.builder = builder;
}
public int getBitmapSize() {
return builder.bitmapSize;
}
public static Builder with() {
return new Builder();
}
/*这里用到了RXJava来将网络传入的图片URL或者Path转换层Bitmap,如果你还没有导入RXJava的话,可以将这个方法删除
* 或者用你自己的方式将URL转换为Bitmap*/
public <T> void collectBitmap(List<T> dataList, BitmapCallBack callBack) {
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
for (T t : dataList) {
e.onNext(t);
}
e.onComplete();
}
}).map(new Function<T, Bitmap>() {
@Override
public Bitmap apply(T ts) throws Exception {
return ImageLoadTool.transferBitmap(ts);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
.subscribe(new Observer<Bitmap>() {
private List<Bitmap> resultList;
@Override
public void onSubscribe(Disposable d) {
if (resultList == null) {
resultList = new ArrayList<>();
}
}
@Override
public void onNext(Bitmap bitmap) {
resultList.add(bitmap);
}
@Override
public void onComplete() {
callBack.onLoadingFinish(formatNineCellBitmap(resultList));
}
@Override
public void onError(Throwable e) {
}
});
}
//计算九宫格的图片
public Bitmap formatNineCellBitmap(List<Bitmap> bitmapList) {
if (bitmapList == null || bitmapList.size() == 0) {
return null;
}
int length = bitmapList.size();
//最多显示9张
if (length > 9) {
length = 9;
}
int bitmapSize = builder.bitmapSize;
//图片画板的内间距
int paddingSize = builder.paddingSize;
//每张图片之间的间距
int itemMargin = builder.itemMargin;
//每张需要绘制图片的宽高
int cellSize;
switch (length) {
case 1:
cellSize = bitmapSize - paddingSize * 2;
break;
case 2:
case 3:
case 4:
cellSize = (bitmapSize - paddingSize * 2 - itemMargin) / 2;
break;
default: //默认是三列的图标展示
cellSize = (bitmapSize - paddingSize * 2 - itemMargin * 2) / 3;
}
//画布
Bitmap outBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(outBitmap);
//先画合成之后的背景颜色,默认是白色
canvas.drawColor(builder.backgroundColor);
//这个主要是用来计算绘制图片的起始位置
int left = paddingSize, top = paddingSize;
int moveSize = cellSize + itemMargin;
for (int i = 0; i < length; i++) {
Bitmap dealBitmap = scaleAndCenterInsideBitmap(bitmapList.get(i), cellSize);
if (dealBitmap != null) {
switch (length) {
case 1:
left = paddingSize;
top = paddingSize;
break;
case 2:
left = paddingSize + moveSize * i;
top = (bitmapSize - cellSize) / 2;
break;
case 3:
if (i == 0) {
left = (bitmapSize - cellSize) / 2;
} else {
left = paddingSize + moveSize * (i % 2);
}
top = paddingSize + moveSize * ((i + 1) / 2);
break;
case 4:
left = paddingSize + moveSize * (i % 2);
top = paddingSize + moveSize * (i / 2);
break;
case 5:
if (i <= 1) {
left = (bitmapSize - cellSize * 2 - paddingSize * 2) / 2 + moveSize * (i % 2);
} else {
left = paddingSize + moveSize * (i % 3);
}
top = paddingSize + (bitmapSize - cellSize * 2) / 2 + moveSize * ((i + 1) / 3);
break;
case 6:
left = paddingSize + moveSize * (i % 3);
top = paddingSize + (bitmapSize - cellSize * 2) / 2 + moveSize * (i / 3);
break;
case 7:
if (i == 0) {
left = (bitmapSize - cellSize - paddingSize * 2) / 2;
} else if (i <= 3) {
left = paddingSize + moveSize * ((i - 1) % 3);
} else {
left = paddingSize + moveSize * ((i - 1) % 3);
}
top = paddingSize + moveSize * ((i + 2) / 3);
break;
case 8:
if (i <= 1) {
left = (bitmapSize - cellSize * 2 - paddingSize * 2) / 2 + moveSize * (i % 3);
} else if (i <= 4) {
left = paddingSize + moveSize * ((i - 2) % 3);
} else {
left = paddingSize + moveSize * ((i - 2) % 3);
}
top = paddingSize + moveSize * ((i + 1) / 3);
break;
case 9:
left = paddingSize + moveSize * (i % 3);
top = paddingSize + moveSize * (i / 3);
break;
}
canvas.drawBitmap(dealBitmap, left, top, null);
}
}
return outBitmap;
}
//将图片缩放换成指定宽高,并且CenterInside模式
private Bitmap scaleAndCenterInsideBitmap(Bitmap sourceBitmap, int size) {
float sourceWidth = sourceBitmap.getWidth();
float sourceHeight = sourceBitmap.getHeight();
float rate = sourceWidth / sourceHeight;
float destRate = 1;
Bitmap outBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(outBitmap);
Bitmap resizeBitmap;
Matrix matrix = new Matrix();
if (rate < destRate) {
//图片过高,需要裁掉部分高度
float scale = size / sourceWidth;
matrix.setScale(scale, scale);
resizeBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, (int) sourceWidth, (int) sourceHeight, matrix, true);
float cropHeight = (sourceHeight - sourceWidth) * scale;
canvas.drawBitmap(resizeBitmap, 0, -cropHeight / 2, null);
} else {
//图片过宽,需要裁掉部分宽度
float scale = size / sourceHeight;
matrix.setScale(scale, scale);
resizeBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, (int) sourceWidth, (int) sourceHeight, matrix, true);
float cropWidth = (sourceWidth - sourceHeight) * scale;
canvas.drawBitmap(resizeBitmap, -cropWidth / 2, 0, null);
}
return outBitmap;
}
public static class Builder {
//画布宽度和高度
private int bitmapSize = 300;
//聚合后的图片内间距
private int paddingSize = 10;
//每张图片的间距
private int itemMargin = 15;
//聚合后图片的背景色
private int backgroundColor = Color.WHITE;
public Builder() {
}
public NineCellBitmapUtil build() {
return new NineCellBitmapUtil(this);
}
public int getBackgroundColor() {
return backgroundColor;
}
public Builder setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
public int getBitmapSize() {
return bitmapSize;
}
public Builder setBitmapSize(int bitmapSize) {
this.bitmapSize = bitmapSize;
return this;
}
public int getPaddingSize() {
return paddingSize;
}
public Builder setPaddingSize(int paddingSize) {
this.paddingSize = paddingSize;
return this;
}
public int getItemMargin() {
return itemMargin;
}
public Builder setItemMargin(int itemMargin) {
this.itemMargin = itemMargin;
return this;
}
}
/***
*@date 创建时间 2018/9/18 11:50
*@author 作者: W.YuLong
*@description 图片聚合完成之后的回调
*/
public interface BitmapCallBack {
/*处理完成*/
void onLoadingFinish(Bitmap bitmap);
}
}
复制代码
具体使用如下:
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.hwariot.android.R;
import com.hwariot.android.tools.util.NineCellBitmapUtil;
import com.hwariot.lib.base.BaseActivity;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/***
* @date 创建时间 2018/9/19 11:30
* @author 作者: W.YuLong
* @description
*/
public class TestActivity extends BaseActivity implements View.OnClickListener {
@BindView(R.id.test_ImageView) ImageView imageView;
@BindView(R.id.test_add_Button) Button addButton;
@BindView(R.id.test_remove_Button) Button removeButton;
NineCellBitmapUtil nineCellBitmapUtil;
String[] urlArray = {
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1538451017&di=dd252d5e4594f786d34891fb6be826ff&imgtype=jpg&er=1&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201311%2F28%2F20131128101128_JZUaM.jpeg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537856300317&di=e4aebfba49e34aa5bd8de8346b268229&imgtype=0&src=http%3A%2F%2Fs9.knowsky.com%2Fbizhi%2Fl%2F35001-45000%2F20095294542896291195.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537856300315&di=8def4a51ac362ffa7602ca768d76c982&imgtype=0&src=http%3A%2F%2Fg.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2Ff9198618367adab44ce126ab8bd4b31c8701e420.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537345745067&di=d51264f2b354863c865a1da4b6672d90&imgtype=0&src=http%3A%2F%2Fpic40.nipic.com%2F20140426%2F6608733_175243397000_2.jpg",
"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3394638573,2701566035&fm=26&gp=0.jpg",
"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2758635669,3034136689&fm=26&gp=0.jpg",
"http://t.cn/EvHONPF",
"http://t.cn/EvHOTa9",
"http://t.cn/EvHO38y",
};
private List<String> imgList = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_layout);
ButterKnife.bind(this);
// 实例化这个这个工具类,默认聚合的图片尺寸是1000像素,每张图的间距是20像素
nineCellBitmapUtil = NineCellBitmapUtil.with().setBitmapSize(1000)
.setItemMargin(20).setPaddingSize(20).build();
addButton.setOnClickListener(this);
removeButton.setOnClickListener(this);
}
private int i = 0;
@Override
public void onClick(View v) {
if (v == addButton) {
if (i < urlArray.length){
imgList.add(urlArray[i]);
i++;
//调用这个方法进行聚合
nineCellBitmapUtil.collectBitmap(imgList, new NineCellBitmapUtil.BitmapCallBack() {
@Override
public void onLoadingFinish(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
});
}
} else if (v == removeButton) {
if (i > 0){
i--;
imgList.remove(i);
nineCellBitmapUtil.collectBitmap(imgList, new NineCellBitmapUtil.BitmapCallBack() {
@Override
public void onLoadingFinish(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
});
}
}
}
}复制代码
使用就是先实例化这个工具类
// 实例化这个这个工具类,默认聚合的图片尺寸是1000像素,每张图的间距是20像素
nineCellBitmapUtil = NineCellBitmapUtil.with().setBitmapSize(1000)
.setItemMargin(20).setPaddingSize(20).build();复制代码
然后调用这个聚合后的算法
//调用这个方法进行聚合
nineCellBitmapUtil.collectBitmap(imgList, new NineCellBitmapUtil.BitmapCallBack() {
@Override
public void onLoadingFinish(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
}); 复制代码
这样就完成了,是不是使用起来非常简单方便高效!
下图就是展示的效果