45

I have the following CardView and I want to set different radius for each corner in the card. Is it possible to change them by XML or programmaticaly? Thanks in advance.

<android.support.v7.widget.CardView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginRight="16dp"
    android:layout_marginLeft="16dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp"
    app:cardCornerRadius="0dp"
    app:cardElevation="0dp">
</android.support.v7.widget.CardView>

EDIT As Avinash suggest, I am looking for the behaviour of this lib github.com/captain-miao/OptionRoundCardview but using the default CardView item. If it is not possible to change it individually, this lib is a good approach.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Juanje
  • 1,235
  • 2
  • 11
  • 28
  • In case if we just need to shape an image, use the material [ShapeableImageView](https://stackoverflow.com/a/67851035/4694013) that draws the bitmap with the provided Shape. – Anoop M Maddasseri Jun 09 '21 at 04:35

5 Answers5

133

It requires the official MaterialCardView (which extends the androidx.cardview.widget.CardView) and at least the version 1.1.0 of the Material components library.

Add to your layout the MaterialCardView:

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

Define a custom style inheriting a material card style (for example Widget.MaterialComponents.CardView) and use the shapeAppearanceOverlay attribute:

  <style name="CustomCardViewStyle" parent="@style/Widget.MaterialComponents.CardView">
     <item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay_card_custom_corners</item>
  </style>


  <style name="ShapeAppearanceOverlay_card_custom_corners" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSizeTopRight">4dp</item>
    <item name="cornerSizeTopLeft">8dp</item>
    <item name="cornerSizeBottomRight">16dp</item>
    <item name="cornerSizeBottomLeft">0dp</item>
  </style>

enter image description here

You can also achieve it programmatically.
Just apply a custom ShapeAppearanceModel to the corners of the card.
Something like:

float radius = getResources().getDimension(R.dimen.my_corner_radius);
cardView.setShapeAppearanceModel(
  cardView.getShapeAppearanceModel()
      .toBuilder()
      .setTopLeftCorner(CornerFamily.ROUNDED,..)
      .setTopRightCorner(CornerFamily.ROUNDED,..)
      .setBottomRightCorner(CornerFamily.ROUNDED,radius)
      .setBottomLeftCornerSize(0)
      .build());

Note: it requires the version 1.1.0 of the library.


With Jetpack compose you can use the shape parameter in the Card.

Something like:

Card(
    shape = RoundedCornerShape(
        topStart = 4.dp,
        topEnd = 8.dp,
        bottomEnd = 16.dp,
        bottomStart = 2.dp,
    )
){
    Text("Content Card")
}

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 1
    Hi Gabriel, thanks for your answer. This example could be done without Android x? – Juanje Sep 09 '19 at 07:40
  • @Juanje No, the new material components library requires [androidx](https://github.com/material-components/material-components-android/blob/master/docs/getting-started.md#new-namespace-and-androidx) – Gabriele Mariotti Sep 09 '19 at 07:42
  • Thanks @Gabriele, I will try then. – Juanje Sep 09 '19 at 08:14
  • It's not working. "shapeAppearanceOverlay" is in red color – OhhhThatVarun Sep 12 '19 at 01:18
  • 1
    @VarunRaj It requires 1.1.0 (as described in the answer). Currently 1.1.0-alpha10 – Gabriele Mariotti Sep 12 '19 at 05:28
  • 1
    @GabrieleMariotti - if you could add the proper `implementation ..... alpha....` that would save people like me couple of minutes :) – Krzysztof Kubicki Nov 04 '19 at 12:38
  • @GabrieleMariotti, do you know a way to make the ImageView inside the MaterialCardView to respect the new rounded corners and fill the entire area ? – Krzysztof Kubicki Nov 04 '19 at 13:47
  • 1
    @KrzysztofKubicki There are some solutions. For example you can use the `ShapableImageView` in the material components library. [Check this answer](https://stackoverflow.com/questions/59248890/imageview-with-only-one-rounded-corner/59430153#59430153). – Gabriele Mariotti Dec 30 '19 at 16:15
  • Heads up, setShapeAppearanceModel w/ the builder didn't work for me when using unique corner sizes - they would always match one size. I had to create separate xml styles and set those at run time via ShapeAppearanceModel.builder( context, style, 0 ).build() – em_ Feb 02 '23 at 19:44
3

You can create a custom xml and name it rounded_corners.xml like this:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="1dp"
    android:topLeftRadius="20dp"
    android:topRightRadius="30dp"
    android:bottomLeftRadius="40dp"
    android:bottomRightRadius="50dp"/>
<solid android:color="your_background_color" />
</shape>

And then use this as the background for your CardView:

android:background="@drawable/rounded_corners"

EDIT: I just noticed that this may work for all other views other than CardView, so refer to this question for seeing how to do a workaround.

Vucko
  • 7,371
  • 2
  • 27
  • 45
  • You are right, this approach does not work for CardViews. I have already check the post you suggest but I think it is a dirty solution. I was loooking for something cleaner as modifying this attributes from code for example. Thanks anyway! – Juanje Jul 04 '18 at 18:43
  • Yeah I noticed that it is a workaround. There appears to not be a nice way of doing this. – Vucko Jul 07 '18 at 13:30
  • it doesn't work for cardview, so this answer is no longer valid for this question. – Amir Dora. Oct 26 '20 at 17:43
1

In case, if you use ImageView inside CardView, you should change ImageView into ShapeableImageView. Normal ImageView only works with all corners not each corner.

Here is more detail example on material.io docs

themes.xml

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

<style name="MyCardViewOverlay">
    <item name="cornerFamily">rounded</item>
    <!-- below items does not work with normal ImageView -->
    <item name="cornerSizeTopRight">0dp</item>
    <item name="cornerSizeTopLeft">60dp</item>
    <item name="cornerSizeBottomRight">0dp</item>
    <item name="cornerSizeBottomLeft">0dp</item>
</style>

layout.xml

<com.google.android.material.card.MaterialCardView
    style="@style/MyCardView"
    android:layout_width="200dp"
    android:layout_height="200dp"
    app:cardPreventCornerOverlap="false">

    <com.google.android.material.imageview.ShapeableImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@color/orange_600"
        app:shapeAppearanceOverlay="@style/MyCardViewOverlay" />
</com.google.android.material.card.MaterialCardView>
khcpietro
  • 1,459
  • 2
  • 23
  • 42
0

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.

Max
  • 183
  • 2
  • 8
-1

Hi you can add it programmatically or by xml with following code.

app:cardCornerRadius="0dp"// xml
cardView.setRadius(0);

this one is extra who is looking for elevation

app:cardElevation="0.7dp"//xml
app:cardMaxElevation="1dp"//xml
cardView.setCardElevation(2.1f);//code
cardView.setMaxCardElevation(3f);//code

The complete Java representation of the CardView’s XML.

CardView cardView = (CardView) findViewById(R.id.cardView);
cardView.setUseCompatPadding(true);
cardView.setContentPadding(30, 30, 30, 0);
cardView.setPreventCornerOverlap(true);
cardView.setCardBackgroundColor(Color.WHITE);
cardView.setCardElevation(2.1f);
cardView.setRadius(0);
cardView.setMaxCardElevation(3f);
Avinash Ajay Pandey
  • 1,497
  • 12
  • 19
  • 1
    This solution sets all corners of the CardView, I want to set only one, topLeft for example. – Juanje Jul 04 '18 at 18:38
  • 1
    okay got your point directly with cardview you can not achieve easily so i will suggest you to use some third party libs. https://github.com/captain-miao/OptionRoundCardview check this one – Avinash Ajay Pandey Jul 04 '18 at 18:45
  • Yes, you are right, I have already check this project. It is my next step if I don't get any solution with CardView. Thanks! Appreciate your help! – Juanje Jul 04 '18 at 18:49