Android 圆形ImageView

标题

Android 圆形ImageView


在Android上是实现圆形的ImageView,通过Xfermode实现。

代码实现:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;

import androidx.appcompat.widget.AppCompatImageView;

public class CircleImageView extends AppCompatImageView {

    private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private final Path clipPath = new Path();
    private Matrix matrix;

    public CircleImageView(Context context) {
        super(context);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 关闭硬件加速以确保Xfermode正常工作
        setLayerType(LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        matrix = null; // 重置矩阵,当尺寸变化时重新计算
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            super.onDraw(canvas);
            return;
        }

        // 获取View尺寸(考虑Padding)
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int viewWidth = getWidth() - paddingLeft - paddingRight;
        int viewHeight = getHeight() - paddingTop - paddingBottom;

        if (viewWidth <= 0 || viewHeight <= 0) return;

        // 将Drawable转换为Bitmap
        Bitmap bitmap = drawableToBitmap(drawable);
        if (bitmap == null) return;

        // 计算缩放矩阵(仅需一次或在尺寸变化时计算)
        if (matrix == null) {
            matrix = getScaleMatrix(bitmap, viewWidth, viewHeight);
        }

        // 创建离屏缓冲层
        int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);

        // 绘制目标圆形(DST)
        float radius = Math.min(viewWidth, viewHeight) / 2f;
        float centerX = paddingLeft + viewWidth / 2f;
        float centerY = paddingTop + viewHeight / 2f;
        clipPath.reset();
        clipPath.addCircle(centerX, centerY, radius, Path.Direction.CW);
        canvas.drawPath(clipPath, paint);

        // 设置SRC_IN混合模式
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        // 绘制源Bitmap(应用矩阵偏移)
        canvas.translate(paddingLeft, paddingTop); // 调整绘制位置以考虑Padding
        canvas.drawBitmap(bitmap, matrix, paint);
        canvas.translate(-paddingLeft, -paddingTop); // 复位

        // 恢复状态
        paint.setXfermode(null);
        canvas.restoreToCount(saveCount);
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = Math.max(drawable.getIntrinsicWidth(), 1);
        int height = Math.max(drawable.getIntrinsicHeight(), 1);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, width, height);
        drawable.draw(canvas);
        return bitmap;
    }

    private Matrix getScaleMatrix(Bitmap bitmap, int dstWidth, int dstHeight) {
        Matrix matrix = new Matrix();
        float srcWidth = bitmap.getWidth();
        float srcHeight = bitmap.getHeight();

        // 计算缩放比例(CenterCrop模式)
        float scale = Math.max(
                dstWidth / srcWidth,
                dstHeight / srcHeight
        );

        // 应用缩放并居中
        matrix.setScale(scale, scale);
        float scaledWidth = srcWidth * scale;
        float scaledHeight = srcHeight * scale;
        matrix.postTranslate(
                (dstWidth - scaledWidth) / 2,
                (dstHeight - scaledHeight) / 2
        );

        return matrix;
    }
}

你可能感兴趣的:(android,android,studio,java)