Wrong XY when drawing CircularImage

I am writing a custom Circular ImageView in Android. I need to install Drawable overlay on top of it, so I decided to write a custom CircularImageView that contains the drawing itself + drawable.

Actually, I have 2 problems:

  • The image is drawn at the top left, I need it to be drawn in the center of the view
  • I need my crown to be larger (stretched), but I don’t know how to change it.

Some imgs for clarification:
What I would like to achieve: What I have now: (please do not pay attention to the black border of the frame, this is just to clarify the wrong image of "gravity")
enter image description here

enter image description here

My view code:

public class CrownCircularImageView extends ImageView {

    private Drawable crown;
    private int canvasSize;
    private int crownWidth;
    private int crownHeight;

    // Object used to draw
    private Bitmap image;
    private Drawable drawable;
    private Paint paint;
    private Paint crownPaint;

    public CrownCircularImageView(Context context) {
        this(context, null, 0);
    }

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

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

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        crownPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.crown = ContextCompat.getDrawable(context, R.drawable.ic_crown);
    }

    private void loadBitmap() {
        if (this.drawable == getDrawable())
            return;

        this.drawable = getDrawable();
        this.image = drawableToBitmap(this.drawable);
        updateShader();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        canvasSize = w - crownWidth;
        if (h < canvasSize)
            canvasSize = h - crownHeight;
        if (image != null)
            updateShader();
    }

    private void updateShader() {
        if (image == null)
            return;

        // Crop Center Image
        image = cropBitmap(image);

        // Create Shader
        BitmapShader shader = new BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        // Center Image in Shader
        Matrix matrix = new Matrix();
        matrix.setScale((float) canvasSize / (float) image.getWidth(), (float) canvasSize / (float) image.getHeight());
        shader.setLocalMatrix(matrix);

        // Set Shader in Paint
        paint.setShader(shader);
    }

    private Bitmap cropBitmap(Bitmap bitmap) {
        Bitmap bmp;
        if (bitmap.getWidth() >= bitmap.getHeight()) {
            bmp = Bitmap.createBitmap(
                    bitmap,
                    bitmap.getWidth() / 2 - bitmap.getHeight() / 2,
                    0,
                    bitmap.getHeight(),
                    bitmap.getHeight());
        } else {
            bmp = Bitmap.createBitmap(
                    bitmap,
                    0,
                    bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
                    bitmap.getWidth(),
                    bitmap.getWidth());
        }
        return bmp;
    }

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

        int intrinsicWidth = drawable.getIntrinsicWidth();
        int intrinsicHeight = drawable.getIntrinsicHeight();

        if (!(intrinsicWidth > 0 && intrinsicHeight > 0))
            return null;

        try {
            // Create Bitmap object out of the drawable
            Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            // Simply return null of failed bitmap creations
            Log.e(getClass().toString(), "Encountered OutOfMemoryError while generating bitmap!");
            return null;
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        // Load the bitmap
        loadBitmap();

        // Check if image isn't null
        if (image == null)
            return;

        if (!isInEditMode()) {
            canvasSize = canvas.getWidth();
            if (canvas.getHeight() < canvasSize) {
                canvasSize = canvas.getHeight();
            }
        }

        int circleCenter = (canvasSize - crownHeight) / 2;
        int cx = (canvasSize - crownWidth) / 2;
        int cy = (canvasSize - crownHeight) / 2;

        Bitmap crownBmp = drawableToBitmap(crown);

        int crownX = cx;
        int crownY = cy;

        canvas.drawCircle(cx, cy, circleCenter, paint);
        canvas.drawBitmap(crownBmp, crownX, crownY, crownPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);

        crownWidth = crown.getIntrinsicWidth();
        crownHeight = crown.getIntrinsicHeight();

        setMeasuredDimension(width, height);
    }

    @Override
    public ScaleType getScaleType() {
        return ScaleType.CENTER_CROP;
    }

    private int measureWidth(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            // The parent has determined an exact size for the child.
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            // The child can be as large as it wants up to the specified size.
            result = specSize;
        } else {
            // The parent has not imposed any constraint on the child.
            result = canvasSize;
        }

        return result + crown.getIntrinsicWidth();
    }

    private int measureHeight(int measureSpecHeight) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpecHeight);
        int specSize = MeasureSpec.getSize(measureSpecHeight);

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            // The child can be as large as it wants up to the specified size.
            result = specSize;
        } else {
            // Measure the text (beware: ascent is a negative number)
            result = canvasSize;
        }

        return (result + 2 + crown.getIntrinsicHeight());
    }

}
+4
2

, , . .

CIRCLE_PADDING RESIZE_CROWN_FACTOR, .

public class CrownImageView extends ImageView {
    private static final int CIRCLE_PADDING = 25;
    private static final float RESIZE_CROWN_FACTOR = 1.5f;

    private Bitmap rounded;
    private Bitmap resizedCrown;

    public CrownImageView(final Context context) {
        super(context);
    }

    public CrownImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    public CrownImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();

        if (drawable == null || getWidth() == 0 || getHeight() == 0) {
            return;
        }

        if (resizedCrown == null) {
            loadCrown();
        }

        loadImage(drawable);

        canvas.drawBitmap(rounded, 0, 0, null);
        canvas.drawBitmap(resizedCrown, canvas.getWidth() - resizedCrown.getWidth(), 0, null);
    }

    private void loadImage(Drawable drawable) {
        Bitmap bmp = bitmapFromDrawable(drawable);

        final Rect rect = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());

        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);

        rounded = Bitmap.createBitmap(bmp.getWidth(),
                bmp.getHeight(), Bitmap.Config.ARGB_8888);

        Canvas newCanvas = new Canvas(rounded);
        newCanvas.drawARGB(0, 0, 0, 0);

        float centerX = getWidth() / 2;
        float centerY = getHeight() / 2;
        float radius = Math.min(getWidth(), getHeight()) / 2 - CIRCLE_PADDING;
        newCanvas.drawCircle(centerX, centerY, radius, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        newCanvas.drawBitmap(bmp, rect, rect, paint);
    }

    private void loadCrown() {
        Bitmap crown = BitmapFactory.decodeResource(getResources(), R.drawable.crown);
        resizedCrown = Bitmap.createScaledBitmap(crown,
                (int) (crown.getWidth() * RESIZE_CROWN_FACTOR),
                (int) (crown.getHeight() * RESIZE_CROWN_FACTOR),
                true);
    }

    private Bitmap bitmapFromDrawable(Drawable drawable) {
        Bitmap bmp;

        if (drawable instanceof BitmapDrawable) {
            bmp = ((BitmapDrawable) drawable).getBitmap();
        } else {
            bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas bmpCanvas = new Canvas(bmp);
            drawable.setBounds(0, 0, bmpCanvas.getWidth(), bmpCanvas.getHeight());
            drawable.draw(bmpCanvas);
        }

        return bmp;
    }
}

: Glide,

final CrownImageView imageView = (CrownImageView) findViewById(R.id.fragment_kids_row_img_kids);
Glide.with(this).load(yourimageurl).into(imageView);
+1

, , View

, - .drawCircle

canvas.drawCircle(cx, cy, circleCenter, paint);

. -

int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
float bitmapRadius = Math.min(image.getWidth(), image.getHeight()) / 2f;
canvas.drawCircle(centerX, centerY, bitmapRadius, paint);

, .

, (), , .

- , .

Bitmap bitmap = Bitmap.createBitmap(
      intrinsicWidth + scale, 
      intrinsicHeight + scale, 
      Bitmap.Config.ARGB_8888);

: http://pastebin.com/0h02Tqh1

0

All Articles