绘制CircularImage时XY错误

时间:2016-06-22 22:53:06

标签: android android-view

我正在Android中编写自定义的Circular ImageView。我需要在它上面设置一个Drawable覆盖,所以我选择编写一个自定义的CircularImageView来保存图片本身+ drawable。

其实我有两个问题:

  1. 图像是左上角绘制的,我需要将它绘制在视图的中心
  2. 我需要我的王冠更大(可画)但我不知道如何调整它。
  3. 有些人要澄清:
    我想要实现的目标:
    enter image description here
    我现在拥有的东西:(请不要考虑黑框边框,只是为了澄清错误的图像“重力”)
    enter image description here

    我的观看代码:

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

2 个答案:

答案 0 :(得分:1)

您可以创建一个新的位图,在带有圆形遮罩的透明背景上绘制旧位图,然后在其上绘制表冠。此示例还允许在图像周围添加填充。

您需要调整CIRCLE_PADDINGRESIZE_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 :(得分:0)

  

图像是左上角绘制的,我需要将它绘制在视图的中心

是的,这是因为.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