Android View Clipping
JavaAndroidXmlAndroid LayoutClipJava 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.
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)
}
}
}
}
Solution 9 - Java
Give android:clipToPadding a try. It will solve your problem.