Android学习之仿QQ讨论组和微信群聊头像

本文介绍了如何在Android中实现仿QQ讨论组和微信群聊的头像显示效果,包括圆角矩形和头像间距的自定义设置,详细讲解了具体代码实现过程。

    这是自己总结的,希望对你们有帮助

  1:先看效果


  

 

                                                       

2:具体代码实现


2.1 直接粘代码

 

public class GroupView extends ImageView {
    /** 图片之间的距离 */
    private  int padding = 2;
    /** 圆角值 */
    private  int cornor = 0;

    private  int width,height;;
    /** 头像模式 圆的 */
    public static final int FACETYPE_CIRCLE = 1;
    /** 头像模式 方的 最多9个 */
    public static final int FACETYPE_SQUARE = 2;

    private Context mContext;

    private int mViewType;//默认圆形
    private Bitmap[] mBitmaps ;
    private int background;
    public GroupView(Context context,Bitmap[] bitmaps) {
        super(context);
        this.mBitmaps = bitmaps;
    }

    public GroupView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GroupView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mContext = context;

        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GroupView, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.GroupView_type:
                    mViewType = a.getInt(R.styleable.GroupView_type, FACETYPE_CIRCLE);
                    break;
                case R.styleable.GroupView_cornor:
                    cornor = (int) a.getDimension(R.styleable.GroupView_cornor,0);
                    break;
                case R.styleable.GroupView_padding:
                    padding = (int) a.getDimension(R.styleable.GroupView_padding,3);
                case R.styleable.GroupView_backgroundGP:
                    background = a.getColor(R.styleable.GroupView_backgroundGP,Color.parseColor("#DDDFD4"));
                    break;
                default:
                    break;
            }
        }

        a.recycle();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureWidth(int widthMeasureSpec){
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST) {
            width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        } else {
            width = MeasureSpec.getSize(widthMeasureSpec);
        }
        return width;
    }

    private int measureHeight(int heightMeasureSpec){
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode == MeasureSpec.AT_MOST) {
            height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        } else {
            height = MeasureSpec.getSize(heightMeasureSpec);
        }
        return height;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        // super.onDraw(canvas);
        Paint paint = new Paint();
        canvas.drawBitmap(createGroupFace(mViewType, mContext, mBitmaps),0,0,paint);
    }

    public void setImageBitmaps(Bitmap[] bitmaps) {
        mBitmaps = bitmaps;
    }

    public void setImageBitmaps(List<Bitmap> bitmaps) {
        mBitmaps = bitmaps.toArray(new Bitmap[bitmaps.size()]);
    }

    public  Bitmap createGroupFace(int type, Context context,
                                   Bitmap[] bitmapArray) {
        System.out.println("hiwhitley"+"type"+type);
        if (type == FACETYPE_CIRCLE) {
            return createGroupBitCircle(bitmapArray, context);
        }
        return createTogetherBit(bitmapArray, context);
    }

    private static Bitmap scaleBitmap(float paramFloat, Bitmap paramBitmap) {
        Matrix localMatrix = new Matrix();
        localMatrix.postScale(paramFloat, paramFloat);
        return Bitmap.createBitmap(paramBitmap, 0, 0, paramBitmap.getWidth(),
                paramBitmap.getHeight(), localMatrix, true);
    }

    /**
     * 拼接群头像 圆形版的
     *
     * @param bitmapArray
     * @param context
     * @return
     */
    private  Bitmap createGroupBitCircle(Bitmap[] bitmapArray,
                                         Context context) {
        if (bitmapArray.length < 1 && bitmapArray.length > 9) {
            return null;
        }
        // 先取一个获取宽和高
        Bitmap tempBitmap = (Bitmap) bitmapArray[0];
        if (tempBitmap == null) {
            return null;
        }
        // 画布的宽
        int tempWidth = width;
        // 画布的高
        int tempHeight = height;
        Bitmap canvasBitmap = Bitmap.createBitmap(tempWidth, tempHeight,
                Bitmap.Config.ARGB_8888);
        Canvas localCanvas = new Canvas(canvasBitmap);
        localCanvas.drawColor(background);
        JoinBitmaps.join(localCanvas, Math.min(tempWidth, tempHeight),
                Arrays.asList(bitmapArray));
        return canvasBitmap;
    }

    /**
     * 拼接群头像
     *
     * @param paramList
     * @param context
     * @return 头像本地路径
     */
    @SuppressWarnings("unused")
    private  Bitmap createTogetherBit(Bitmap[] paramList,
                                      final Context context) {
        if (paramList.length < 1 && paramList.length > 9) {
            return null;
        }
        // 先取一个获取宽和高
        Bitmap tempBitmap = (Bitmap) paramList[0];
        if (tempBitmap == null) {
            return null;
        }
        // 画布的宽
        int tempWidth = width;
        // 画布的高
        int tempHeight = height;
        // 创建一个空格的bitmap
        Bitmap canvasBitmap = Bitmap.createBitmap(tempWidth, tempHeight,
                Bitmap.Config.ARGB_8888);
        // 头像的数量
        int bitmapCount = paramList.length;
        Canvas localCanvas = new Canvas(canvasBitmap);
        localCanvas.drawColor(background);
        int colum = 0;

        if (bitmapCount > 1 && bitmapCount < 5) {
            colum = 2;
        } else if (bitmapCount > 4 && bitmapCount < 10) {
            colum = 3;
        } else {
            colum = 1;
        }
        float scale = 1.0F / colum;
        // 根据列数缩小
        Bitmap scaledBitmap = scaleBitmap(scale, tempBitmap);
        if (padding > 0) {
            padding = dip2px(context, padding);
            // 如果有内边距 再次缩小
            float paddingScale = (float) (tempWidth - (colum + 1) * padding)
                    / colum / scaledBitmap.getWidth();
            scaledBitmap = scaleBitmap(paddingScale, scaledBitmap);
            scale = scale * paddingScale;
        }
        // 第一行的 头像个数
        int topRowCount = bitmapCount % colum;
        // 满行的行数
        int rowCount = bitmapCount / colum;
        if (topRowCount > 0) {
            // 如果第一行头像个数大于零 行数加1
            rowCount++;
        } else if (topRowCount == 0) {
            // 6 或者 9 第一行头像个数和列数一致
            topRowCount = colum;
        }
        // 缩小后头像的宽
        int scaledWidth = scaledBitmap.getWidth();
        // 缩小后头像的高
        int scaledHeight = scaledBitmap.getHeight();
        // 第一个头像与画布顶部的距离
        int firstTop = ((tempHeight - (rowCount * scaledHeight + (rowCount + 1)
                * padding)) / 2)
                + padding;
        // 第一个头像与画布左部的距离
        int firstLeft = ((tempWidth - (topRowCount * scaledWidth + (topRowCount + 1)
                * padding)) / 2)
                + padding;
        for (int i = 0; i < paramList.length; i++) {
            if (i == 9) {// 达到上限 停止
                break;
            }
            // 按照最终压缩比例压缩
            Bitmap bit = scaleBitmap(scale, (Bitmap) paramList[i]);
            if (cornor > 0) {
                // 圆角化
                bit = GetRoundedCornerBitmap(bit);
            }
            localCanvas.drawBitmap(bit, firstLeft, firstTop, null);
            firstLeft += (scaledWidth + padding);
            if (i == topRowCount - 1 | tempWidth - firstLeft < scaledWidth) {
                firstTop += (scaledHeight + padding);
                firstLeft = padding;
            }
            bit.recycle();
        }
        // 重置padding
        //padding = 2;
        localCanvas.save(Canvas.ALL_SAVE_FLAG);
        localCanvas.restore();
        return canvasBitmap;
    }

    /**
     * 圆角
     *
     * @param bitmap
     * @return
     */
    private Bitmap GetRoundedCornerBitmap(Bitmap bitmap) {
        try {
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                    bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight());
            final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight()));
            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(Color.BLACK);
            canvas.drawRoundRect(rectF, cornor, cornor, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

            final Rect src = new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight());

            canvas.drawBitmap(bitmap, src, rect, paint);
            return output;
        } catch (Exception e) {
            return bitmap;
        }
    }

    private  int dip2px(Context context, float value) {
        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                value, context.getResources().getDisplayMetrics()) + 0.5f);
    }


}

