Round only top corner of cardview
AndroidAndroid LayoutAndroid CardviewAndroid Problem Overview
I want to corner only the top of a cardview.
I used below property and it is rounding all the corner.
I want to show an overlap of all cards
card_view:cardCornerRadius="4dp"
here is my layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
card_view:cardCornerRadius="4dp"
card_view:cardPreventCornerOverlap="false"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/re1">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@color/colorAccent"
android:text="contact det"
android:gravity="center_vertical"
android:textColor="@android:color/white"
android:textSize="14dp"/>
<TextView
android:id="@+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:gravity="center_vertical"
android:textSize="10dp"
android:layout_below="@id/title"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"/>
<TextView
android:id="@+id/txtSurname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Surname"
android:gravity="center_vertical"
android:textSize="10dp"
android:layout_below="@id/txtName"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
/>
<TextView
android:id="@+id/txtEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textSize="10dp"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_marginRight="150dp"
android:layout_alignBaseline="@id/txtName"/>
<TextView
android:id="@+id/txtAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Address"
android:textSize="10dp"
android:layout_alignLeft="@id/txtEmail"
android:layout_alignBaseline="@id/txtSurname"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
Android Solutions
Solution 1 - Android
We can set the marginBottom of the card view in negative value.Margin should be same value as card radius. For Example,
<FrameLayout
android:id="@+id/rootview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_marginBottom="-3dp"
project:cardCornerRadius="3dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--The child view inside the cardview should have extra padding,so that negative margin will not affect the bottom padding of its child.Here normally we have 16dp bottom padding for child + margin bottom of the parent is 3dp=19dp comes.-->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="19dp"/>
</android.support.v7.widget.CardView>
</FrameLayout>
It works for me.But I am in doubt whether it is the proper way of doing.Any suggestions are welcome.
Solution 2 - Android
I have been trying the same but none of the solutions provided worked for me.
The only thing that worked was:
-
Make a custom background resource (like a rectangle shape) with rounded corners.
-
set this custom background using the command -
cardView = view.findViewById(R.id.card_view2); cardView.setBackgroundResource(R.drawable.card_view_bg);
Worked perfectly for me! Hope this helps you.
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.
Solution 3 - Android
Tricky thing because you can't make CardView do this. Internally it uses a RoundRectDrawable
(package private) which uses roundRect
like this:
// rectf, rx, ry, paint
canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);
Therefore you need a different solution, for example I found this gist by Ahmed-Abdelmeged where they use canvas clipping per each corner using a path to describe the outline.
So while I'm not the one who made this code, I'll post it here for future travellers.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundedView">
<attr name="topLeftCornerRadius" format="dimension" />
<attr name="topRightCornerRadius" format="dimension" />
<attr name="bottomLeftCornerRadius" format="dimension" />
<attr name="bottomRightCornerRadius" format="dimension" />
</declare-styleable>
</resources>
and
package com.abdelmeged.ahmed.roundedlayout;
/**
* Created by ahmed on 9/17/2017.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
/**
* Custom wrapper view to get round corner round view
*/
public class RoundedView extends FrameLayout {
/**
* The corners than can be changed
*/
private float topLeftCornerRadius;
private float topRightCornerRadius;
private float bottomLeftCornerRadius;
private float bottomRightCornerRadius;
public RoundedView(@NonNull Context context) {
super(context);
init(context, null, 0);
}
public RoundedView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.RoundedView, 0, 0);
//get the default value form the attrs
topLeftCornerRadius = typedArray.getDimension(R.styleable.
RoundedView_topLeftCornerRadius, 0);
topRightCornerRadius = typedArray.getDimension(R.styleable.
RoundedView_topRightCornerRadius, 0);
bottomLeftCornerRadius = typedArray.getDimension(R.styleable.
RoundedView_bottomLeftCornerRadius, 0);
bottomRightCornerRadius = typedArray.getDimension(R.styleable.
RoundedView_bottomRightCornerRadius, 0);
typedArray.recycle();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
@Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
final Path path = new Path();
float[] cornerDimensions = {
topLeftCornerRadius, topLeftCornerRadius,
topRightCornerRadius, topRightCornerRadius,
bottomRightCornerRadius, bottomRightCornerRadius,
bottomLeftCornerRadius, bottomLeftCornerRadius};
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight())
, cornerDimensions, Path.Direction.CW);
canvas.clipPath(path);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
public void setTopLeftCornerRadius(float topLeftCornerRadius) {
this.topLeftCornerRadius = topLeftCornerRadius;
invalidate();
}
public void setTopRightCornerRadius(float topRightCornerRadius) {
this.topRightCornerRadius = topRightCornerRadius;
invalidate();
}
public void setBottomLeftCornerRadius(float bottomLeftCornerRadius) {
this.bottomLeftCornerRadius = bottomLeftCornerRadius;
invalidate();
}
public void setBottomRightCornerRadius(float bottomRightCornerRadius) {
this.bottomRightCornerRadius = bottomRightCornerRadius;
invalidate();
}
}
This will let you clip the edge of images and views before they get rendered, therefore it does exactly what you want.
Solution 4 - Android
Or, you can use MaterialCardView
<com.google.android.material.card.MaterialCardView
style="@style/CustomCardViewStyle"
...>
</com.google.android.material.card.MaterialCardView>
<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>
You cand find a good answer here
Solution 5 - Android
In case if you just want to shape an image, use material ShapeableImageView
that draws the bitmap with the provided Shape.
<!-- Media -->
<com.google.android.material.imageview.ShapeableImageView
...
app:shapeAppearance="?attr/shapeAppearanceMediumComponent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Card.Media" />
In res/values/styles.xml
:
<style name="ShapeAppearanceOverlay.App.Card.Media" parent="">
<item name="cornerSizeBottomLeft">0dp</item>
<item name="cornerSizeBottomRight">0dp</item>
<item name="cornerSizeTopLeft">8dp</item>
<item name="cornerSizeTopRight">8dp</item>
</style>
Solution 6 - Android
Well, I am so desperate finding a way to achieve this, one it's not possible, and creating your own shadow is somewhat I don't like the result and I lucky in my case I need it in the corner of the screen top right to be exact.
let's make it simple, make oversized card view into another view in my case I use frame layout then change it's x and y translation to what you need, well what I do is, make translation x and y into same exact card radius corner value. and there you go one sided rounded card view with barbaric way.
code ? sample ? here you go
<FrameLayout
android:id="@+id/miniTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/frameLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:translationX="10dp"
android:translationY="-10dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/drwable_red__rounded_botleft_10"
android:gravity="center"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingLeft="5dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:paddingRight="10dp"
android:paddingBottom="5dp">
<TextView
android:id="@+id/miniTimerText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="12dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
note : oh I dynamically generate the textview text so add it yourself :)
Solution 7 - Android
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">
Solution 8 - Android
You can simply add an empty view to the bottom of your card view , set its background color the same as the cardView and also give a small negative margin to the top of the empty view, here is a sample :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/linBottomSheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="-8dp"
android:elevation="2dp"
app:cardBackgroundColor="@color/colorAccent"
app:cardCornerRadius="10dp">
</androidx.cardview.widget.CardView>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_marginTop="-10dp"
android:background="@color/colorAccent" />
</LinearLayout>
Solution 9 - Android
I only created card view to wrap around image for corner radius then used constraint layout to add guidline and add below text layout to guidline. then guidline have overlapped on card with margin.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/card_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/_10sdp"
android:layout_marginRight="@dimen/_10sdp"
android:layout_marginTop="@dimen/_9sdp"
android:elevation="@dimen/_2sdp"
android:background="@drawable/card_top_corners"
android:clipChildren="true"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="@dimen/_152sdp"
app:cardCornerRadius="@dimen/_10sdp"
app:cardPreventCornerOverlap="false"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="@dimen/_142sdp"
android:scaleType="centerCrop"
android:src="@drawable/shahruk"
android:visibility="visible" />
</androidx.cardview.widget.CardView>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline14"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="@dimen/_142sdp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline14">
<TextView
android:id="@+id/txt_title"
style="@style/medium_14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:paddingLeft="@dimen/_8sdp"
android:paddingTop="@dimen/_8sdp"
android:paddingRight="@dimen/_8sdp"
android:text="Rupa Singh: First indian woman to become a Jockey."
android:textColor="@color/city_news_text" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/_8sdp"
android:layout_marginRight="@dimen/_8sdp"
android:orientation="horizontal">
<TextView
android:id="@+id/txt_date"
style="@style/medium_9sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxWidth="@dimen/_120sdp"
android:maxLines="1"
android:paddingTop="2dp"
android:text="Today"
android:textColor="@color/header_new"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/view2"
android:layout_width="1dp"
android:layout_height="@dimen/_8sdp"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/_7sdp"
android:layout_marginRight="@dimen/_7sdp"
android:background="@color/header_new"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/txt_date"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txt_special_tag"
style="@style/medium_9sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="start|center_vertical"
android:maxLines="1"
android:paddingTop="2dp"
android:text="Top News"
android:textColor="@color/header_new"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/view2"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<TextView
style="@style/regular_11sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_5sdp"
android:paddingLeft="@dimen/_8sdp"
android:paddingTop="@dimen/_2sdp"
android:paddingRight="@dimen/_8sdp"
android:paddingBottom="@dimen/_8sdp"
android:text="Napur records highest temperature in summers this year with measure of 225 degree celsius....[Read more]"
android:textColor="@color/scheme_subtext" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Solution 10 - Android
Simply scrolling the CardView on the Y-axis did the trick for me. Note the scrollY attribute on the CardView
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="0dp"
app:cardCornerRadius="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:scrollY="10dp"
>
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:scaleType="fitXY"
android:src="@drawable/sample_post_image"
/>
</androidx.cardview.widget.CardView>
I tried this answer but the cut-out radius has some dark background, which is not desirable.
Solution 11 - Android
Use this library https://github.com/captain-miao/OptionRoundCardview
Instead of using CardView
, use OptRoundCardView
Solution 12 - Android
It's better to update your CardView form:
androidx.cardview.widget.CardView
to new one:
com.google.android.material.card.MaterialCardView
like this:
<com.google.android.material.card.MaterialCardView
android:id="@+id/bottomCard"
android:layout_width="70dp"
android:layout_height="70dp">
then in Kotlin use like this:
var shapeAppearanceModel: ShapeAppearanceModel.Builder =ShapeAppearanceModel().toBuilder()
shapeAppearanceModel.setBottomRightCorner(
CornerFamily.ROUNDED,
CornerSize { return@CornerSize 45F })
binding.bottomCard.shapeAppearanceModel =shapeAppearanceModel.build()
instead of binding
you can put
bottomCard=view.findViewById<MaterialCardView>(R.id.bottomCard)
Solution 13 - Android
As per the question, I am assuming that you want to apply corner radius property to only top of the card. You can obtain this effect by using two CardView
. Place one CardView
inside another CardView
and remove outer CardView
corner radius property. Also apply a transparent background to your outer CardView
Your inner CardView will have a cornerRadius value of 4dp. Then apply a marginTop to your inner CardView
, so that its bottom part becomes hidden by the outer CardView
. This way, the bottom corner radius of your inner CardView
will be hidden.
You will have to put your xml content in your Inner CardView
. Outer CardView
serves only the purpose of hiding the bottom rounded corners of the inner CardView
.
Your xml layout will look like this:
<?xml version="1.0" encoding="utf-8"?>
<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="match_parent"
android:layout_gravity="center"
card_view:cardBackgroundColor="@android:color/transparent"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="4dp" >
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
card_view:cardElevation="0dp"
card_view:cardCornerRadius="4dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/re1">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@color/colorAccent"
android:text="contact det"
android:gravity="center_vertical"
android:textColor="@android:color/white"
android:textSize="14dp"/>
<TextView
android:id="@+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:gravity="center_vertical"
android:textSize="10dp"
android:layout_below="@id/title"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"/>
<TextView
android:id="@+id/txtSurname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Surname"
android:gravity="center_vertical"
android:textSize="10dp"
android:layout_below="@id/txtName"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
/>
<TextView
android:id="@+id/txtEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textSize="10dp"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_marginRight="150dp"
android:layout_alignBaseline="@id/txtName"/>
<TextView
android:id="@+id/txtAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Address"
android:textSize="10dp"
android:layout_alignLeft="@id/txtEmail"
android:layout_alignBaseline="@id/txtSurname"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
</android.support.v7.widget.CardView>
I have taken reference from this SO question: Question. I hope it solves your problem.