Remove elevation shadow without removing elevation itself - android

Is there a way for AppBarLayout to no drop shadow and keep its elevation?
<android.support.design.widget.AppBarLayout
app:elevation="0dp">

To complete M.Sandholtz answer, you can also define this in XML, with outlineProvider="none".
<View
android:id="#+id/viewElevationNoShadow"
android:outlineProvider="none"
android:elevation="4dp" />

I just ran into this same problem and this is what fixed it for me:
val withElevationNoShadow = view.findViewById<*your view type*>(*your view id*)
withElevationNoShadow.outlineProvider = null
Keep in mind that the code above is Kotlin, but the Java is almost identical.
This works because shadows are drawn by ViewOutlineProviders. By setting your view's ViewOutlineProvider to null, you take away the default shadow.
For more info about ViewOutlineProviders check out
https://developer.android.com/reference/android/view/ViewOutlineProvider
and
https://developer.android.com/training/material/shadows-clipping

Related

Why there is no shadow under AppBarLayout despite having elevation [duplicate]

I've created an AppBar layout like this
<android.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/appbar_layout"
android:layout_height="#dimen/app_bar_height"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="20dp">
<android.support.design.widget.CollapsingToolbarLayout...>
</android.support.design.widget.AppBarLayout>
it works and casts a shadow in the LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</LinearLayout>
However when I put it into the CoordinatorLayout shadow is gone:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>
How can I make appbar to show its shadow again?
This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.
the reason is above,try this to solve:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//some other code here
ViewCompat.setElevation(appBarLayout, The Elevation In Px);
}
});
The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.
Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:translationZ="8dp"
app:elevation="0dp">
<!--
* `app:elevation=0dp` disables the default shadow that is automatically added on
scroll ; other values e.g. `6dp` are ignored despite what the official doc says
(see below)
* so instead we're using `android:translationZ` to add a shadow with a custom
elevation
-->
The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.
setTargetElevation() is now deprecated for AppBarLayout.
The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator.
material-components uses this as you can see here
I've added an example implementation of always showing AppBarLayout elevation here in this gist.
All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:
appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

Recyclerview transparent background

How do I make my Recyclerview transparent. Not the items in it, but the actual component itself so I can see the view behind it. I tried this:
android:background="#android:color/transparent"
But it doesn't work. If set it to a color (like red or blue) using that attribute it works though...
Try using this:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null" />
with this, your RecyclerView's background will be null and you can see the Parent View's background.

CollapsingToolbarLayout - shadow only when scrolled [duplicate]

I've created an AppBar layout like this
<android.support.design.widget.AppBarLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/appbar_layout"
android:layout_height="#dimen/app_bar_height"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="20dp">
<android.support.design.widget.CollapsingToolbarLayout...>
</android.support.design.widget.AppBarLayout>
it works and casts a shadow in the LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</LinearLayout>
However when I put it into the CoordinatorLayout shadow is gone:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>
How can I make appbar to show its shadow again?
This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.
the reason is above,try this to solve:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//some other code here
ViewCompat.setElevation(appBarLayout, The Elevation In Px);
}
});
The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.
Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:translationZ="8dp"
app:elevation="0dp">
<!--
* `app:elevation=0dp` disables the default shadow that is automatically added on
scroll ; other values e.g. `6dp` are ignored despite what the official doc says
(see below)
* so instead we're using `android:translationZ` to add a shadow with a custom
elevation
-->
The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.
setTargetElevation() is now deprecated for AppBarLayout.
The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator.
material-components uses this as you can see here
I've added an example implementation of always showing AppBarLayout elevation here in this gist.
All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:
appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

There is no method to get the current background color of CardView

There is no method to get the current background color of CardView. There is a method to set the background like
cardView.setCardBackgroundColor(color);
I would like something like:
cardView.getCardBackgroundColor();
It will be really helpful.
It looks like a getCardBackgroundColor() method has indeed been added to CardView, but in a rather recent version, so just make sure your support library version is up to date.
Do note that this method returns a ColorStateList rather than a single color value. Calling getDefaultColor() on that will give you the normal background color.
int backgroundColor = cardView.getCardBackgroundColor().getDefaultColor();
You should set and get color to parent layout inside CardView.
<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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible">
</RelativeLayout>
In this case, try to set and get from RelativeLayout.
It was a problem with gradle. I was using an old version of CardView bundled with some other library. Fixed by adding the line:
compile 'com.android.support:cardview-v7:24.2.1'

