1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 类似微信群聊九宫格头像的算法实现

类似微信群聊九宫格头像的算法实现

时间:2018-06-05 22:50:52

相关推荐

类似微信群聊九宫格头像的算法实现

在工作中遇到了一个开发的需求是将多选的图片聚合起来,类似于微信群聊那种九宫格的头像的那种。当然遇到这个需求首先肯定会从网上查找一些资料,发现大部分的实现类似于通过定义九宫格的ImageView控件来实现,这样一来,实际上图片没有被压缩,而且还生成了一大堆的控件,对内存性能效果是很大的。 既然网上没有合适好的算法方案,那不如自己来实现一个吧,通过分析头像的的形成的原理主要有如下的几个规律:

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 创建时间 /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() {@Overridepublic void subscribe(ObservableEmitter e) throws Exception {for (T t : dataList) {e.onNext(t);}e.onComplete();}}).map(new Function<T, Bitmap>() {@Overridepublic Bitmap apply(T ts) throws Exception {return ImageLoadTool.transferBitmap(ts);}}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.newThread()).subscribe(new Observer<Bitmap>() {private List<Bitmap> resultList;@Overridepublic void onSubscribe(Disposable d) {if (resultList == null) {resultList = new ArrayList<>();}}@Overridepublic void onNext(Bitmap bitmap) {resultList.add(bitmap);}@Overridepublic void onComplete() {callBack.onLoadingFinish(formatNineCellBitmap(resultList));}@Overridepublic 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 创建时间 /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 创建时间 /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 = {"/timg?image&quality=80&size=b9999_10000&sec=1538451017&di=dd252d5e4594f786d34891fb6be826ff&imgtype=jpg&er=1&src=http%3A%2F%%2Fuploads%2Fitem%2F11%2F28%2F1128101128_JZUaM.jpeg","/timg?image&quality=80&size=b9999_10000&sec=1537856300317&di=e4aebfba49e34aa5bd8de8346b268229&imgtype=0&src=http%3A%2F%%2Fbizhi%2Fl%2F35001-45000%2F5294542896291195.jpg","/timg?image&quality=80&size=b9999_10000&sec=1537856300315&di=8def4a51ac362ffa7602ca768d76c982&imgtype=0&src=http%3A%2F%2Fg.%2Fzhidao%2Fpic%2Fitem%2Ff9198618367adab44ce126ab8bd4b31c8701e420.jpg","/timg?image&quality=80&size=b9999_10000&sec=1537345745067&di=d51264f2b354863c865a1da4b6672d90&imgtype=0&src=http%3A%2F%%2F0426%2F6608733_175243397000_2.jpg","/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3394638573,2701566035&fm=26&gp=0.jpg","/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2758635669,3034136689&fm=26&gp=0.jpg","/EvHONPF","/EvHOTa9","/EvHO38y",};private List<String> imgList = new ArrayList<>();@Overrideprotected 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;@Overridepublic void onClick(View v) {if (v == addButton) {if (i < urlArray.length){imgList.add(urlArray[i]);i++;//调用这个方法进行聚合nineCellBitmapUtil.collectBitmap(imgList, new NineCellBitmapUtil.BitmapCallBack() {@Overridepublic void onLoadingFinish(Bitmap bitmap) {imageView.setImageBitmap(bitmap);}});}} else if (v == removeButton) {if (i > 0){i--;imgList.remove(i);nineCellBitmapUtil.collectBitmap(imgList, new NineCellBitmapUtil.BitmapCallBack() {@Overridepublic 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() {@Overridepublic void onLoadingFinish(Bitmap bitmap) {imageView.setImageBitmap(bitmap);}}); 复制代码

这样就完成了,是不是使用起来非常简单方便高效!

下图就是展示的效果

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。