2.2直接粘代码

public class JoinBitmaps {
    public static final void join(Canvas canvas, int dimension, List<Bitmap> bitmaps) {
        if (bitmaps == null)
            return;
        int count = Math.min(bitmaps.size(), JoinLayout.max());
        float[] size = JoinLayout.size(count);
        join(canvas, dimension, bitmaps, count, size);
    }

    public static final void join(Canvas canvas, int dimension, List<Bitmap> bitmaps, int count,
                                  float[] size) {
        join(canvas, dimension, bitmaps, count, size, 0.15f);
    }

    public static final void join(Canvas canvas, int dimension, List<Bitmap> bitmaps,
                                  float gapSize) {
        if (bitmaps == null)
            return;
        int count = Math.min(bitmaps.size(), JoinLayout.max());
        float[] size = JoinLayout.size(count);
        join(canvas, dimension, bitmaps, count, size, gapSize);
    }

    public static final void join(Canvas canvas, int dimension, List<Bitmap> bitmaps, int count,
                                  float[] size, float gapSize) {
        if (bitmaps == null)
            return;
        // 旋转角度
        float[] rotation = JoinLayout.rotation(count);
        // paint
        Paint paint = new Paint();
        paint.setAntiAlias(true);

        Matrix matrixJoin = new Matrix();
        // scale as join size
        matrixJoin.postScale(size[0], size[0]);

        canvas.save();
        // canvas.drawColor(Color.RED);
        // index<count bitmaps.size 可能会越界
        for (int index = 0; index < count; index++) {
            Bitmap bitmap = bitmaps.get(index);

            // MATRIX
            Matrix matrix = new Matrix();
            // scale as destination
            matrix.postScale((float) dimension / bitmap.getWidth(),
                    (float) dimension / bitmap.getHeight());

            canvas.save();

            matrix.postConcat(matrixJoin);

            float[] offset = JoinLayout.offset(count, index, dimension, size);
            canvas.translate(offset[0], offset[1]);

            // 缩放
            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                    bitmap.getHeight(), matrix, true);
            // 裁剪
            Bitmap bitmapOk = createMaskBitmap(newBitmap, newBitmap.getWidth(),
                    newBitmap.getHeight(), (int) rotation[index], gapSize);

            canvas.drawBitmap(bitmapOk, 0, 0, paint);
            canvas.restore();
        }

