106
votes

Is there a way to make CardView only have corner radius at the top?

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="10dp"
    >
14
In case if we just need to shape an image, use the material ShapeableImageView that draws the bitmap with the provided Shape.Anoop M Maddasseri

14 Answers

126
votes

Unless you try to extend the Android CardView class, you cannot customize that attribute from XML.

Nonetheless, there is a way of obtaining that effect.

Place a CardView inside another CardView and apply a transparent background to your outer CardView and remove its corner radius ("cornerRadios = 0dp"). Your inner CardView will have a cornerRadius value of 3dp, for example. Then apply a marginTop to your inner CardView, so its bottom bounds will be cut by the outer CardView. This way, the bottom corner radius of your inner CardView will be hidden.

The XML code is the following:

 <android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_outer"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_gravity="center"
    card_view:cardBackgroundColor="@android:color/transparent"
    card_view:cardCornerRadius="0dp"
    card_view:cardElevation="3dp" >

    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view_inner"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:layout_marginTop="3dp"
        card_view:cardBackgroundColor="@color/green"
        card_view:cardCornerRadius="4dp"
        card_view:cardElevation="0dp" >
    </android.support.v7.widget.CardView>
</android.support.v7.widget.CardView>

And the visual effect is the following:

CardView with rounded corners only on top

Always put your content in your Inner CardView. Your outer CardView serves only the purpose of "hiding" the bottom Rounded Corners of the inner CardView.

43
votes
dependencies: compile 'com.android.support:cardview-v7:23.1.1'

<android.support.v7.widget.CardView
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:elevation="12dp"
    android:id="@+id/view2"
    app:cardCornerRadius="40dp"
    android:layout_centerHorizontal="true"
    android:innerRadius="0dp"
    android:shape="ring"
    android:thicknessRatio="1.9">
    <ImageView
        android:layout_height="80dp"
        android:layout_width="match_parent"
        android:id="@+id/imageView1"
        android:src="@drawable/Your_image"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true">
    </ImageView>
</android.support.v7.widget.CardView>
42
votes

You can use the standard MaterialCard included in the official Material Components library.

Use in your layout:

<com.google.android.material.card.MaterialCardView
        style="@style/MyCardView"
        ...>

In your style use the shapeAppearanceOverlay attribute to customize the shape (the default corner radius is 4dp)

  <style name="MyCardView" parent="@style/Widget.MaterialComponents.CardView">
    <item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay.MaterialCardView.Cut</item>
  </style>


  <style name="ShapeAppearanceOverlay.MaterialCardView.Cut" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSizeTopRight">8dp</item>
    <item name="cornerSizeTopLeft">8dp</item>
    <item name="cornerSizeBottomRight">0dp</item>
    <item name="cornerSizeBottomLeft">0dp</item>
  </style>

You can also use:

<com.google.android.material.card.MaterialCardView
     app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.MaterialCardView.Cut"
     ...>

It is the result:

enter image description here

11
votes

There is an example how to achieve it, when the card is at the very bottom of the screen. If someone has this kind of problem just do something like that:

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="-5dp"
    card_view:cardCornerRadius="4dp">

    <SomeView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp">

    </SomeView>

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

Card View has a negative bottom margin. The view inside a Card View has the same, but positive bottom margin. This way rounded parts are hidden below the screen, but everything looks exactly the same, because the inner view has a counter margin.

7
votes

You can use this drawable xml and set as background to cardview :

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffffff"/>

    <stroke android:width="1dp"
        android:color="#ff000000"
        />

    <padding android:left="1dp"
        android:top="1dp"
        android:right="1dp"
        android:bottom="1dp"
        />

    <corners 
        android:topLeftRadius="7dp"
        android:topRightRadius="7dp"/>
</shape>
6
votes

I wrote a drawable lib to custom round corner position, it looks like this:

example.png

You can get this lib at here:

https://github.com/mthli/Slice

2
votes

You need to do 2 things :

1) Call setPreventCornerOverlap(false) on your CardView.

2) Put rounded Imageview inside CardView

About rounding your imageview, I had the same problem so I made a library that you can set different radii on each corner. Finally I got the result what I wanted like below.

