Tobii
Tobii

Reputation: 1

How to clip drawables with xml files?

I'm trying to create an overlay for the corners in my app. I want them to be rounded and black all the time like this:

Attached Image

I created it with this code:

<?xml version="1.0" encoding="utf-8"?>

<item>
    <shape android:shape="rectangle">
        <solid android:color="#000"/>
    </shape>
</item>

<item>
    <shape android:shape="rectangle">
        <solid android:color="#FFF"/>
        <corners android:radius="24dp"/>
    </shape>
</item>

Then I added it to my theme as an android:windowFrame:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowFrame">@drawable/corner_overlay</item>
</style>

But obviosly everything was white then. Now I'm trying to clip the second shape instead of coloring it white and if that doesnt work I'm looking for another way to get my corner overlay working!

Thanks for every help!

Upvotes: 0

Views: 2580

Answers (2)

Adrian Grygutis
Adrian Grygutis

Reputation: 479

From Android SDK 31 clipToOutline attribute is available. There is also outlineProvider attribute which helps describe outline source.

android:clipToOutline="true"
android:outlineProvider="background"

Jetpack Compose has Modifier.clip.

Upvotes: 0

dantes_21
dantes_21

Reputation: 427

You can create a Custom Frame Layout and wrap all your content with it.

class RoundedCornerLayout : FrameLayout {

private var paint: Paint? = null
private var paint2: Paint? = null
private var cornerRadius: Float = 10f

private var mWidth: Int = 0
private var mHeight: Int = 0

constructor(context: Context) : super(context) {
    init(context, null, 0)
}

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

constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
    init(context, attrs, defStyle)
}

private fun init(context: Context, attrs: AttributeSet?, defStyle: Int) {
    val metrics = context.getResources().getDisplayMetrics()
    cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics)

    paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint?.color = Color.BLACK

    paint2 = Paint(Paint.ANTI_ALIAS_FLAG)
    paint2?.color = Color.TRANSPARENT
    paint2?.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

    setWillNotDraw(false)
    setLayerType(LAYER_TYPE_SOFTWARE, null)
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)
    mWidth = w
    mHeight = h
}

override fun onDraw(canvas: Canvas?) {
    canvas?.drawRect(0f, 0f, mWidth.toFloat(), mHeight.toFloat(), paint)
    canvas?.drawRoundRect(RectF(0f, 0f, mWidth.toFloat(), mHeight.toFloat()), cornerRadius, cornerRadius, paint2)
}

companion object {
    private val CORNER_RADIUS = 40.0f
}
}

And use it in your xml:

<com.dantes.backstack.RoundedCornerLayout
            android:id="@+id/wrapper"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

      <!-- Your content here-->

</com.dantes.backstack.RoundedCornerLayout>

Of course this is draft and you need to optimize it and make more clear to your purposes. But principal part is PorterDuffXfermode(PorterDuff.Mode.CLEAR). This mode make magic and cuts the tarnsparent rectangle from the dark.

Maybe it will help or at least push your minds in right direction.

Upvotes: 0

Related Questions