        canvas.restore();
    }

    public static final Bitmap createMaskBitmap(Bitmap bitmap, int viewBoxW, int viewBoxH,
                                                int rotation, float gapSize) {

        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final Paint paint = new Paint();
        paint.setAntiAlias(true);// 抗锯齿
        paint.setFilterBitmap(true);
        int center = Math.round(viewBoxW / 2f);
        canvas.drawCircle(center, center, center, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, 0, 0, paint);

        if (rotation != 360) {
            Matrix matrix = new Matrix();
            // 根据原图的中心位置旋转
            matrix.setRotate(rotation, viewBoxW / 2, viewBoxH / 2);
            canvas.setMatrix(matrix);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawCircle(viewBoxW * (1.5f - gapSize), center, center, paint);
        }
        return output;
    }

    public static final Bitmap createBitmap(int width, int height, List<Bitmap> bitmaps) {
        int count = Math.min(bitmaps.size(), JoinLayout.max());
        float[] size = JoinLayout.size(count);
        return createBitmap(width, height, bitmaps, count, size, 0.15f);
    }

    public static final Bitmap createBitmap(int width, int height, List<Bitmap> bitmaps,
                                            int count, float[] size) {
        return createBitmap(width, height, bitmaps, count, size, 0.15f);
    }

    public static final Bitmap createBitmap(int width, int height, List<Bitmap> bitmaps,
                                            int count, float[] size, float gapSize) {
        Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        int dimen = Math.min(width, height);
        join(canvas, dimen, bitmaps, count, size, gapSize);
        return output;
    }
}

2.3直接粘代码

public class JoinLayout {
    public static final String TAG = JoinLayout.class.getSimpleName();

    public static int max() {
        return 5;
    }

    private static final float[][] rotations = { new float[] { 360.0f }, new float[] { 45.0f, 360.0f },
            new float[] { 120.0f, 0.0f, -120.0f }, new float[] { 90.0f, 180.0f, -90.0f, 0.0f },
            new float[] { 144.0f, 72.0f, 0.0f, -72.0f, -144.0f }, };

    public static float[] rotation(int count) {
        return count > 0 && count <= rotations.length ? rotations[count - 1] : null;
    }

