CardView with different corner radius
U

5

47

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.

Upstream answered 4/7, 2018 at 17:59 Comment(1)
In case if we just need to shape an image, use the material ShapeableImageView that draws the bitmap with the provided Shape.Radioactive
A
138

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

Argumentation answered 7/9, 2019 at 20:14 Comment(9)
Hi Gabriel, thanks for your answer. This example could be done without Android x?Upstream
@Upstream No, the new material components library requires androidxArgumentation
Thanks @Gabriele, I will try then.Upstream
It's not working. "shapeAppearanceOverlay" is in red colorVenezuela
@VarunRaj It requires 1.1.0 (as described in the answer). Currently 1.1.0-alpha10Argumentation
@GabrieleMariotti - if you could add the proper implementation ..... alpha.... that would save people like me couple of minutes :)Pacifier
@GabrieleMariotti, do you know a way to make the ImageView inside the MaterialCardView to respect the new rounded corners and fill the entire area ?Pacifier
@KrzysztofKubicki There are some solutions. For example you can use the ShapableImageView in the material components library. Check this answer.Argumentation
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()Snatch
M
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.

Mills answered 4/7, 2018 at 18:2 Comment(3)
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!Upstream
Yeah I noticed that it is a workaround. There appears to not be a nice way of doing this.Mills
it doesn't work for cardview, so this answer is no longer valid for this question.Timehonored
L
2

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>
Libation answered 17/10, 2022 at 7:33 Comment(0)
V
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.

Vortumnus answered 15/10, 2020 at 14:43 Comment(0)
L
-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);
Looselimbed answered 4/7, 2018 at 18:13 Comment(3)
This solution sets all corners of the CardView, I want to set only one, topLeft for example.Upstream
okay got your point directly with cardview you can not achieve easily so i will suggest you to use some third party libs. github.com/captain-miao/OptionRoundCardview check this oneLooselimbed
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!Upstream

© 2022 - 2024 — McMap. All rights reserved.