RippleDrawable NOT drawing over Views - android

I have a layout with a KenBurnsView and an ImageView over it (just a toggle button). When I click on the button a Ripple is generated but is drawn below the KenBurnsView.
Previously, when I had an Image view in replacement to the KenBurnsView the Ripple was drawn above the ImageView on the top.
Here is my layout:
<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:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
android:clickable="true"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="#dimen/nav_drawer_header_height">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.flaviofaria.kenburnsview.KenBurnsView
android:id="#+id/header_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/cover_1" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/header_toggle"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
android:padding="10dp"
android:src="#drawable/toggle_down" />
</RelativeLayout>
</FrameLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/nav_toggle_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></RelativeLayout>
</LinearLayout>
This is my ripple drawable XML:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/white"
android:drawSelectorOnTop="true"> <!-- ripple color -->
</ripple>
This is how I am adding the ripple:
toggle.setBackground(getResources().getDrawable(R.drawable.ripple));
What is the problem because of which the Ripple gets drwan below the KenBurnsView? It used to work perfectly when there was an ImageView in place of the KenBurnsView?

Unbounded ripples are projected on to the first available background of an ancestor view. Trace up the view hierarchy from the ImageView that's hosting the ripple and you will find that the first available background is on the LinearLayout with identifier drawer.
If you set a transparent background on the RelativeLayout containing your ImageView, the first available background will be one that's rendered above the sibling view and you will get the desired effect.
Side note, that RelativeLayout should be replaced with a FrameLayout, which will provide the same effect with a less expensive layout pass.

as you can see from your own code ('setBackground') , you're setting the ripple as a BACKGROUND that's why it's being drawn on the background.
ImageView on android API 21 added this "hack" for the ripple android:drawSelectorOnTop="true". But the library you're using didn't add the same hack to it.
There's nothing wrong itself on your code. But this type of behavior cannot be guaranteed by the Android team for 3rd party libraries.
You have a few of options here that will vary on cleanliness, effort and performance:
check ImageView source code, clone the library, add the same hack that imageview used on it for the ripple. After it's working fine, make sure to pull request back to the library.
wrap your KenBurnsView with a FrameLayout and set the ripple using setForeground on the FrameLayout.
clone the library, add option to foreground drawable to it (similar to this How to set foreground attribute to other non FrameLayout view). Also make sure to pull request this valueable code back to the library.

Related

Cardview shadow looks different when inside a ScrollView

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.

Android XML: Drop shadow cut off

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.

Incorrect overlay behavior in FrameLayout

According to the docs, child views in FrameLayout are drawn on top of each other with the most recently added view on top. I have notice though, that this seems to not be accurate in Lollipop or later. For example, in the following xml, the button is still visible even though it should be covered by my custom view.
It is worth mentioning that although my custom view extends FrameLayout, I do inflate a child view, so my FrameLayout isn't empty.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="#+id/some_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:text="button"/>
<mycustomframelayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"/>
</FrameLayout>
Any idea what I am missing here?
Buttons in Lollipop and higher have a default elevation to them which causes them to always draw on top. You can change this by overriding the default StateListAnimator.
Try putting this into your button XML:
android:stateListAnimator="#null"
The FrameLayout should now cover the button.
Try putting an elevation to the FrameCustom:
<mycustomframelayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:elevation="100dp"/>

Cardview - white border around card

I am using a cardview as the root of a custom view I am writing. I using the v7 support library. My XML looks like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="6dp"
card_view:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- some other views -->
</LinearLayout>
</android.support.v7.widget.CardView>
My problem is that I am getting a white border around my card view. It looks like it is there to indicate elevation as it is thicker on the right side. I've tried adjusting cardElevation and MaxCardElevation in my XML like so :
card_view:cardElevation="0dp"
and in code in my custom view that extends CardView and uses this layout:
setCardElevation(0);
setMaxCardElevation(0);
But the white border persists. I'm not sure how to get rid of it. If anyone had any input into why this is happening or suggestions on how I can remove the white border it would be appreciated. Thanks much.
I know it's a bit late, but for anyone having a similar problem:
I had the same issue: A white border was shown on pre-lollipop devices.
I solved it setting the cardPreventCornerOverlap to false on your XML.
Like this:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="6dp"
card_view:cardPreventCornerOverlap="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- some other views -->
</LinearLayout>
</android.support.v7.widget.CardView>
Support CardView doesn't support content clipping, because it's expensive on older devices. It's possible to clip content using Canvas.saveLayer/restoreLayer and PorterDuff modes. This is how Carbon implements rounded corners with correct content clipping. See the image:
I might be late in the game, but I had the same issue. Just wanted to share a simple solution!
My custom view extended a CardView and I had a margin applied to the root element (i.e. CardView) in the XML just like in the original question. This ended up giving me the extra white border like this:
Solution was to move the margin from root of the Custom View XML to the declaration of your custom view (check comments in the snippet)
Code snippet:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/cvSettings"
style="#style/DefaultCardViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin" <!-- Remove this -->
app:cardElevation="#dimen/default_card_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
.
.
.
</android.support.v7.widget.CardView>
Ended up just moving over the margin to my custom view declaration which got rid of the extra white border:
<com.example.android.custom.MyCustomView
android:id="#+id/custom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_margin" <!-- Move it here-->
cv:pt_widgetColor="#color/colorAccent" />
After the change, much cleaner :) :
use cardBackgroundColor="color" in xml card_view
sample code :
<android.support.v7.widget.CardView
android:id="#+id/card_view_khaterat"
android:layout_width="250dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
app:cardBackgroundColor="#f56f6c"/>

Android RelativeLayout Background Color

For a long time I am reading posts from stackoverflow because they are very helpful and google seems to think that also.
Since yesterday I have a problem with a row in a ListView in Android. I want to show an image and the area between the image and the bottom of the element should be filled with a grey color.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/ConversationsBadgeLayout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#c0c0c0"
android:orientation="vertical" >
<QuickContactBadge
android:id="#+id/ConversationsBadge"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
<!--
...
A LinearLayout with TextViews, shouldn't be interesting for this
...
-->
</RelativeLayout>
My Problem ist that the it seems that the inner layout only wraps the content but doesn't fill_parent. When I set for example 100dp it works but that is not what i want.
It would be nice if you could help me with that. I tried much workarround like using LinearLayouts and TextViews but nothing worked.
You can set the background color to the ListView itself, then everything in it will have the background you want.
BTW, I recommend using LinearLayout instead of RelativeLayout in your case.
The layout file should contain exactly one outermost element and it should have both android:layout_width="match_parent" and android:layout_height="match_parent" Your RelativeLayout has android:layout_height="wrap_content"
i think you can use you can take background color in another xml file and put in drawable folder and also using Linear Layout is very useful to your problem

Categories

Resources