Неправильно XY при рисовании CircularImage

Я пишу пользовательский Circular ImageView в Android. Мне нужно установить Drawable overlay поверх него, поэтому я решил написать собственный CircularImageView, который содержит сам рисунок + drawable.

На самом деле у меня есть 2 проблемы:

  1. Изображение рисуется вверху слева, мне нужно, чтобы оно было нарисовано в центре окна
  2. Мне нужна моя корона, чтобы быть более крупной (выдвижной), но я не знаю, как ее изменить.

Некоторые из них уточняют:
Что я хотел бы достичь:
Введите описание изображения здесь
То, что у меня есть сейчас: (пожалуйста, не обращайте внимания на черную рамку рамки, это просто для того, чтобы прояснить неправильный образ «тяжести»)
Введите описание изображения здесь

Мой код просмотра:

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()); } } 

Вы можете создать новый растровый рисунок, чтобы нарисовать старый на прозрачном фоне с помощью круглой маски, а затем нарисуйте на нем корону. Этот пример также позволяет добавлять прописку вокруг изображения.

Вы захотите настроить значения 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); 

Изображение рисуется вверху слева, мне нужно, чтобы оно было нарисовано в центре окна

Да, это из-за параметров в .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