I have a CardView within a ConstraintLayout.
This view is then inflated and added to a LinearLayout.
I would like the CardView to cast a shadow on the next CardView, but it seems to be clipped by the ConstraintLayout. How can I get the elevation shadow to show on the CardView without providing more padding or margins for it?
i.e. How can I cast the shadow on an adjacent item?
<LinearLayout>
<ConstraintLayout>
<CardView> <-- This view's shadow is cut
...
</CardView>
</ConstraintLayout>
<ConstraintLayout>
<CardView>
...
</CardView>
</ConstraintLayout>
<LinearLayout>
Try adding this comment inside your card view that's enough
card_view:cardUseCompatPadding="true"
How can I get the elevation shadow to show on the CardView without providing more padding or margins for it?
i.e. How can I cast the shadow on an adjacent item?
You can't, for both a practical reason and a conceptual one.
The practical reason comes down to how the Android framework draws CardView shadows. On older API levels, the card is inset within its own bounds and that extra space is used to draw the shadow. So even if you had two cards immediately next to each other, they'd still have "space" between them due to these insets. From the documentation:
Before Lollipop, CardView adds padding to its content and draws shadows to that area.
On Lollipop and higher, shadows are drawn within the parent's bounds, not within the CardView's bounds. Still, the parent will clip the shadow if there isn't enough space between the card's edges and the parent's edges to draw the whole shadow. In your example, each CardView is in a separate parent, so even if you put those parents immediately next to each other, each parent would still clip its card's shadow.
As for the conceptual reason, that's just not how shadows work (in nature). If you have two cards at the same elevation, even if they're right next to each other, the top card wouldn't cast a shadow on the bottom card.
Try to add
app:cardElevation="10dp"
In order to use app:cardElevation you have to add to your LinearLayout:
xmlns:app="http://schemas.android.com/apk/res-auto"
I tried this in a test project and the elevation should work this way. Below is my code:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="ro.helpproject.funcode.help.MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="50dp"
app:cardElevation="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEST TEST" />
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="50dp"
app:cardElevation="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEST TEST" />
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
CardView needs padding around it for shadow to appear.
If app:cardUseCompatPadding="true" adds the shadow for you but you don't want the extra padding from 4 directions (LRTB), you need to add margin to the CardView yourself.
Enable Developer options -> Show layout boundaries and if you see that there is no empty space around your CardView. Then that's probably the reason shadow not appearing.
Related
[![my image][1]][1]
As. you can see from the image i have a rounded corner shape ..but i want to have a shadow just on the top (there is no where else for it anyway since its covered on the other ends). How can i place a shadow just at the top of this cardView ? here is what i have so far and i've tried using two framelayouts earlier.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/viewRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:theme="#style/Theme.MaterialComponents.Light"
android:id="#+id/greenCardView"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:clipToOutline="true"
android:clipToPadding="true"
android:clipChildren="true"
app:cardPreventCornerOverlap="true"
app:cardBackgroundColor="#color/green">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/contentContainer"
android:layout_width="match_parent"
android:background="#color/transparent"
android:layout_height="54dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
i also need the shadow to have no background under it ..so it should not be on a white background, i just want the shadow on top alone on a transparent background.
update: after i udated to 70dp elevation the shadow is only appearing on the bottom :
[![enter image description here][2]][2]
notice the shadow is only appearing at the bottom . how can i make shadow just at the top
[1]: https://i.stack.imgur.com/8XC6l.png
[2]: https://i.stack.imgur.com/egRoB.png
Increse the value of
app:cardElevation="0dp"
it was how i was attaching the scrollview to the cardview ..i used a space view to attach it a bit lower and it works great now (since i dont have access to negative margins) ..thanks
what i learned is that when you have a scrollview attached to a cardview then you should attach the scrollview a few pixels away from the top so that it does not look cut off when it scrolls.
I stumbled upon something weird. I am using the same CardView component in more than one place in my app, all with the same elevation (3dp), and they all looks the same. However, for one scenario I need to embed the CardView inside a ScrollView. I didn't change anything in the CardView configuration, but the shadow now looks different.
This is my layout:
<ScrollView 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="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="16dp"
android:scrollbars="none">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
app:cardCornerRadius="8dp"
app:cardElevation="3dp"
app:cardUseCompatPadding="true">
<!-- some other views-->
</androidx.cardview.widget.CardView>
</ScrollView>
In the picture below you can see on the right the CardView and on the left the two shadows: on the top the shadow generated by the CardView alone, on the bottom the one generated when the CardView is inside a ScrollView. As you can see the second one appears darker and thicker.
NOTE: The background color (#FAFAFA) is the same in both scenario.
For both cases, I would check the following properties as it could contribute to the difference you're seeing:
getTranslationZ()
getElevation()
getOutlineAmbientShadowColor() (this is only valid in API 28+)
getOutlineSpotShadowColor() (this is only valid in API 28+)
Plus, checking Layout inspector to see if there's any view that could affect to the rendering.
Also, this article from Sebastiano Poggi could be of help.
I have what I think is a pretty common use case: I have multiple rows of information on the screen. I'm hoping to implement these views without having to use nested ViewGroups. Each row should have a minimum height, but expand if the contents are larger than the minimum height. The contents should be nested vertically.
It seems like this simplified example should work:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Row"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/view"
app:layout_constraintBottom_toBottomOf="#+id/view"/>
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#8800ff00"
app:layout_constraintHeight_min="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="#id/textView"/>
</android.support.constraint.ConstraintLayout>
Instead of creating a ViewGroup for each row, I have a flat layout with constraints. A View for each row sets the row height and can be clickable. The views inside the row are siblings in the layout hierarchy, but center themselves vertically in the middle of the View for that row. Since I've specified app:layout_constraintHeight_min and anchor the bottom of the View to the bottom of the contents, it should grow with the contents.
But there's a problem:
ConstraintLayout adds undesired spacing above the row! Note that the unwanted spacing above the row is equal to the correct spacing between the bottom of the contents and the bottom of the row.
My theory is this: since the View's bottom is anchored to the bottom of the contents (the TextView) it wants to stick tightly to that and be right next to it. If I force it to move further away, it adds something like a bottom margin to accomplish that, it adds a similar top margin to be symmetrical.
How do I make it stop? If it wasn't for that unwanted spacing on the top, I'd have exactly what I need. Perhaps there's some special ConstraintLayout trick, some magical attribute to fix this behavior. Or maybe there's a completely different way to use ConstraintLayout to accomplish the UI I want.
I realize that using fixed-height rows would make this much simpler, but I don't like doing that if the contents can grow.
I could change my UI to have a nested ConstraintLayout for each row, but I'd rather not do that after working so hard to make a complex layout completely flat, without multiple layers of ViewGroups. But that's what I'll do if I can't find a better solution, which I hope to find here.
I think removing the min height and adding some margin in the TextView will do the thing and instead of using match_parent you can use constraints if possible
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:text="Row is not column"
android:textColor="#283858"
app:layout_constraintBottom_toBottomOf="#+id/view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/view"/>
<View
android:id="#+id/view"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#8800ff00"
app:layout_constraintBottom_toBottomOf="#id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
As you can see on an attached image I'm having a sort of triangle shadow at the right side of my cards down in the list.
I have elevation set to 0 for all three:
app:cardElevation="0dp"
card_view:cardElevation="0dp"
android:elevation="0dp"
This happens to all my lists. What am I missing?
You didn't post complete layout source, but I had the same issue and I assume the cause was the same. I had a similar list of items, each row being a custom view which extends LinearLayout and inflates some custom layout (let's call it row_item.xml). The list layout looked something like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.example.android.RowItem
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<com.example.android.RowItem
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
The RowItem layout (row_item.xml) looked something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="10dp"
android:outlineProvider="bounds">
...
</LinearLayout>
The problem is RowItem being LinearLayout alone and inflating row_item.xml with the following code:
LayoutInflater.from(context).inflate(R.layout.row_item, this, true);
This actually wrapped the LinearLayout with elevation by ANOTHER LinearLayout, creating a layout similar to this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="10dp"
android:outlineProvider="bounds">
...
</LinearLayout>
</LinearLayout>
Setting elevation on the LinearLayout wrapped by another LinearLayout caused these weird shadows. The solution is setting the elevation on the outside LinearLayout. Even better solution is getting rid of the double layout by replacing <LinearLayout> by <merge> in row_item.xml and setting elevation programmatically inside the custom view's code.
In case you are not using a custom view but are having this problem, you are probably not setting elevation on the outer most container of your item.
I have a relative layout with a margin and a floating action button that is nested inside this layout.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent"
android:layout_margin="#dimen/activityMargin"
android:orientation="vertical"
android:clipToPadding="false">
<android.support.design.widget.FloatingActionButton
android:id="#+id/id_FABSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
app:srcCompat="#drawable/ic_save_white"/>
</RelativeLayout>
As you can see in the attached picture, the drop shadow of the floating action button is cut off. How does this happen and how can it be fixed?
In your relative layout tag, use padding instead of margin and add the attribute android:clipToPadding="false" to avoid the shadows being cut.
<RelativeLayout 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="match_parent"
android:padding="#dimen/activityMargin"
android:clipToPadding="false">
Problem is that shadows are cut by bounds of view or view group. To tackle this issue you have to use:
android:clipChildren
Defines whether a child is limited to draw inside of its bounds or not.
android:clipToPadding
Defines whether the ViewGroup will clip its children and resize (but not clip) any EdgeEffect to its padding, if padding is not zero.
Problem is that you have to set this to many views in xml if you want to render shadow. I resolved this issue on level of themes.xml. In my top level theme I just set:
<item name="android:clipChildren">false</item>
<item name="android:clipToPadding">false</item>
Then, if there is space on screen, shadow is rendered. I hope it won't break something else.
EDIT: It breaks some views. For example CameraPreview will set black background to whole screen. Be careful with scrolling views, etc.