    private static final float[][] sizes = { new float[] { 0.9f, 0.9f },
            new float[] { 0.5f, 0.65f }, new float[] { 0.45f, 0.8f },
            new float[] { 0.45f, 0.91f }, new float[] { 0.38f, 0.80f } };

    public static float[] size(int count) {
        return count > 0 && count <= sizes.length ? sizes[count - 1] : null;
    }

    public static float[] offset(int count, int index, float dimension, float[] size) {
        switch (count) {
            case 1:
                return offset1(index, dimension, size);
            case 2:
                return offset2(index, dimension, size);
            case 3:
                return offset3(index, dimension, size);
            case 4:
                return offset4(index, dimension, size);
            case 5:
                return offset5(index, dimension, size);
            default:
                break;
        }
        return new float[] { 0f, 0f };
    }

    /**
     * 5个头像
     *
     * @param index
     *            下标
     * @param dimension
     *            画布边长(正方形)
     * @param size
     *            size[0]缩放 size[1]边距
     * @return 下标index X,Y轴坐标
     */
    private static float[] offset5(int index, float dimension, float[] size) {
        // 圆的直径
        float cd = (float) dimension * size[0];
        // 边距
        float s1 = -cd * size[1];

        float x1 = 0;
        float y1 = s1;

        float x2 = (float) (s1 * Math.cos(19 * Math.PI / 180));
        float y2 = (float) (s1 * Math.sin(18 * Math.PI / 180));

        float x3 = (float) (s1 * Math.cos(54 * Math.PI / 180));
        float y3 = (float) (-s1 * Math.sin(54 * Math.PI / 180));

        float x4 = (float) (-s1 * Math.cos(54 * Math.PI / 180));
        float y4 = (float) (-s1 * Math.sin(54 * Math.PI / 180));

        float x5 = (float) (-s1 * Math.cos(19 * Math.PI / 180));
        float y5 = (float) (s1 * Math.sin(18 * Math.PI / 180));

        // Log.d(TAG, "x1:" + x1 + "/y1:" + y1);
        // Log.d(TAG, "x2:" + x2 + "/y2:" + y2);
        // Log.d(TAG, "x3:" + x3 + "/y3:" + y3);
        // Log.d(TAG, "x4:" + x4 + "/y4:" + y4);
        // Log.d(TAG, "x5:" + x5 + "/y5:" + y5);

        // 居中 Y轴偏移量
        float xx1 = (dimension - cd - y3 - s1) / 2;
        // 居中 X轴偏移量
        float xxc1 = (dimension - cd) / 2;
        // xx1 = xxc1 = -s1;
        // xx1 = xxc1 = 0;
        switch (index) {
            case 0:
                // return new float[] { s1 + xxc1, xx1 };
                return new float[] { x1 + xxc1, y1 + xx1 };
            case 1:
                return new float[] { x2 + xxc1, y2 + xx1 };
            case 2:
                return new float[] { x3 + xxc1, y3 + xx1 };
            case 3:
                return new float[] { x4 + xxc1, y4 + xx1 };
            case 4:
                return new float[] { x5 + xxc1, y5 + xx1 };
            default:
                break;
        }
        return new float[] { 0f, 0f };
    }

    /**
     * 4个头像
     *
     * @param index
     *            下标
     * @param dimension
     *            画布边长(正方形)
     * @param size
     *            size[0]缩放 size[1]边距
     * @return 下标index X,Y轴坐标
     */
    private static float[] offset4(int index, float dimension, float[] size) {
        // 圆的直径
        float cd = (float) dimension * size[0];
        // 边距
        float s1 = cd * size[1];

        float x1 = 0;
        float y1 = 0;

        float x2 = s1;
        float y2 = y1;

        float x3 = s1;
        float y3 = s1;

        float x4 = x1;
        float y4 = y3;

        // Log.d(TAG, "x1:" + x1 + "/y1:" + y1);
        // Log.d(TAG, "x2:" + x2 + "/y2:" + y2);
        // Log.d(TAG, "x3:" + x3 + "/y3:" + y3);
        // Log.d(TAG, "x4:" + x4 + "/y4:" + y4);

        // 居中 X轴偏移量
        float xx1 = (dimension - cd - s1) / 2;
        switch (index) {
            case 0:
                return new float[] { x1 + xx1, y1 + xx1 };
            case 1:
                return new float[] { x2 + xx1, y2 + xx1 };
            case 2:
                return new float[] { x3 + xx1, y3 + xx1 };
            case 3:
                return new float[] { x4 + xx1, y4 + xx1 };
            default:
                break;
        }
        return new float[] { 0f, 0f };
    }

