ImageView 只有一个圆角

Posted

技术标签:

【中文标题】ImageView 只有一个圆角【英文标题】:ImageView with only one rounded corner 【发布时间】:2020-04-02 13:22:27 【问题描述】:

我正在尝试制作ImageView 的一个圆角,如下图所示,但带有右下角。尝试使用背景形状,但它根本不起作用。 Glide 加载的所有图像。我应该使用ViewOutlineProvider 之类的东西吗?有没有一种有效的方法来做到这一点?谢谢!

<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>

【问题讨论】:

这里是可能对你有用的库:github.com/pungrue26/SelectableRoundedImageView 你能发布一张视图的图片吗,它是如何使用你添加的当前代码寻找你的?因为相同的代码给了我你想要的底部圆角。还要发布要应用形状的 ImageView 的代码 【参考方案1】:

Material Components library从1.2.0-alpha03版本开始引入了ShapeableImageView

只需使用类似的东西:

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

然后在您的代码中,您可以将ShapeAppearanceModel 应用于:

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

你也可以在xml中应用shapeAppearanceOverlay参数:

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

与:

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

使用 jetpack compose,您可以使用 RoundedCornerShape 应用 clip 修饰符:

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

【讨论】:

是否仍然不支持在ShapeableImageView 上通过 XML(直接在视图上或通过样式/主题)自定义 shapeAppearance 和/或 shapeAppearanceOverlay @Richard 是的。例如,您可以在 xml 布局中使用:app:shapeAppearance="?attr/shapeAppearanceMediumComponent" 谢谢,它成功了 ;-) 虽然它在 Android Studio 布局预览中没有正确显示。运行时,ShapeableImageView 正确显示(带有圆形边缘)。在预览时,它显示一个矩形。这是一个错误吗? 此功能现在在 1.2.0 中稳定【参考方案2】:

此外,如果您想摆脱在“.java”文件中编写代码。然后你可以像下面这样定义 style 并将其添加到你的ShapeableImageView:

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

然后:

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

【讨论】:

【参考方案3】:

这是您的主要布局文件,它使用自定义可绘制“round_one.xml”文件。只需复制并粘贴此代码。 它有望满足您的要求。

<?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_
    android:layout_>

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_
        android:layout_
        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_
            android:layout_
            android:layout_gravity="center"
            android:scaleType="fitXY"
            android:src="@android:drawable/ic_menu_day" />
        <TextView
            android:id="@+id/textView22"
            android:layout_
            android:layout_
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="8dp"
            android:text="title goes here" />

        <TextView
            android:layout_
            android:layout_
            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>

【讨论】:

【参考方案4】:

要只圆 imageview 的一个角,请按照以下步骤和代码:

将以下文件添加到您的项目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;
        
    


styleable添加到res文件夹下的attr文件

<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>

在 XML 文件中使用:

 <com.skd.stackdemo.RoundCornerImageView
        android:layout_
        android:layout_
        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" />

上述代码的输出是:

更多信息请查看这个github项目:SelectableRoundedImageView

希望对你有用

【讨论】:

以上是关于ImageView 只有一个圆角的主要内容,如果未能解决你的问题,请参考以下文章

创建带圆角的 ImageView [重复]

Xamarin.iOS UITableViewCell ImageView 上的圆角

android 如何重写imageview 让图片有圆角效果

Android自己定义圆角ImageView

UITableViewCell 圆角 imageView

带圆角的 CardView 内的 ImageView 绘制不正确