Android View Clipping

JavaAndroidXmlAndroid LayoutClip

Java Problem Overview


Is there any way to define the clip region of a ViewGroup in android (Honeycomb)? For example, I have a ListView with an image background that has rounded corners. As I scroll through the list, the children stick out past the corners of the background - I would prefer them to clip within the rounded corners. Left: unclipped, Right: clipped

The left image is what it is currently doing, and the right is what I'd like.

I was looking at ClipDrawable, but it seems that this may only be used for progress bars?

Also, I'm trying to do this in a widget. So I cannot use a custom view and override onDraw for masking.

Thank you!

Java Solutions


Solution 1 - Java

Try subclassing ViewGroup and overriding the OnDraw method as follows, substituting in values for RADIUS_IN_PIXELS:

@Override
protected void onDraw(Canvas canvas) {
    Path clipPath = new Path();
    clipPath.addRoundRect(new RectF(canvas.getClipBounds()), RADIUS_IN_PIXELS, RADIUS_IN_PIXELS, Path.Direction.CW);
    canvas.clipPath(clipPath);
    super.onDraw(canvas);
}

...and also create a custom drawable like this called something like 'rounded', substituting in YOUR_BACKGROUND_COLOR and RADIUS_IN_DP, making sure to match the rounding of the rectangle in DP to your previous clipping radius in PX:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="RADIUS_IN_DP" />
    <solid android:color="YOUR_BACKGROUND_COLOR"/>
</shape>

Then you can use that subclass in your layout, adding the lines

android:background="@drawable/rounded"
android:clipChildren="true"

All children will clip to the bounds you specify in the OnDraw() override, and a background will be added based on your 'rounded' drawable.

Solution 2 - Java

Make sure layout has a background with rounded corners.

Kotlin

layout.outlineProvider = ViewOutlineProvider.BACKGROUND
layout.clipToOutline = true

Java

layout.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
layout.setClipToOutline(true);

Solution 3 - Java

Create custom layout with overridden onDraw(Canvas canvas)

call canvas.clipRect(0, 0, mCanvasWidth, mCanvasHeight);

this will clip all views that goes out of layout boundary.

And don't forget to call setWillNotDraw(false) in constructor, so your onDraw will execute

Solution 4 - Java

How about this: How to render an Android view to a bitmap, then clip that bitmap.

Or, another idea, use FrameLayout, stack your clip mask on top of your ViewGroup. Clip mask would have transparent middle, opaque borders.

In both cases, I guess it will be tricky to handle user input...

Solution 5 - Java

Path p = new Path()

// define your clipping path...

canvas.clipPath(p);

Solution 6 - Java

If you take a look to WhatsUp you can see that in the contact picture there is an image rounded by a rounded border. To do this I have put the ImageView inside a FrameLayout (FrameLayout because I use ProgressBar in front of picture to notify loading [actually invisible]) that has rounded border. The picture has a square shape but to refine it, you need to work with canvas.

Take another look at this link that will solve your problem ;)

Solution 7 - Java

May be you can used the Canvas.clipRegion method to clip the differences of the to views.

Solution 8 - Java

To add onto the answer by @Marco, you can also provide a custom View.outlineProvider. I ran into a similar issue using Google's newer MaterialCardView. For some reason, that view does not clip its children with the rounded corners. Child views would just draw on top of the rounded corner.

Kotlin:

val cornerRadius = 16.dp()
materialCardView.apply {
    clipToOutline = true
    outlineProvider = object : ViewOutlineProvider() {
        override fun getOutline(view: View?, outline: Outline?) {
            view?.apply {
                outline?.setRoundRect(0, 0, width, (height + cornerRadius).toInt(), cornerRadius)
            }
        }
    }
}

enter image description here

Solution 9 - Java

Give android:clipToPadding a try. It will solve your problem.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon RossView Question on Stackoverflow
Solution 1 - Javahead in the codesView Answer on Stackoverflow
Solution 2 - JavaMarcoView Answer on Stackoverflow
Solution 3 - JavakapilView Answer on Stackoverflow
Solution 4 - JavaPēteris CauneView Answer on Stackoverflow
Solution 5 - JavaBondaxView Answer on Stackoverflow
Solution 6 - JavaSimone CasagrandaView Answer on Stackoverflow
Solution 7 - Javablessanm86View Answer on Stackoverflow
Solution 8 - JavahellaandrewView Answer on Stackoverflow
Solution 9 - JavaHassan JawedView Answer on Stackoverflow