I'm trying to make one rounded corner of ImageView like in the picture below but with bottom right corner. Tried using background shape but it's not working at all. All images loaded by Glide. Should i use something like ViewOutlineProvider? Is there are an efficient way to do this? Thanks!

<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <corners
        android:radius="2dp"
        android:bottomRightRadius="20dp"
        android:bottomLeftRadius="0dp"
        android:topLeftRadius="0dp"
        android:topRightRadius="0dp"/>
</shape>

Example from Android Material Docs


The Material Components library introduced the ShapeableImageView starting from the version 1.2.0-alpha03.

Just use something like:

  <com.google.android.material.imageview.ShapeableImageView
      android:id="@+id/image_view"
      android:scaleType="centerInside"
      android:adjustViewBounds="true"
      ../>

then in your code you can apply the ShapeAppearanceModel with:

ShapeableImageView imageView = findViewById(R.id.image_view);
float radius = getResources().getDimension(R.dimen.default_corner_radius);
imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
    .toBuilder()
    .setTopRightCorner(CornerFamily.ROUNDED,radius)
    .build());

enter image description here

You can also apply in the xml the shapeAppearanceOverlay parameter:

<com.google.android.material.imageview.ShapeableImageView
      app:shapeAppearanceOverlay="@style/customRroundedImageView"
      app:srcCompat="@drawable/ic_image" />

with:

  <style name="customRoundedImageView" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSize">0dp</item>   
    <item name="cornerSizeTopRight">8dp</item>
  </style>

With jetpack compose you can apply the clip Modifier using a RoundedCornerShape:

Image(painterResource(id = R.drawable.xxx),
    contentDescription = "xxxx",
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(xx.dp,xx.dp)
        .clip(RoundedCornerShape(topStart = 12.dp)),
)

enter image description here


Also if you want to get rid of writing code in ".java" file. Then you can define style like below and just add it to your ShapeableImageView:

<com.google.android.material.imageview.ShapeableImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ex_image"
    app:shapeAppearanceOverlay="@style/roundedImageView"
    />

then:

<style name="roundedImageView" parent="">
    <item name="cornerFamilyTopRight">rounded</item>
    <item name="cornerSizeTopRight">30dp</item>
</style>

this is your main layout file which uses a custom drawable "round_one.xml"file. just copy and paste this code. it will hopefully meet your requirements.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:elevation="@dimen/_10sdp"
    android:background="@color/white"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/round_one"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="@dimen/_80sdp"
            android:layout_gravity="center"
            android:scaleType="fitXY"
            android:src="@android:drawable/ic_menu_day" />
        <TextView
            android:id="@+id/textView22"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="8dp"
            android:text="title goes here" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            android:text="Secondary text"
            />
    </LinearLayout>


</androidx.cardview.widget.CardView>

round_one.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/gray" />
    <corners android:topRightRadius="50dp" />
</shape>

To round only one corner of imageview follow below steps and code:

Add below file to your project RoundCornerImageView.java

package com.skd.stackdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

public class RoundCornerImageView extends ImageView {

    public static final String TAG = "RoundCornerImageView";

    private int mResource = 0;

    private static final ScaleType[] sScaleTypeArray = {
            ScaleType.MATRIX,
            ScaleType.FIT_XY,
            ScaleType.FIT_START,
            ScaleType.FIT_CENTER,
            ScaleType.FIT_END,
            ScaleType.CENTER,
            ScaleType.CENTER_CROP,
            ScaleType.CENTER_INSIDE
    };

    // Set default scale type to FIT_CENTER, which is default scale type of
    // original ImageView.
    private ScaleType mScaleType = ScaleType.FIT_CENTER;

    private float mLeftTopCornerRadius = 0.0f;
    private float mRightTopCornerRadius = 0.0f;
    private float mLeftBottomCornerRadius = 0.0f;
    private float mRightBottomCornerRadius = 0.0f;

