仿微信群组头像组合边框实现
来源:互联网 发布:什么数据库8000多 编辑:程序博客网 时间:2024/06/08 15:18
由于项目需要展示头像跟微信群组那样的组合,网上搜了一堆都不太符合要求,额,可能没有找到吧
下面就分享一个自己整合的头像合成工具类:
先说一下实现思路和步骤:
(1)首先要创建一张空白的大图片(2)根据需要的图片宽度(此处都是正方形),计算所有图片在空白图片中的坐标,由于要设置小图片直接的间隙,此处就要加上间隙的宽度(3)以此需要合成的图片与空白图片进行组合(第二次组合要在第一次组合的基础上进行)(4)组合成之后对图片设置背景颜色(及边框和间隙的颜色)
此图片组合可支持1-9张图片的组合展示
以下就是具体的实现类和参考实例代码中有详细注释:
/** * 实现9张图片组合 * <p> * Created by:wangjian on 2017/11/17 10:28 */public class NineImageCombine { /** * 进行图片组合 * * @param bitmaps 图片列表 * @param parentWidth 图片显示的宽度 * @param padding 图片间距大小 * @param borderColor 边框和间隙颜色 * @return */ public static Bitmap combineImages(List<Bitmap> bitmaps, int parentWidth, int padding, int borderColor) { int size = bitmaps.size(); // 根据图片数计算列数 int maxColumn = getMaxColumn(size); // 计算图片行数 // int maxRow = getMaxRow(size); // 图片实际占用宽度(去除padding) int valiableImageWidth = parentWidth - (maxColumn - 1) * padding; // 根据列数计算图片宽度和高度 int imgWidth = valiableImageWidth / maxColumn; // int imgHeight = valiableImageWidth / maxColumn; // padding占据图片宽度的百分比 float paddingPer = (float) padding / imgWidth; // 画布,空白大图 Bitmap newBitmap = Bitmap.createBitmap(parentWidth, parentWidth, Bitmap.Config.ARGB_8888); // 获得各图片坐标 List<PointF> points = getPointFlist(size, maxColumn, imgWidth, paddingPer); for (int i = 0; i < points.size(); i++) { // 生成指定大小的缩略图 Bitmap thumBitmap = getThumbnailBitmap(bitmaps.get(i), imgWidth); // 组合成新的图片 newBitmap = mixtureBitmap(newBitmap, thumBitmap, points.get(i)); } if (borderColor != 0) { newBitmap = setBgAndBorder(newBitmap, borderColor, padding); } return newBitmap; } /** * 计算每一张图片的坐标点 * * @param size 图片的数量 * @param maxColumn 行数 * @param imgWidth 每一张图片的宽度 * @param paddingPer 图片中间的缝隙与图片宽度的百分比 * @return */ private static List<PointF> getPointFlist(int size, int maxColumn, float imgWidth, float paddingPer) { List<PointF> pointFList = new ArrayList<>(); // 1张图片 if (maxColumn == 1) { int xleft = 0; int xtop = 0; addPointF(pointFList, imgWidth, xleft, xtop); } // 2,3,4张图片 else if (maxColumn == 2) { if (size == 2) { // 对应坐标 w == imgWidth // 0,w/2 w w/2 for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: xleft = 0; xtop = 1 / 2f; break; case 1: xleft = 1 + paddingPer; xtop = 1 / 2f; break; } addPointF(pointFList, imgWidth, xleft, xtop); } } else if (size == 3) { // 对应坐标 w == imgWidth // w/2,0 // 0,w w w for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: xleft = 1 / 2f; xtop = 0; break; case 1: xleft = 0; xtop = 1 + paddingPer; break; case 2: xleft = 1 + paddingPer; xtop = 1 + paddingPer; break; } addPointF(pointFList, imgWidth, xleft, xtop); } } else { // 对应坐标 w == imgWidth // 0,0 w 0 // 0,w w w for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: case 2: xleft = 0; xtop = i * (1 / 2f); if (i == 2) { xtop += paddingPer; } break; case 1: case 3: xleft = 1 + paddingPer; xtop = (i - 1) * (1 / 2f); if (i == 3) { xtop += paddingPer; } break; } addPointF(pointFList, imgWidth, xleft, xtop); } } } // 5,6,7,8,9张图片 else if (maxColumn == 3) { switch (size) { case 5: // 对应坐标 w == imgWidth // w/2,w/2 3w/2,w/2 // 0,3w/2 w,3w/2 2w,3w/2 for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: xleft = 1 / 2f; xtop = 1 / 2f; break; case 1: xleft = 3 / 2f + paddingPer; xtop = 1 / 2f; break; case 2: case 3: case 4: xleft = i - 2; xtop = 3 / 2f + paddingPer; if (i != 2) { xleft += (i - 2) * paddingPer; } break; } addPointF(pointFList, imgWidth, xleft, xtop); } break; case 6: // 对应坐标 w == imgWidth // 0,w/2 w,w/2 2w,w/2 // 0,3w/2 w,3w/2 2w,3w/2 for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: case 1: case 2: xleft = i; xtop = 1 / 2f; if (i != 0) { xleft += (i) * paddingPer; } break; case 3: case 4: case 5: xleft = i - 3; xtop = 3 / 2f + paddingPer; if (i != 3) { xleft += (i - 3) * paddingPer; } break; } addPointF(pointFList, imgWidth, xleft, xtop); } break; case 7: // 对应坐标 w == imgWidth // w,0 // 0,w w,w 2w,w // 0,2w w,2w 2w,2w for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: xleft = 1 + paddingPer; xtop = 0; break; case 1: case 2: case 3: xleft = i - 1; xtop = 1 + paddingPer; if (i != 1) { xleft += (i - 1) * paddingPer;// 除了第一列,依次递增加padding } break; case 4: case 5: case 6: xleft = i - 4; xtop = 2 + (2) * paddingPer;// 最下面一行要加2倍padding if (i != 4) { xleft += (i - 4) * paddingPer;// 除了第一列,依次递增加padding } break; } addPointF(pointFList, imgWidth, xleft, xtop); } break; case 8: // 对应坐标 w == imgWidth // w/2,0 3w/2,0 // 0,w w,w 2w,w // 0,2w w,2w 2w,2w for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: xleft = 1 / 2f; xtop = 0; break; case 1: xleft = 3 / 2f + paddingPer; xtop = 0; break; case 2: case 3: case 4: xleft = i - 2; xtop = 1 + paddingPer; if (i != 2) { xleft += (i - 2) * paddingPer;// 除了第一列,依次递增加padding } break; case 5: case 6: case 7: xleft = i - 5; xtop = 2 + (2) * paddingPer;// 最下面一行要加2倍padding if (i != 5) { xleft += (i - 5) * paddingPer;// 除了第一列,依次递增加padding } break; } addPointF(pointFList, imgWidth, xleft, xtop); } break; case 9: // 对应坐标 w == imgWidth // 0,0 w,0 2w,0 // 0,w w,w 2w,w // 0,2w w,2w 2w,2w for (int i = 0; i < size; i++) { //计算左上角坐标 float xleft = 0; float xtop = 0; switch (i) { case 0: case 1: case 2: xleft = i; xtop = 0; if (i != 0) { xleft += (i) * paddingPer; } break; case 3: case 4: case 5: xleft = i - 3; xtop = 1 + paddingPer; if (i != 3) { xleft += (i - 3) * paddingPer; } break; case 6: case 7: case 8: xleft = i - 6; xtop = 2 + (2) * paddingPer; if (i != 6) { xleft += (i - 6) * paddingPer; } break; } addPointF(pointFList, imgWidth, xleft, xtop); } break; } } return pointFList; } /** * 计算并保存坐标点 * * @param pointFList * @param imgWidth * @param xleft * @param xtop */ private static void addPointF(List<PointF> pointFList, float imgWidth, float xleft, float xtop) { float left = imgWidth * xleft; float top = imgWidth * xtop; PointF pointF = new PointF(left, top); pointFList.add(pointF); } /** * 根据图片数计算行数 * * @param size * @return */ private static int getMaxRow(int size) { int maxRow = 1; switch (size) { case 1: case 2: maxRow = 1; break; case 3: case 4: case 5: case 6: maxRow = 2; break; case 7: case 8: case 9: maxRow = 3; break; } return maxRow; } /** * 根据图片数计算列数 * * @param size 图片数量 * @return */ private static int getMaxColumn(int size) { int maxColumn = 1; switch (size) { case 1: maxColumn = 1; break; case 2: case 3: case 4: maxColumn = 2; break; case 5: case 6: case 7: case 8: case 9: maxColumn = 3; break; } return maxColumn; } /** * 进行图片压缩 * * @param bitmap * @param widthDp * @return */ public static Bitmap getThumbnailBitmap(Bitmap bitmap, int widthDp) { Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, widthDp, widthDp); return thumbnail; } /** * drawable 转换成bitmap * * @param drawable * @return */ public static Bitmap drawableToBitmap(Drawable drawable) { Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.setBitmap(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; } /** * 保存图片到文件中 * * @param mContext * @param bitmap * @param desName * @return * @throws IOException */ public static File saveBitmap2File(Context mContext, Bitmap bitmap, String desName) throws IOException { FileOutputStream fOut = null; File file = mContext.getExternalFilesDir("Pictures"); if (!file.exists()) { file.mkdirs(); } File saveFile = new File(file, desName + ".png"); file.createNewFile(); fOut = new FileOutputStream(saveFile); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); try { fOut.flush(); } catch (IOException e) { e.printStackTrace(); } try { fOut.close(); } catch (IOException e) { e.printStackTrace(); } return saveFile; } /** * 在padding>0的情况,设置图片间隙和边框,否则是有边框 * * @param orginBitmap * @param color 背景颜色(即边框和间隙颜色) * @param padding 图片间隙 * @return */ private static Bitmap setBgAndBorder(Bitmap orginBitmap, int color, int padding) { Paint paint = new Paint(); paint.setColor(color); int addSize = 2 * padding; int afwidth = orginBitmap.getWidth() + addSize; int afheight = orginBitmap.getHeight() + addSize; Bitmap bitmap = Bitmap.createBitmap(afwidth, afheight, orginBitmap.getConfig()); Canvas canvas = new Canvas(bitmap); // canvas.drawColor(color); canvas.drawRect(0, 0, afwidth, afheight, paint); canvas.drawBitmap(orginBitmap, padding, padding, paint); return bitmap; } /** * 给bitmap设置边框 * * @param bitmap 图片源 * @param color 边框颜色 * @param size 宽度 */ public static Bitmap setBitmapBorder(Bitmap bitmap, int color, int size) { Canvas canvas = new Canvas(bitmap); Rect rect = canvas.getClipBounds(); Paint paint = new Paint(); //设置边框颜色 paint.setColor(color); paint.setStyle(Paint.Style.STROKE); //设置边框宽度 paint.setStrokeWidth(size); canvas.drawRect(rect, paint); return bitmap; } /** * 进行图片组合 * * @param first 第一张图片 * @param second 第二张图片 * @param fromPoint 第二张图片的坐标 * @return 组合后的图片 */ public static Bitmap mixtureBitmap(Bitmap first, Bitmap second, PointF fromPoint) { Bitmap newBitmap = Bitmap.createBitmap(first.getWidth(), first.getHeight(), Bitmap.Config.ARGB_8888); Canvas cv = new Canvas(newBitmap); // 第一张图片从(0,0)位置开始绘制 cv.drawBitmap(first, 0, 0, null); // 第二张图片从指定的坐标绘制 cv.drawBitmap(second, fromPoint.x, fromPoint.y, null); cv.save(Canvas.ALL_SAVE_FLAG); cv.restore(); return newBitmap; } public static int dp2px(Context context, float dp) { float density = context.getResources().getDisplayMetrics().density; return (int) (dp * density + .5f); }}
参考实例:
// 图片处理合成是耗时操作建议放到子线程中处理private void testCombine(){ // 获得资源图片 Drawable drawable = getResources().getDrawable(R.mipmap.mm); Bitmap bitmap = NineImageCombine.drawableToBitmap(drawable); // 封装成bitmap列表,图片数量可自行定义 List<Bitmap> list = new ArrayList<>(); for (int i = 0; i < 7; i++) { list.add(bitmap); } // 设置需要显示的图片宽度 int parentWidth = dp2px(MainActivity.this, 156); // 设置边框和间隙的宽度 int padding = dp2px(MainActivity.this, 3); // 进行图片组合 final Bitmap newBitmap = NineImageCombine.combineImages(list, parentWidth, padding, Color.parseColor("#d8d8d8")); // 保存到文件中 try { File file = NineImageCombine.saveBitmap2File(MainActivity.this, newBitmap, System.currentTimeMillis() + ""); System.out.println("path:" + file.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } }
以下是我未来媳妇图片合成效果(:(:(:
阅读全文
1 0
- 仿微信群组头像组合边框实现
- Android:实现IM多人员组合的群组头像
- android 仿微信群组头像效果
- Android 仿微信群组头像合成
- 自定义View-仿微信群组头像
- Swift - QQ讨论组头像的实现 (多人聊天的组合头像)
- 群组头像拼接
- 群组头像合成控件
- 高仿QQ讨论组头像拼图
- Android 仿QQ讨论组头像
- android 群组头像的显示(仿QQ群组)
- android 群组头像的显示(仿QQ群组)
- LongListSelector 锁定组头(sticky header )之我的实现
- 关于QQ群头像以及微信讨论组头像的工具类
- swing组合边框(CompoundBorder)
- 实现像sum对整数一样,字符串按某列group by来组合字符串列
- 隐藏文本框的边框,像Lable
- tableview实现静态表格(纯代码)组头组尾实现
- fatal error C1083: 无法打开包括文件: “stddef.h”: No such file or directory
- jvm垃圾回收
- 换肤方案[整理]
- 有关二叉树的递归算法
- 排序算法-堆排序
- 仿微信群组头像组合边框实现
- 创建Spring Boot第一个引用项目出现的Bug
- Banner 无线轮播图
- 二叉树的深度
- 网络请求框架 Retrofit 2 使用入门
- 分布式id生成
- 关于某个PyQt5系列教程“'QMainWindow' object has no attribute”的错误修正
- idea 远程dubug
- 我的秋招总结(百度,搜狗,京东,美团,科大讯飞,新华三,国家互联网应急中心,微盟,ofo面经)