https://github.com/pungrue26/SelectableRoundedImageView

Rounded ImageView inside CardView

1
votes

NOTE: This here is a workaround if you want to achieve rounded corners at the bottom only and regular corners at the top. This will not work if you want to have different radius for all four corners of the cardview. You will have to use material cardview for it or use some third party library.

Here's what seemed to work for me:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#F9F9F9">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@drawable/profile_bg"/>

    </androidx.cardview.widget.CardView>

    <androidx.cardview.widget.CardView
        android:id="@+id/cvProfileHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="32dp">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="280dp"
            android:orientation="vertical"
            android:background="@drawable/profile_bg"
            android:id="@+id/llProfileHeader"
            android:gravity="center_horizontal">

            <!--Enter your code here-->

        </LinearLayout>
    
    </androidx.cardview.widget.CardView>

</RelativeLayout>

There's two cardview's in all. The second cardview is the one that will have rounded corners (on all sides as usual) and will hold all other subviews under it. The first cardview above it is also at the same level (of elevation), and has the same background but is only about half the height of the second cardview and has no rounded corners (just the usual sharp corners). This way I was able to achieve partially rounded corners on the bottom and normal corners on the top. But for all four sides, you may have to use the material cardview.

You could do the reverse of this to get rounded corners at the top and regular ones at the bottom, i.e. let the first cardview have rounded corners and the second cardview have regular corners.

0
votes
0
votes

You can put your ImageView inside a CardView, and add those properties to the ImageView:

android:cropToPadding="true"
android:paddingBottom="15dp"

That way you will get rid of the rounded bottom corner, but keep in mind that this comes in the price of having a small portion of your image cut off.

0
votes

My custom way to implemented with a lib

//Rounded card

add this implementation on build.gradle

implementation 'com.github.captain-miao:optroundcardview:1.0.0'

in XML:

<com.github.captain_miao.optroundcardview.OptRoundCardView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="10dp"
    app:optRoundCardCornerRadius="40dp"
    app:optRoundCardLeftBottomCorner="false"
    app:optRoundCardRightBottomCorner="false"
    app:optRoundCardBackgroundColor="#E2EAF8">
-1
votes

Easiest way to achieve it in Android Studio is explained below:

Step 1:
Write below line in dependencies in build.gradle:

compile 'com.android.support:cardview-v7:+'

Step 2:
Copy below code in your xml file for integrating the CardView.

For cardCornerRadius to work, please be sure to include below line in parent layout: xmlns:card_view="http://schemas.android.com/apk/res-auto"

And remember to use card_view as namespace for using cardCornerRadius property.

For example : card_view:cardCornerRadius="4dp"

XML Code:

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view_outer"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_gravity="center"
    card_view:cardBackgroundColor="@android:color/transparent"
    card_view:cardCornerRadius="0dp"
    card_view:cardElevation="3dp" >

    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view_inner"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:layout_marginTop="3dp"
        card_view:cardBackgroundColor="@color/green"
        card_view:cardCornerRadius="4dp"
        card_view:cardElevation="0dp" >
    </android.support.v7.widget.CardView>

</android.support.v7.widget.CardView>
-1
votes

An easy way to achieve this would be:

1.Make a custom background resource (like a rectangle shape) with rounded corners.

2.set this custom background using the command -

cardView = view.findViewById(R.id.card_view2);
cardView.setBackgroundResource(R.drawable.card_view_bg);

this worked for me.

The XML layout I made with top left and bottom right radius.

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:topLeftRadius="18dp" android:bottomRightRadius="18dp" />
</shape>

In your case, you need to change only topLeftRadius as well as topRightRadius.

If you have a layout that overlaps with the corners of the card view and has a different color maybe, then you might need a different background resource file for the layout and in the xml set this background resource to your layout.

I tried and tested the above method. Hope this helps you.

-3
votes

If you're setting the card background programmatically, make use you use cardView.setCardBackgroundColor() and not cardView.setBackgroundColor() and make sure use using app:cardPreventCornerOverlap="true" on the cardView.xml. That fixed it for me.

Btw, the above code (in quotations) is in Kotlin and not Java. Use the java equivalent if you're using Java.