Android XML rounded clipped corners
Asked Answered
M

3

35

I've setup a LinearLayout with the following drawable background:

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

The problem I'm having is within the LinearLayout I have another LinearLayout element that sits at the bottom of it's parent. Since that doesn't have rounded corners its corners extend past the parents bottom left and right corners.

The drawable background on the Child LinearLayout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:src="@drawable/pedometer_stats_background" 
    android:tileMode="repeat"   
/>

The issue looks like this: http://kttns.org/hn2zm on the device the non-clipping is more apparent.

What is the best method to accomplish the clipping?

Merrie answered 1/12, 2010 at 19:19 Comment(1)
I'm guessing it will be solved with clever use of padding and marginsBeni
E
7

What your describing sounds like this:

<LinearLayout android:shape="rounded">
   <LinearLayout android:background="@drawable/pedometer_stats_background">
   </LinearLayout>
</LinearLayout>

And the inner layout is pushing outside the rounded corners because it isn't rounded. You'll have to round the corners of your bitmap. If you have a repeating bitmap you'll want to look at defining a nine-patch drawable. Round your corners then define the portion of the graphic that can expand.

http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape

It'd be nice if we could just add a bitmap to the shape drawable and have that be applied as a skin over whatever shape we're drawing. And, I bet if you know what your doing you could create a Shape subclass that draws a bitmap, but that's not included in Android out of the box unfortunately.

Extension answered 1/12, 2010 at 20:17 Comment(2)
Thanks for this, I was trying to get away without custom shaping the bitmaps. Can't believe you can't stop children from bleeding out.Experimentalism
Well you can stop them, but it's not there out of the box. With a little code and ingenuity you can create something that does that.Extension
R
44

2018 Update

A lot has changed in the last 7 years.

The best way to handle this type of layout these days is to use CardView which has built in support for rounded corners and many other newer UI features as well.

Apply the cardCornerRadius property to set the corners to round.

<android.support.v7.widget.CardView
    .......
    app:cardCornerRadius="16dp">

</android.support.v7.widget.CardView>

Original

I needed iPhone-style rounded layouts, with a grey background behind them. (sigh - always copying the iPhone)

I was frustrated I couldn't find a way to mask a layout. Most of the answers here say to use a background image, but this is not what I needed.


Edit: Previous answer suggested using a FrameLayout and setting the android:foreground drawable. This introduced some strange padding into the view. I have updated my answer to use simpler RelativeLayout technique.


The trick is to use a RelativeLayout; place your layout inside it. Below your layout, add another ImageView, setting its background to a suitable masking image frame. This will draw that on top of your other layout.

In my case, I made a 9Patch file which was a grey background, with a transparent rounded rectangle cut out of it.

frame

This creates the perfect mask for your underlying layout.

XML code is below - this is a normal layout XML file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content" android:layout_width="fill_parent">

    <!-- this can be any layout that you want to mask -->
    <LinearLayout android:id="@+id/mainLayout"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:orientation="vertical"
        android:background="@android:color/white">

        <TextView android:layout_height="wrap_content"
            android:layout_width="wrap_content" android:layout_gravity="center"
            android:text="Random text..." />

    </LinearLayout>

    <!-- FRAME TO MASK UNDERLYING VIEW -->
    <ImageView android:layout_height="fill_parent" 
        android:layout_width="fill_parent" 
        android:background="@drawable/grey_frame"
        android:layout_alignTop="@+id/mainLayout"
        android:layout_alignBottom="@+id/mainLayout" />

</RelativeLayout>

Note the ImageView at the bottom, aligned top & bottom to the main layout, with the masking image set:

  • android:background="@drawable/grey_frame"

This references my 9Patch file - and masks the underlying layout by being drawn in the foreground.

Here is an example showing the grey rounded corners over a standard layout.

maskedLayout

hth

Revulsive answered 29/11, 2011 at 15:10 Comment(10)
I've tried several approaches for rounded corners on ListViews and this one is definitely the most reliable. Works like a charm. Thank you!Zug
This is definitely the best way. Also it allows your designers to go crazy and add drop shadows/glow to the rounded corners and you don't have to do some crazy <shape> drawing or anything.Sura
I had fun with "always copying from iPhone." So true! :(Maneater
I use a similar trick but instead of drawing a 9-patch I draw 2 shapes around the image: 1 with rounded corners and 1 without. Requires an extra pass of course, but only pixels that actually need to be drawn. Plus I don't have to worry about aliasing issues or multiple bitmaps for different devices.Arboretum
This does not work if you need transparent backgroundSchram
Ek sal dit bietjie probeer dankieMonoplegia
@Monoplegia hierdie antwoord is amper sewe jaar oud, en daar is deesdae beter metode om te gebruik. / This answer is 7 years old and there are better methods. I would always suggest these days to use CardView instead.Revulsive
@RichardLeMesurier I actually want to use it for a standard ListView with nice rounded cornersMonoplegia
@Monoplegia I would just put the ListView inside a CardView these days. Best luck whichever route you take.Revulsive
Absolutely massive thanks for the CardView update to your original post @RichardLeMesurier - it saved me a lot of pain and anguish in trying to get rounded corners added to my Mapbox views and some MediaPlayer/SurfaceViews too!Marcellemarcellina
M
15

API level 21 (Lollipop) added View.setClipToOutline. From Android documentation on Defining Shadows and Clipping Views:

To clip a view to the shape of a drawable, set the drawable as the background of the view ... and call the View.setClipToOutline() method.

I tested this by setting a parent View's background to a GradientDrawable with a corner radius, and child Views are correctly cropped to match the same rounded corners of the parent.

Mufi answered 15/8, 2017 at 21:50 Comment(2)
API level 21 is Lollipop, not JellybeanTuberculosis
I didn't want to use CardView and View.setClipToOutline worked for me. You have to set it to the parent view.Padilla
E
7

What your describing sounds like this:

<LinearLayout android:shape="rounded">
   <LinearLayout android:background="@drawable/pedometer_stats_background">
   </LinearLayout>
</LinearLayout>

And the inner layout is pushing outside the rounded corners because it isn't rounded. You'll have to round the corners of your bitmap. If you have a repeating bitmap you'll want to look at defining a nine-patch drawable. Round your corners then define the portion of the graphic that can expand.

http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape

It'd be nice if we could just add a bitmap to the shape drawable and have that be applied as a skin over whatever shape we're drawing. And, I bet if you know what your doing you could create a Shape subclass that draws a bitmap, but that's not included in Android out of the box unfortunately.

Extension answered 1/12, 2010 at 20:17 Comment(2)
Thanks for this, I was trying to get away without custom shaping the bitmaps. Can't believe you can't stop children from bleeding out.Experimentalism
Well you can stop them, but it's not there out of the box. With a little code and ingenuity you can create something that does that.Extension

© 2022 - 2024 — McMap. All rights reserved.