Search code examples
androidimageviewandroid-drawableandroid-bitmapandroid-framelayout

Change background image but keep drawable to a view android xml


I have a Framelayout which has some rounded corners through a drawable xml file

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle" >

    <!-- View background color -->
    <solid
            android:color="@color/colorPrimary" >
    </solid>

    <!-- The radius makes the corners rounded -->
    <corners
        android:topLeftRadius="20dp"
        android:bottomRightRadius="20dp" >
    </corners>
</shape>

Inside the FrameLayout i have 2 TextViews and an imageView which gets loaded with a bitmap programmatically. The problem is that i have tried everything to give the ImageView same rounded corners as the FrameLayout so i decided to replace the ImageView with another simple View (as FrameLayout or smth) and set the bitmap image as a background of the view. This didn't work either.

So is there any way in a view to set the drawable with the corners in the xml, and when later programmatically change the background with a bitmap to keep somehow the rounded corners with the new image loaded? Thank you


Solution

  • Solution

    Step 1. Go to res/values folder, create a xml file named attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="RoundedImageView">
            <attr name="topLeftCorner" format="dimension" />
            <attr name="topRightCorner" format="dimension" />
            <attr name="bottomRightCorner" format="dimension" />
            <attr name="bottomLeftCorner" format="dimension" />
        </declare-styleable>
    </resources>
    

    Step 2. Create a class that extends from AppCompatImageView, named RoundedImageView

    public class RoundedImageView extends AppCompatImageView {
    
        private final Path path = new Path();
        private final float[] radii = new float[8];
        private final RectF rect = new RectF();
    
        public RoundedImageView(@NonNull Context context) {
            this(context, null);
        }
    
        public RoundedImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageView);
            try {
                int topLeftCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_topLeftCorner, 0);
                int topRightCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_topRightCorner, 0);
                int bottomRightCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_bottomRightCorner, 0);
                int bottomLeftCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_bottomLeftCorner, 0);
                radii[0] = topLeftCorner;
                radii[1] = topLeftCorner;
                radii[2] = topRightCorner;
                radii[3] = topRightCorner;
                radii[4] = bottomRightCorner;
                radii[5] = bottomRightCorner;
                radii[6] = bottomLeftCorner;
                radii[7] = bottomLeftCorner;
            } finally {
                a.recycle();
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            rect.left = 0;
            rect.top = 0;
            rect.right = getWidth();
            rect.bottom = getHeight();
            path.rewind();
            path.addRoundRect(rect, radii, Path.Direction.CW);
            canvas.clipPath(path);
            super.onDraw(canvas);
        }
    }
    

    Step 3. Use it from layout file.

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F00"
        android:gravity="center">
    
        <com.example.roundedimageview.RoundedImageView
            android:id="@+id/imageView"
            android:layout_width="240dp"
            android:layout_height="240dp"
            android:layout_gravity="center"
            android:scaleType="centerCrop"
            android:src="@drawable/ic_android"
            app:bottomRightCorner="20dp"
            app:topLeftCorner="20dp" />
    </FrameLayout>
    

    Result

    enter image description here

    Benefit

    • You can set the corner radius for top-left, top-right, bottom-right, bottom-left.

    • Work with Glide, Picasso library

    Limitations