    private float mBorderWidth = 0.0f;
    private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
    private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);

    private boolean isOval = false;

    private Drawable mDrawable;

    private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };

    public RoundCornerImageView(Context context) {
        super(context);
    }

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

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

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.SelectableRoundedImageView, defStyle, 0);

        final int index = a.getInt(R.styleable.SelectableRoundedImageView_android_scaleType, -1);
        if (index >= 0) {
            setScaleType(sScaleTypeArray[index]);
        }

        mLeftTopCornerRadius = a.getDimensionPixelSize(
                R.styleable.SelectableRoundedImageView_sriv_left_top_corner_radius, 0);
        mRightTopCornerRadius = a.getDimensionPixelSize(
                R.styleable.SelectableRoundedImageView_sriv_right_top_corner_radius, 0);
        mLeftBottomCornerRadius = a.getDimensionPixelSize(
                R.styleable.SelectableRoundedImageView_sriv_left_bottom_corner_radius, 0);
        mRightBottomCornerRadius = a.getDimensionPixelSize(
                R.styleable.SelectableRoundedImageView_sriv_right_bottom_corner_radius, 0);

        if (mLeftTopCornerRadius < 0.0f || mRightTopCornerRadius < 0.0f
                || mLeftBottomCornerRadius < 0.0f || mRightBottomCornerRadius < 0.0f) {
            throw new IllegalArgumentException("radius values cannot be negative.");
        }

        mRadii = new float[] {
                mLeftTopCornerRadius, mLeftTopCornerRadius,
                mRightTopCornerRadius, mRightTopCornerRadius,
                mRightBottomCornerRadius, mRightBottomCornerRadius,
                mLeftBottomCornerRadius, mLeftBottomCornerRadius };

        mBorderWidth = a.getDimensionPixelSize(
                R.styleable.SelectableRoundedImageView_sriv_border_width, 0);
        if (mBorderWidth < 0) {
            throw new IllegalArgumentException("border width cannot be negative.");
        }

        mBorderColor = a
                .getColorStateList(R.styleable.SelectableRoundedImageView_sriv_border_color);
        if (mBorderColor == null) {
            mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
        }

        isOval = a.getBoolean(R.styleable.SelectableRoundedImageView_sriv_oval, false);
        a.recycle();

        updateDrawable();
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        invalidate();
    }

    @Override
    public ScaleType getScaleType() {
        return mScaleType;
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        super.setScaleType(scaleType);
        mScaleType = scaleType;
        updateDrawable();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        mResource = 0;
        mDrawable = RoundCornerDrawable.fromDrawable(drawable, getResources());
        super.setImageDrawable(mDrawable);
        updateDrawable();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        mResource = 0;
        mDrawable = RoundCornerDrawable.fromBitmap(bm, getResources());
        super.setImageDrawable(mDrawable);
        updateDrawable();
    }

    @Override
    public void setImageResource(int resId) {
        if (mResource != resId) {
            mResource = resId;
            mDrawable = resolveResource();
            super.setImageDrawable(mDrawable);
            updateDrawable();
        }
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        setImageDrawable(getDrawable());
    }

    private Drawable resolveResource() {
        Resources rsrc = getResources();
        if (rsrc == null) {
            return null;
        }

        Drawable d = null;

        if (mResource != 0) {
            try {
                d = rsrc.getDrawable(mResource);
            } catch (Resources.NotFoundException e) {
                Log.w(TAG, "Unable to find resource: " + mResource, e);
                // Don't try again.
                mResource = 0;
            }
        }
        return RoundCornerDrawable.fromDrawable(d, getResources());
    }

    private void updateDrawable() {
        if (mDrawable == null) {
            return;
        }

        ((RoundCornerDrawable) mDrawable).setScaleType(mScaleType);
        ((RoundCornerDrawable) mDrawable).setCornerRadii(mRadii);
        ((RoundCornerDrawable) mDrawable).setBorderWidth(mBorderWidth);
        ((RoundCornerDrawable) mDrawable).setBorderColor(mBorderColor);
        ((RoundCornerDrawable) mDrawable).setOval(isOval);
    }

    public float getCornerRadius() {
        return mLeftTopCornerRadius;
    }

    /**
     * Set radii for each corner.
     *
     * @param leftTop The desired radius for left-top corner in dip.
     * @param rightTop The desired desired radius for right-top corner in dip.
     * @param leftBottom The desired radius for left-bottom corner in dip.
     * @param rightBottom The desired radius for right-bottom corner in dip.
     *
     */
    public void setCornerRadiiDP(float leftTop, float rightTop, float leftBottom, float rightBottom) {
        final float density = getResources().getDisplayMetrics().density;

        final float lt = leftTop * density;
        final float rt = rightTop * density;
        final float lb = leftBottom * density;
        final float rb = rightBottom * density;

        mRadii = new float[] { lt, lt, rt, rt, rb, rb, lb, lb };
        updateDrawable();
    }

    public float getBorderWidth() {
        return mBorderWidth;
    }

    /**
     * Set border width.
     *
     * @param width
     *            The desired width in dip.
     */
    public void setBorderWidthDP(float width) {
        float scaledWidth = getResources().getDisplayMetrics().density * width;
        if (mBorderWidth == scaledWidth) {
            return;
        }

        mBorderWidth = scaledWidth;
        updateDrawable();
        invalidate();
    }

    public int getBorderColor() {
        return mBorderColor.getDefaultColor();
    }

    public void setBorderColor(int color) {
        setBorderColor(ColorStateList.valueOf(color));
    }

    public ColorStateList getBorderColors() {
        return mBorderColor;
    }

    public void setBorderColor(ColorStateList colors) {
        if (mBorderColor.equals(colors)) {
            return;
        }

        mBorderColor = (colors != null) ? colors : ColorStateList
                .valueOf(DEFAULT_BORDER_COLOR);
        updateDrawable();
        if (mBorderWidth > 0) {
            invalidate();
        }
    }

    public boolean isOval() {
        return isOval;
    }

    public void setOval(boolean oval) {
        isOval = oval;
        updateDrawable();
        invalidate();
    }

    static class RoundCornerDrawable extends Drawable {

        private static final String TAG = "RoundCornerDrawable";
        private static final int DEFAULT_BORDER_COLOR = Color.BLACK;

        private RectF mBounds = new RectF();
        private RectF mBorderBounds = new RectF();

        private final RectF mBitmapRect = new RectF();
        private final int mBitmapWidth;
        private final int mBitmapHeight;

        private final Paint mBitmapPaint;
        private final Paint mBorderPaint;

        private BitmapShader mBitmapShader;

        private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };
        private float[] mBorderRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };

        private boolean mOval = false;

        private float mBorderWidth = 0;
        private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
        // Set default scale type to FIT_CENTER, which is default scale type of
        // original ImageView.
        private ScaleType mScaleType = ScaleType.FIT_CENTER;

        private Path mPath = new Path();
        private Bitmap mBitmap;
        private boolean mBoundsConfigured = false;

        public RoundCornerDrawable(Bitmap bitmap, Resources r) {
            mBitmap = bitmap;
            mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

            if (bitmap != null) {
                mBitmapWidth = bitmap.getScaledWidth(r.getDisplayMetrics());
                mBitmapHeight = bitmap.getScaledHeight(r.getDisplayMetrics());
            } else {
                mBitmapWidth = mBitmapHeight = -1;
            }

            mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);

            mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mBitmapPaint.setStyle(Paint.Style.FILL);
            mBitmapPaint.setShader(mBitmapShader);

            mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mBorderPaint.setStyle(Paint.Style.STROKE);
            mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
            mBorderPaint.setStrokeWidth(mBorderWidth);
        }

        public static RoundCornerDrawable fromBitmap(Bitmap bitmap, Resources r) {
            if (bitmap != null) {
                return new RoundCornerDrawable(bitmap, r);
            } else {
                return null;
            }
        }

        @SuppressLint("LongLogTag")
        public static Drawable fromDrawable(Drawable drawable, Resources r) {
            if (drawable != null) {
                if (drawable instanceof RoundCornerDrawable) {
                    return drawable;
                } else if (drawable instanceof LayerDrawable) {
                    LayerDrawable ld = (LayerDrawable) drawable;
                    final int num = ld.getNumberOfLayers();
                    for (int i = 0; i < num; i++) {
                        Drawable d = ld.getDrawable(i);
                        ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d, r));
                    }
                    return ld;
                }

                Bitmap bm = drawableToBitmap(drawable);
                if (bm != null) {
                    return new RoundCornerDrawable(bm, r);
                } else {
                    Log.w(TAG, "Failed to create bitmap from drawable!");
                }
            }
            return drawable;
        }

        public static Bitmap drawableToBitmap(Drawable drawable) {
            if (drawable == null) {
                return null;
            }

            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            }

            Bitmap bitmap;
            int width = Math.max(drawable.getIntrinsicWidth(), 2);
            int height = Math.max(drawable.getIntrinsicHeight(), 2);
            try {
                bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                drawable.draw(canvas);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                bitmap = null;
            }
            return bitmap;
        }

        @Override
        public boolean isStateful() {
            return mBorderColor.isStateful();
        }

        @Override
        protected boolean onStateChange(int[] state) {
            int newColor = mBorderColor.getColorForState(state, 0);
            if (mBorderPaint.getColor() != newColor) {
                mBorderPaint.setColor(newColor);
                return true;
            } else {
                return super.onStateChange(state);
            }
        }

        private void configureBounds(Canvas canvas) {
            // I have discovered a truly marvelous explanation of this,
            // which this comment space is too narrow to contain. :)
            // If you want to understand what's going on here,
            // See http://www.joooooooooonhokim.com/?p=289
            Rect clipBounds = canvas.getClipBounds();
            Matrix canvasMatrix = canvas.getMatrix();

            if (ScaleType.CENTER == mScaleType) {
                mBounds.set(clipBounds);
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                applyScaleToRadii(canvasMatrix);
                mBounds.set(clipBounds);
            } else if (ScaleType.FIT_XY == mScaleType) {
                Matrix m = new Matrix();
                m.setRectToRect(mBitmapRect, new RectF(clipBounds), Matrix.ScaleToFit.FILL);
                mBitmapShader.setLocalMatrix(m);
                mBounds.set(clipBounds);
            } else if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
                    || ScaleType.FIT_CENTER == mScaleType || ScaleType.CENTER_INSIDE == mScaleType) {
                applyScaleToRadii(canvasMatrix);
                mBounds.set(mBitmapRect);
            } else if (ScaleType.MATRIX == mScaleType) {
                applyScaleToRadii(canvasMatrix);
                mBounds.set(mBitmapRect);
            }
        }

        private void applyScaleToRadii(Matrix m) {
            float[] values = new float[9];
            m.getValues(values);
            for (int i = 0; i < mRadii.length; i++) {
                mRadii[i] = mRadii[i] / values[0];
            }
        }

        private void adjustCanvasForBorder(Canvas canvas) {
            Matrix canvasMatrix = canvas.getMatrix();
            final float[] values = new float[9];
            canvasMatrix.getValues(values);

            final float scaleFactorX = values[0];
            final float scaleFactorY = values[4];
            final float translateX = values[2];
            final float translateY = values[5];

            final float newScaleX = mBounds.width()
                    / (mBounds.width() + mBorderWidth + mBorderWidth);
            final float newScaleY = mBounds.height()
                    / (mBounds.height() + mBorderWidth + mBorderWidth);

            canvas.scale(newScaleX, newScaleY);
            if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
                    || ScaleType.FIT_XY == mScaleType || ScaleType.FIT_CENTER == mScaleType
                    || ScaleType.CENTER_INSIDE == mScaleType || ScaleType.MATRIX == mScaleType) {
                canvas.translate(mBorderWidth, mBorderWidth);
            } else if (ScaleType.CENTER == mScaleType || ScaleType.CENTER_CROP == mScaleType) {
                // First, make translate values to 0
                canvas.translate(
                        -translateX / (newScaleX * scaleFactorX),
                        -translateY / (newScaleY * scaleFactorY));
                // Then, set the final translate values.
                canvas.translate(-(mBounds.left - mBorderWidth), -(mBounds.top - mBorderWidth));
            }
        }

        private void adjustBorderWidthAndBorderBounds(Canvas canvas) {
            Matrix canvasMatrix = canvas.getMatrix();
            final float[] values = new float[9];
            canvasMatrix.getValues(values);

            final float scaleFactor = values[0];

            float viewWidth = mBounds.width() * scaleFactor;
            mBorderWidth = (mBorderWidth * mBounds.width()) / (viewWidth - (2 * mBorderWidth));
            mBorderPaint.setStrokeWidth(mBorderWidth);

            mBorderBounds.set(mBounds);
            mBorderBounds.inset(- mBorderWidth / 2, - mBorderWidth / 2);
        }

        private void setBorderRadii() {
            for (int i = 0; i < mRadii.length; i++) {
                if (mRadii[i] > 0) {
                    mBorderRadii[i] = mRadii[i];
                    mRadii[i] = mRadii[i] - mBorderWidth;
                }
            }
        }

        @Override
        public void draw(Canvas canvas) {
            canvas.save();
            if (!mBoundsConfigured) {
                configureBounds(canvas);
                if (mBorderWidth > 0) {
                    adjustBorderWidthAndBorderBounds(canvas);
                    setBorderRadii();
                }
                mBoundsConfigured = true;
            }

            if (mOval) {
                if (mBorderWidth > 0) {
                    adjustCanvasForBorder(canvas);
                    mPath.addOval(mBounds, Path.Direction.CW);
                    canvas.drawPath(mPath, mBitmapPaint);
                    mPath.reset();
                    mPath.addOval(mBorderBounds, Path.Direction.CW);
                    canvas.drawPath(mPath, mBorderPaint);
                } else {
                    mPath.addOval(mBounds, Path.Direction.CW);
                    canvas.drawPath(mPath, mBitmapPaint);
                }
            } else {
                if (mBorderWidth > 0) {
                    adjustCanvasForBorder(canvas);
                    mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
                    canvas.drawPath(mPath, mBitmapPaint);
                    mPath.reset();
                    mPath.addRoundRect(mBorderBounds, mBorderRadii, Path.Direction.CW);
                    canvas.drawPath(mPath, mBorderPaint);
                } else {
                    mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
                    canvas.drawPath(mPath, mBitmapPaint);
                }
            }
            canvas.restore();
        }

        public void setCornerRadii(float[] radii) {
            if (radii == null)
                return;

            if (radii.length != 8) {
                throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
            }

            for (int i = 0; i < radii.length; i++) {
                mRadii[i] = radii[i];
            }
        }

        @Override
        public int getOpacity() {
            return (mBitmap == null || mBitmap.hasAlpha() || mBitmapPaint.getAlpha() < 255) ? PixelFormat.TRANSLUCENT
                    : PixelFormat.OPAQUE;
        }

        @Override
        public void setAlpha(int alpha) {
            mBitmapPaint.setAlpha(alpha);
            invalidateSelf();
        }

        @Override
        public void setColorFilter(ColorFilter cf) {
            mBitmapPaint.setColorFilter(cf);
            invalidateSelf();
        }

        @Override
        public void setDither(boolean dither) {
            mBitmapPaint.setDither(dither);
            invalidateSelf();
        }

        @Override
        public void setFilterBitmap(boolean filter) {
            mBitmapPaint.setFilterBitmap(filter);
            invalidateSelf();
        }

        @Override
        public int getIntrinsicWidth() {
            return mBitmapWidth;
        }

        @Override
        public int getIntrinsicHeight() {
            return mBitmapHeight;
        }

        public float getBorderWidth() {
            return mBorderWidth;
        }

        public void setBorderWidth(float width) {
            mBorderWidth = width;
            mBorderPaint.setStrokeWidth(width);
        }

        public int getBorderColor() {
            return mBorderColor.getDefaultColor();
        }

        public void setBorderColor(int color) {
            setBorderColor(ColorStateList.valueOf(color));
        }

        public ColorStateList getBorderColors() {
            return mBorderColor;
        }

        /**
         * Controls border color of this ImageView.
         *
         * @param colors
         *            The desired border color. If it's null, no border will be
         *            drawn.
         *
         */
        public void setBorderColor(ColorStateList colors) {
            if (colors == null) {
                mBorderWidth = 0;
                mBorderColor = ColorStateList.valueOf(Color.TRANSPARENT);
                mBorderPaint.setColor(Color.TRANSPARENT);
            } else {
                mBorderColor = colors;
                mBorderPaint.setColor(mBorderColor.getColorForState(getState(),
                        DEFAULT_BORDER_COLOR));
            }
        }

        public boolean isOval() {
            return mOval;
        }

        public void setOval(boolean oval) {
            mOval = oval;
        }

        public ScaleType getScaleType() {
            return mScaleType;
        }

        public void setScaleType(ScaleType scaleType) {
            if (scaleType == null) {
                return;
            }
            mScaleType = scaleType;
        }
    }

}

Add styleable to attr file under res folder

<declare-styleable name="RoundCornerImageView">
        <attr name="sriv_left_top_corner_radius" format="dimension" />
        <attr name="sriv_right_top_corner_radius" format="dimension" />
        <attr name="sriv_left_bottom_corner_radius" format="dimension" />
        <attr name="sriv_right_bottom_corner_radius" format="dimension" />
        <attr name="sriv_border_width" format="dimension" />
        <attr name="sriv_border_color" format="color" />
        <attr name="sriv_oval" format="boolean" />
        <attr name="android:scaleType" />
    </declare-styleable>

Used in XML file:

 <com.skd.stackdemo.RoundCornerImageView
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:src="@drawable/android"
        android:scaleType="centerCrop"
        app:sriv_left_top_corner_radius="0dp"
        app:sriv_right_top_corner_radius="20dp"
        app:sriv_left_bottom_corner_radius="0dp"
        app:sriv_right_bottom_corner_radius="0dp"
        app:sriv_oval="false" />

Output for above code is:

enter image description here

For more information please check this github project:SelectableRoundedImageView

I hope it works for you