Rendering rounded corners for imageView on Android

我与影子孤独终老i 提交于 2019-12-12 12:31:50

问题


I have the following piece of code for rendering an imageView with rounded corners.

public class RoundedCornerImageView extends ImageView {

private int rounded;
public RoundedCornerImageView(Context context) {
    super(context);
}

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

public RoundedCornerImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}


public int getRounded() {
    return rounded;
}

public void setRounded(int rounded) {
    this.rounded = rounded;

}


@Override
public void onDraw(Canvas canvas)
{


    Drawable drawable = getDrawable();

    int w = drawable.getIntrinsicHeight(),
        h = drawable.getIntrinsicWidth();

    Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
    Canvas tmpCanvas = new Canvas(rounder);

    // We're going to apply this paint eventually using a porter-duff xfer mode.
    // This will allow us to only overwrite certain pixels. RED is arbitrary. This
    // could be any color that was fully opaque (alpha = 255)
    Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    xferPaint.setColor(Color.WHITE);

    // We're just reusing xferPaint to paint a normal looking rounded box, the 20.f
    // is the amount we're rounding by.
    tmpCanvas.drawRoundRect(new RectF(0,0,w,h), 10.0f, 10.0f, xferPaint);

    // Now we apply the 'magic sauce' to the paint
    xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

    drawable.draw(canvas);
    canvas.drawBitmap(rounder, 0, 0, xferPaint);
}
}



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background='#a3deef'
    >
<com.example.scheduling_android.view.RoundedCornerImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/eventImageView"
        android:adjustViewBounds="false"/>
</LinearLayout>

It works in that it is indeed cropping off the corners of the image. However, the problem arises when I try to render this inside a linearLayout that has a background color #a3deef. The resulting display is a background color of #a3deef with each image displayed with rounded corners where the 4 cropped corner are all in black.

What should I do to make the cropped corners transparent rather than black? Also, it would be great if someone could explain to me why it would black, and not any other colors too!

Thanks in advance.


回答1:


The approach you are taking doesn't really work well if the source isn't already a Bitmap, primarily because it's better to draw the content into the Canvas using transfer modes outside the drawing callback (so it only happens once instead of on every draw refresh) and calling Drawable.draw() anywhere else won't produce the correct results since the bounds won't be set as you expect.

A significantly more efficient method of doing this is not to modify the source data and just apply a rounded clip to the drawing Canvas. For really large radii, this can create a little aliasing, but at 10px it won't be noticeable. The only other drawback to this approach is that clipPath() is not currently supported by hardware acceleration, so you will have to set the layer type for this view to software in order for the rendering to work on Android 3.0+

public class RoundedCornerImageView extends ImageView {

    private Path roundedPath;
    private int rounded;

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

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

    public RoundedCornerImageView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        // If the application is hardware accelerated,
        // must disable it for this view.
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        // Set a default radius
        setRounded(10);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            roundedPath = new Path();
            roundedPath.addRoundRect(new RectF(0, 0, w, h),
                    rounded, rounded, Path.Direction.CW);
        }
    }

    public int getRounded() {
        return rounded;
    }

    public void setRounded(int rounded) {
        this.rounded = rounded;
        roundedPath = new Path();
        roundedPath.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
                rounded, rounded, Path.Direction.CW);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //Apply the clip
        canvas.clipPath(roundedPath);
        //Let the view draw as normal
        super.onDraw(canvas);
    }
}

In the modified version, you simply update the clipping path each time either the view or the radius size changes, and apply that Path as a clip to the Canvas before drawing.

HTH




回答2:


Add this line to make the canvas transparent:

canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);

Also, I use a reverse-filled rounded rectangle path to mask the bitmap so I don't need an intermediary masking bitmap like you do.

public class RoundedImageView extends ImageView {

    private Path mMaskPath;
    private Paint mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mCornerRadius = 10;

    public RoundedImageView(Context context) {
        super(context);

        init();
    }

    public RoundedImageView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        init();
    }

    public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init();
    }

    private void init() {
        ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, null);
        mMaskPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
    }

    /**
     * Set the corner radius to use for the RoundedRectangle.
     * 
     * @param Primitive int - The corner radius of the rounded rectangle.
     */
    public void setCornerRadius(int cornerRadius) {
        mCornerRadius = cornerRadius;
        generateMaskPath(getWidth(), getHeight());
        invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        super.onSizeChanged(w, h, oldW, oldH);

        if (w != oldW || h != oldH) {
            generateMaskPath(w, h);
        }
    }

    private void generateMaskPath(int w, int h) {
        mMaskPath = new Path();
        mMaskPath.addRoundRect(new RectF(0,0,w,h), mCornerRadius, mCornerRadius, Direction.CW);
        mMaskPath.setFillType(FillType.INVERSE_WINDING);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(canvas.isOpaque()) { // If canvas is opaque, make it transparent
            canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
        }

        super.onDraw(canvas);

        if(mMaskPath != null) {
            canvas.drawPath(mMaskPath, mMaskPaint);
        }
    }
}



回答3:


This is because your Canvas that you are working with is not transparent. A non-transparent Canvas has a black background.

This answer sets a SurfaceView's Canvas to be transparent. For you, it may be as simple as setting the background of the Bitmap to be transparent.

Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
rounder.eraseColor(Color.TRANSPARENT);

You can also try this in your ImageView, to set its background to 100% transparent:

setBackgroundColor(0);


来源:https://stackoverflow.com/questions/12358350/rendering-rounded-corners-for-imageview-on-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!