Home > Mobile >  Rounded corner image view with a custom view
Rounded corner image view with a custom view

Time:05-10

I currently am trying to make a project which does not use any libraries. Now, I wanted to use a round image many times I can't just do this:

<CardView>
   <ImageView/>
</CardView>

every time. So, I decided to make a custom class for it. This is my class:

class RoundedImageView : AppCompatImageView {

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        init(attributeSet)
    }

    constructor(context: Context) : super(context) {
        init(null);
    }

    private fun init(attributeSet: AttributeSet?) {
        if (attributeSet == null) return

        val typedArray: TypedArray =
            context.obtainStyledAttributes(attributeSet, R.styleable.RoundedImageView, 0, 0)
        try {
            val bitmapDrawable : BitmapDrawable? = drawable as? BitmapDrawable

            val cornerRadius = typedArray.getDimension(R.styleable.RoundedImageView_cornerRadius,0F)

            bitmapDrawable?.bitmap?.let { getRoundedCornerBitmap(it, cornerRadius) }
        }finally {
            typedArray.recycle()
        }
    }

    private fun getRoundedCornerBitmap(bitmap: Bitmap, pixels: Float) {
        val output = Bitmap.createBitmap(
            bitmap.width, bitmap
                .height, Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(output)
        val color = -0xbdbdbe
        val paint = Paint()
        val rect = Rect(0, 0, bitmap.width, bitmap.height)
        val rectF = RectF(rect)
        val roundPx = pixels.toFloat()
        paint.isAntiAlias = true
        canvas.drawARGB(0, 0, 0, 0)
        paint.color = color
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, rect, rect, paint)
        setImageBitmap(bitmap)
    }
}

But, that does not seem to work. This is what I get as a result: enter image description here

And, this the code I used for it:

<com.sambhav2358.facebookclone.customviews.RoundedImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"/>

I am not even sure whether the code reaches that method or not


PS: Dont mark it as duplicate because I tried every thing here but none of them seem to work. Even that method getRoundedCornerBitmap is taken from a answer but that won't work.

CodePudding user response:

Can you try below code and refer official link for more details.

<com.google.android.material.imageview.ShapeableImageView
        android:id="@ id/ivNotificationIcon"
        android:layout_width="@dimen/_45sdp"
        android:layout_height="@dimen/_45sdp"
         android:backgroundTint="#EEF3F7"
        android:contentDescription="@string/image_description"
        android:scaleType="centerInside"   
 app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.CornerSize50Percent"
        app:srcCompat="@drawable/slider" />

and add this style in you style.xml/theme.xml

 <style name="ShapeAppearanceOverlay.App.CornerSize50Percent" parent="">
 <item name="cornerFamily">rounded</item>
        <item name="cornerSize">50%</item>
        <item name="backgroundTint">@android:color/white</item>        </style>

As per your requirement you will add items in the custom style.

CodePudding user response:

First of all, you are not drawing on the view's canvas, you've to override onDraw to draw anything on the view's canvas. And, as you just want to make your image circular from the corners, you don't need PorterDuff for this. You can just clip a rounded rect from the canvas and it would be suffice for your use case.

You don't have to manually override each constructor of the AppCompatImageView, You can use the @JvmOverloads annotation to override every constructor of the java class in kotlin.

Use withStyledAttributes extension function of core-ktx to access attributeSet

init block can be used to execute code just after the primary constructor.

Don't do object allocation inside of onDraw, reuse expensive objects like paint and path as much as possible.

Keeping above points in mind, your class can be changed like this

class RoundedImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet,
    defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
    val path = Path()
    var cornerRadius: Float = 0f

    init {
        context.withStyledAttributes(attrs, R.styleable.RoundedImageView) {
            cornerRadius = getDimension(R.styleable.RoundedImageView_cornerRadius, 0F)
        }
    }

    override fun onDraw(canvas: Canvas?) {
        val corners = floatArrayOf(
            cornerRadius,
            cornerRadius,
            cornerRadius,
            cornerRadius,
            cornerRadius,
            cornerRadius,
            cornerRadius,
            cornerRadius
        )

        path.addRoundRect(
            0f,
            0f,
            width.toFloat(),
            height.toFloat(),
            corners,
            Path.Direction.CW
        )

        canvas?.clipPath(path)
        super.onDraw(canvas)
    }
}

Now, it can be used like this

<com.sambhav2358.facebookclone.customviews.RoundedImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:cornerRadius="70dp"
        android:src="@drawable/ic_launcher_background"
        />
  • Related