CardView inside RecyclerView has extra margins

I am using a CardView as element inside a RecyclerView. When doing so android automatically generates margins between the cardView and the screen and between different cardViews.
<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:background="#color/galleryCardBGColor"
app:cardCornerRadius="2dp" >
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
I followed the instructions in the link to integrate them into my project:
using-recyclerview-and-cardview-in-eclipse-adt
I had been previously using a linearlayout for the list element :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
This was working perfectly fine, with no margins whatsoever between the list elements. I have now just placed the linear layout inside the cardView which has resulted in extra margins.
The reason being that i want to provide exact margins to these elements, and any margins I supply now is being added over to this preexisting margins.
I have tried supplying zero/negative paddings/margins to the cardView element but none of these work.
Any idea, I can remove these margins or otherwise know exactly how much margin is being added.
did you check if it is margin or padding? (Dev Options / show layout bounds)
CardView adds padding in platforms pre-L to draw shadows. In L, unless you set useCompatPadding=true, there should not be any gap.
Adding negative margins (although it is ugly) should work. If it is not, please add some more code on how you are adding them and how you are setting up the RecyclerView.
It worked for me. Use:
card_view:cardElevation="0dp"
card_view:cardMaxElevation="0dp"
Just described in #yigit 's answer, the CardView will add a default padding to draw it's shadow before Android L. The padding size is described in CardView's doc.
I found the way to clear this padding (also to add padding for content) is to use CardView's contentPaddingLeft(/Right/Top/Bottom) attributes.
If you want to clear the default padding, you can set the contentPadding to minus value. If you want to add content padding, set the contentPadding to the value you want.
In my case, I use these code to clear the default padding:
card_view:contentPaddingLeft="-3dp"
card_view:contentPaddingRight="-3dp"
card_view:contentPaddingTop="-3dp"
card_view:contentPaddingBottom="-3dp"
I tried #Shubham 's answer, but an IllegalStateException is thrown in RadialGradient.java with message the "radius must be > 0".
Use this two tags below:
card_view:cardPreventCornerOverlap="false"
card_view:cardUseCompatPadding="true"
add card_view:cardPreventCornerOverlap="false" to your card
It works only if your Image has Rounded Corners
I know its late but i hope it will help someone
app:cardPreventCornerOverlap="false"
setting app:cardPreventCornerOverlap to false will do the trick :)
Well, seems there is a much easier way to do it, without guessing the padding and all:
card_view:cardPreventCornerOverlap="false"
or using java:
cardView.setPreventCornerOverlap(false)
The comment from #vj9 under the accepted question helped me to calculate the offsets. Sharing it here because it might help someone else:
public static int getVerticalCardViewOffset(Context context) {
Resources res = context.getResources();
int elevation = res.getDimensionPixelSize(R.dimen.cardview_default_elevation);
int radius = res.getDimensionPixelSize(R.dimen.cardview_default_radius);
return (int) (elevation * 1.5 + (1 - Math.cos(45)) * radius);
}
public static int getHorizontalCardViewOffset(Context context) {
Resources res = context.getResources();
int elevation = res.getDimensionPixelSize(R.dimen.cardview_default_elevation);
int radius = res.getDimensionPixelSize(R.dimen.cardview_default_radius);
return (int) (elevation + (1 - Math.cos(45)) * radius);
}
use
android:adjustViewBounds="true"
on the view you want wrapped in the cardview
If you don't need the corner radius or elevation downlevel, consider using FrameLayout on pre-Lollipop.
<include layout="#layout/card_view_compat" />
layout/card_view_compat
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<include layout="#layout/content" />
</FrameLayout>
</merge>
layout-v21/card_view_compat
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="3dp"
app:cardElevation="4dp"
>
<include layout="#layout/content" />
</android.support.v7.widget.CardView>
</merge>
myCardView.setShadowPadding(0,0,0,0);

Categories

Resources