    /**
     * 3个头像
     *
     * @param index
     *            下标
     * @param dimension
     *            画布边长(正方形)
     * @param size
     *            size[0]缩放 size[1]边距
     * @return 下标index X,Y轴坐标
     */
    private static float[] offset3(int index, float dimension, float[] size) {
        // 圆的直径
        float cd = (float) dimension * size[0];
        // 边距
        float s1 = cd * size[1];
        // 第二个圆的 Y坐标
        float y2 = s1 * (3 / 2);
        // 第二个圆的 X坐标
        float x2 = s1 - y2 / 1.73205f;
        // 第三个圆的 X坐标
        float x3 = s1 * 2 - x2;
        // 居中 Y轴偏移量
        float xx1 = (dimension - cd - y2) / 2;
        // 居中 X轴偏移量
        float xxc1 = (dimension - cd) / 2 - s1;
        // xx1 = xxc1 = 0;
        switch (index) {
            case 0:
                return new float[] { s1 + xxc1, xx1 };
            case 1:
                return new float[] { x2 + xxc1, y2 + xx1 };
            case 2:
                return new float[] { x3 + xxc1, y2 + xx1 };
            default:
                break;
        }
        return new float[] { 0f, 0f };
    }

    /**
     * 2个头像
     *
     * @param index
     *            下标
     * @param dimension
     *            画布边长(正方形)
     * @param size
     *            size[0]缩放 size[1]边距
     * @return 下标index X,Y轴坐标
     */
    private static float[] offset2(int index, float dimension, float[] size) {
        // 圆的直径
        float cd = (float) dimension * size[0];
        // 边距
        float s1 = cd * size[1];

        float x1 = 0;
        float y1 = 0;

        float x2 = s1;
        float y2 = s1;

        // Log.d(TAG, "x1:" + x1 + "/y1:" + y1);
        // Log.d(TAG, "x2:" + x2 + "/y2:" + y2);

        // 居中 X轴偏移量
        float xx1 = (dimension - cd - s1) / 2;
        switch (index) {
            case 0:
                return new float[] { x1 + xx1, y1 + xx1 };
            case 1:
                return new float[] { x2 + xx1, y2 + xx1 };
            default:
                break;
        }
        return new float[] { 0f, 0f };
    }

    /**
     * 1个头像
     *
     * @param index
     *            下标
     * @param dimension
     *            画布边长(正方形)
     * @param size
     *            size[0]缩放 size[1]边距
     * @return 下标index X,Y轴坐标
     */
    private static float[] offset1(int index, float dimension, float[] size) {
        // 圆的直径
        float cd = (float) dimension * size[0];
        float offset = (dimension - cd) / 2;
        return new float[] { offset, offset };
    }
}

2.4在MainActivity中

public class MainActivity extends AppCompatActivity {


    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Resources r = getResources();
        Bitmap b1 = BitmapFactory.decodeResource(r,R.drawable.a1);
        Bitmap b2 = BitmapFactory.decodeResource(r,R.drawable.a2);
        Bitmap b3 = BitmapFactory.decodeResource(r,R.drawable.a3);

        Bitmap [] bitmaps={b1,b2,b3,b1,b2,b3,b1,b2,b3};

        GroupView gridView= (GroupView) findViewById(R.id.group_view);
        gridView.setImageBitmaps(bitmaps);
    }

2.5在布局中

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tgBtn="http://schemas.android.com/apk/res-auto"
    tools:context="com.bitmap.activity.MainActivity">
    <com.bitmap.activity.GroupView  //引用自己包下的GroupView
        android:id="@+id/group_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        app:type="circle"
        app:padding="3dp"
        app:cornor="10dp"
        app:backgroundGP="#ff99"/>
</RelativeLayout>

这里通过自定义属性设置:

type:圆或者方
padding:图片间距
cornor:设置圆角矩形
backgroundGp:背景颜色



这就是所有的代码!!!



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值