Home > database >  clipToOutline with cornerRadii with background
clipToOutline with cornerRadii with background

Time:05-24

Sometimes in my practice I want to round view's background corners. Usually i use something like this (@drawable/bg_rounded)

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="16dp"/>
</shape>

But sometimes i need to round only one angle and do this programmatically

I create a test project to show the problem. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@ id/container"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="20dp"
    android:background="@drawable/bg_rounded">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/purple_200"/>

</FrameLayout>

MainActivity class may be like

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val container = findViewById<FrameLayout>(R.id.container)
        container.clipToOutline = true
        val background: GradientDrawable =
            container.background.mutate() as? GradientDrawable ?: return
        background.cornerRadii = floatArrayOf(
            20F, 20F, 20F, 20F,
            20F, 20F, 20F, 20F
        )
    }
}

but unexpected behavior happens - corners are not rounded click to see picture

if i use background.cornerRadius it works predictable

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val container = findViewById<FrameLayout>(R.id.container)
        container.clipToOutline = true
        val background: GradientDrawable =
            container.background.mutate() as? GradientDrawable ?: return
        background.cornerRadius = 20F
//        background.cornerRadii = floatArrayOf(
//            20F, 20F, 20F, 20F,
//            20F, 20F, 20F, 20F
//        )
    }
}

click to see picture

So my question is: what should I use to achieve dynamic adjustment of different radius of corners

CodePudding user response:

if i use background.cornerRadius it works predictable

It is because clipping only supports rectangle, circle, or round rect.

When you use background.cornerRadius it uses RoundRect to draw, but when you use background.cornerRadii it uses Path to draw, and path clipping is not supported until API 33. Check outline documentation.

You cannot use variable corners radius, but you can do a workaround to keep rounded corners at desired positions by using ViewOutlineProvider and RoundRect to draw the outline. You can read more detailed answers about it here.

  • Related