Ripple effect on a ImageButton does not work - android

I set an ImageButton in a RelativeLayout and i want to show a Ripple effect when the button get clicked. As far as i know it have to be enabled by default but for some reason it doesn't show even if i set ?attr/selectableItemBackgroundBorderless or ?attr/selectableItemBackground as foreground or background (i used ?android:attr instead of ?attr too).
I tried everything, i made a custom Ripple effect drawable and setted it as foreground/background and it stills not working.
The app is API 21 > targeting 31, i don't know if it have anything to do with it but i using Material3.dark as main theme.
Anyone have an idea of what could be wrong here?
ImageButon:
<ImageButton
android:id="#+id/tb_music"
style="#style/top_bar_button"
android:layout_marginLeft="8dp"
android:src="#drawable/note" />
Style top_bar_button:
<style name="top_bar_button">
<item name="android:layout_width">64dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:background">#00000000</item>
<item name="android:foreground">#drawable/ripple_effect</item>
<item name="android:clickable">true</item>
</style>
ripple_effect.xml:
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FFFFFF">
<item android:id="#android:id/mask"
android:drawable="#android:color/white">
<shape android:shape="rectangle"> </shape>
</item>
</ripple>
How the button looks

don't use background attribute with ImageButton or Button. These widgets have 9-patch set as background, so when you overwrite it you basically lose default Androids button style and padding. Now you bascially may have in here ImageView or even TextView with drawable set to left/right
for coloring button (image or common, or even other Views) use android:tint attribute, but this will work with API23+ (so you may look for some compat/androidX version if you need API21, note it implements TintableBackgroundView, so we may assume that tint attribute will work, with custom not-android prefix)
also in question you should show your ripple effect drawable file, but even assuming that is is properly written - you have set transparent background, thus ripple effect won't be visible, as it works only in bounds of background - you transparent color removed default "shape" of this View. Just like elevation and translationZ params, these are adding some shadow under View, but only for not transparent, you've also lost this visual effect in here
so in short: remove background attribute leaving default one (or set it as non-transparent-at-all 6-hash solid color, but this will become just colored rectangle) and get familiar with tint and tintMode
aaand if you need a ripple effect on transparent rectange View then afaik thats possible also, but with mask param in drawables XML. and you don't need ImageButton, any View is clickable in Android, especially when set View.OnClickListener using Java/Kotlin. so ImageView will be sufficiet

I don't know why ripple does not work in your app but when I tested it, It is working properly. I think you didn't give padding to your ImageButton. You can see my XML code that how my code shows the Ripple effect.
<ImageButton
android:id="#+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:srcCompat="#drawable/note"
tools:ignore="ContentDescription" />
<!-- Make sure that you have added padding to show ripple effect. Otherwise ripple effect not show-->
Let me know if your problem is not solved yet.

Related

Setting backgroundTint on Material Button with alpha has a weird visual effect in normal and pressed state

I'm using Material Buttons in my project and trying to set backgroundTint with alpha value.
<!-- background_tint.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#android:color/black" android:alpha="0.60"/>
</selector>
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="Sign in"
app:backgroundTint="#color/background_tint" />
</LinearLayout>
The resulting button however looks weird while in normal state and even weirder while pressed.
I don't see this issue when I set backgroundTint to specific shade of gray such as #777777. Why does this happen with alpha value?
We had the same issue with partially opaque elevated material views.
Simply adding android:stateListAnimator="#null" removed the visible shadow artifacts.
We also set the elevation to 0dp which I don't think is required.
You just need to change the style property of Material Button.
style="#style/Widget.MaterialComponents.Button.UnelevatedButton"
It's probable that you're seeing the shadow beneath. It seems like Material Design shadows are weird. It feels like the shadows are only at the sides as you're not suppose to see them anyways.
You can fix it by using an unelevated button (style="#style/Widget.MaterialComponents.Button.UnelevatedButton") or by trying to recreate that shade of gray without alpha (by maybe screenshotting the part without the shadow weirdness and using an eyedropper to get the color in RGB)
Also, it seems like you're trying to change the color of the selector.
It can be achieved by using app:rippleColor="#color/yourRippleColor". Background tint changes the color of the button itself according to the Material Components Documentation (Material Component: Button). Adjusting the alpha adjusts opacity of the color making your button more transparent/opaque enabling you to see beneath it.

Styling a AppCompatButton in v21 to have no shadow and corner radius of zero

I have a AppCompatButton defined in a XML layout, and I have set a theme for it like this:
android:theme="#style/CustomAccentOverlay"
And I have set:
android:stateListAnimator="#null"
to remove the shadow. I have two problems with this.
The height of the button is deducted the height of the shadow, even though the shadow is not shown. Should I remove the shadow in some other way, or how do I fix this?
The button has rounded corners, and I want the corners to be sharp. I can not set a background on the button, because I want to keep the standard ripple effect and that goes away if I set a background (at least I don't know how to keep it if I set a background). I have tried setting
<item name="android:bottomLeftRadius">0dp</item>
and all the other corners to the CustomAccentOverlay theme and also its corresponding style, but it does not work. How can I set the corner radius to zero on my button?
Thank you
Søren
Use the following code for the Button.
<android.support.v7.widget.AppCompatButton
android:layout_width="200dp"
android:layout_height="200dp"
android:text="Button"
android:stateListAnimator="#null"
android:elevation="0dp"
android:background="#android:color/darker_gray"
android:foreground="?attr/selectableItemBackground"
/>
I will explain the attributes.
android:elevation="0dp" and android:stateListAnimator="#null". No shadow for the button.
android:background . Set the desired color as background. It removes the rounded corners.
android:foreground="?attr/selectableItemBackground" . It gives the ripple effect when the button is pressed.
Update 1:
It seems like android:foreground attribute for View works from API 23. For below APIs, create a drawable with ripple in drawable-v21 folder and set it as background to the button,
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="NewApi"
android:color="#color/ripple_color">
<item android:drawable="#color/normal_state_button_background_color"/>
</ripple>
For pre Lollipop versions, create a drawable with selector in drawable folder with the same name.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/pressed_color"
android:state_pressed="true" />
<item android:drawable="#drawable/focused_color"
android:state_focused="true" />
<item android:drawable="#drawable/normal_color" />
</selector>
First question:How to remove shadow of a button?
Here is the answer:
Just add this attribute to your button
android:stateListAnimator="#null"
Second question: How to make the corner of button sharp without losing the standard ripple effect.
Here is the answer: But first you have to make two drawble file with same name but one for below api 21 and one for api > 21 because the ripple is only available only api > 21.So now I am showing how to create that.Read the following text carefully
Right click on the drawble folder and choose new and "Drawble resource file" and hit next then name the drawble whatever you like and press ok.Then again right click on the drawble folder and choose new and "Drawble resource file" and hit next and name the drawble exactly what you named the previous drawble folder but this time at the bottom you can see a section called "available qualifiers".Go to this section and at the very bottom you can see "Version",click it and then you can see a arrow icon at the right,click it then in the "Platform api level" add 21 and then press ok.And now if you expand drawble folder you can see two file of your created drawble file.Once for api that is below 21 and once for upper 21.Open drawble file that you have created and make sure you open that have "(v21)" at the last.Now delete everything from there and add the following code
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="?attr/colorControlHighlight" xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<corners android:radius="0dp"/>
<solid android:color="#D6D7D7"/>
</shape>
</item>
</ripple>
And add this attribute to your button
android:background="#drawable/youdrawblefilethatyouhavecreated"
And now if you run your application you can see that there is no shadow and your button has sharp corner and if you click the ripple shows up.
Lastly,your button look something like this
<android.support.v7.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button 1"
android:background="#drawable/yourcreatddrawblefile"
android:stateListAnimator="#null"/>
Hope this help!
It really sounds like you want to use a clickable TextView rather than a Button. TextView by default will not have shadow and has sharp corners and you can attach a click listener to it. Remember, Button is just a fancy TextView with a lot of visual add-ons to it, and it sounds like you want to remove a lot of it.
If you want to keep the ripple on the TextView and define your own background, set android:foreground="?attr/selectableItemBackground"
EDIT: Even though the other answer was marked accepted, I would still argue that the OP should use a TextView with a click listener and applying the ripple effects to that than using a Button. Clickable TextViews in this manner are exactly how the Google I/O app implements all of their flat buttons that meet Material Design spec.
Use this code
<android.support.v7.widget.AppCompatButton
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/colorAccent"
android:text="#string/button" />

Customize Button (ANDROID)

I want to fully customize button in android, with keeping all its juicy material design styles.
Without a custom drawable png for button, just applying a color to button, i am able to change the color of the button and keep the Elevation, Ripple Effect, Rounded corner and it looks nice.
The code i used for this is
<resources>
<style name="AppTheme.NoActionBar">
<item name="android:colorButtonNormal">#8126f3</item>
</style>
</resources>
Then i wanted to put my own drawable into the button and keep the Material Design effects . so i created a drawable (V21) and assigned it as background to the button.
button_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="#drawable/take_ride_map_btn"/>
</ripple>
But now the problem is that it does not have a elevation. And the ripple effect does not start at the point of touch.
I have looked into this, this, and this SO Question but these are not helpful with using the custom drawable into button.
Please do suggest how can i achieve this -
Elevation while having the custom drawable.
Start the Ripple Effect at the point where user touches.
you can always have the elevation if you set the button to wrap_content both ways i.e height and width and for the ripple effect you should use RippleDecoratorView.
You don't need to cast it to anything just wrap the button inside it in xml and your good to go, plus its highly customizeable too

Get ripple effect in RecyclerView with items containing another background color

I need a simple ripple effect in my RecyclerView elements, which have a background color set. Since they have a background color(blue) set already, I can't set the background to the drawable/ripple.xml:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/color_view_pressed"> <!-- ripple color -->
<item android:drawable="#android:color/white"/>
<!-- normal color -->
So I changed my ripple.xml to:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/color_view_pressed"> <!-- ripple color -->
<item android:drawable="#android:color/blue"/>
<!-- normal color -->
It still doesn't work. :(
EDIT:
Apparently, the ripple color is getting hidden behind the background color, so it is almost not to be seen. But one can see a tinge of it in the background(if I set color_view_pressed to a dark red color).
Is there any way I can achieve that even otherwise? I have tried all possible solutions out there.
Somehow, it was working perfectly well with the ListView. I don't understand how though.
In the root ViewGroup of the layout used for items add foreground attribute instead of background (that you have already set):
android:foreground="?android:attr/selectableItemBackground"
and also set these attributes:
android:clickable="true"
android:focusable="true"
This worked for me
You can have 2 ViewGroups that will have a background - the top one for the ripple, and it's child to have the entire layout with the blue background.

Selector/Ripple/Tint for ImageView

I have an ImageView with a Bitmap as as its source. I want to give a selector/ripple/tint to the ImageView. When I click on ImageView I want to show a white color (#AAFFFFFF) tint with alpha.
This is what I have tried.
selector_image.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/blue_a" android:state_pressed="true"/>
<item android:drawable="#color/green_a" android:state_selected="true"/>
<item android:drawable="#color/red_a" android:state_activated="true"/>
<item android:drawable="#android:color/transparent"/>
</selector>
Then I set this as the ImageView's background using android:background="#drawable/selector_image". However this changes the background which is behind my Bitmap, hence is not visible on top of the Bitmap.
Have a look at this video for help
Image Ripple Effect.
The Video have a ripple effect. I want this ripple in post-lollipop devices and a simple tint without ripple for pre-lollipop.
How can I achieve this effect?
For ripple effect affect you don't need a selector but a ripple like
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="#android:id/mask">
<shape android:shape="oval">
<solid android:color="?android:colorAccent" />
</shape>
</item>
</ripple>
and put this under drawable-v21 folder.For pre lollipop device create a a normal selector and set it as background.Also both the files should have the same name.
How about ImageButton instead of ImageView. You can easily set a background selector for different states.
First of all, to get the nice ripple effect on API 21+, and fallback to a light shadow on older platforms, make sure you are using appcompat-v7 support library, then you can use ?selectableItemBackground to get the effect.
Now the question is about how to add the effect on top of your ImageView. Here are some possible solutions.
If you are using ImageViews as items in a ListView, you can set the following attributes for ListView.
<ListView
...
android:drawSelectorOnTop="true"
android:listSelector="?selectableItemBackground" />
If you are using the ImageView inside a FrameLayout, you can set the ripple as foreground of the FrameLayout.
<FrameLayout
...
android:foreground="?selectableItemBackground" />
You can always add a wrapping FrameLayout over the ImageView to get the foreground ripple. Note that andriod:foreground is only added to all the views since API v23, so we cannot utilize that.
You can also extend ImageView to add backward-compatible foreground support to it. If you want to go this way, leave a comment and I'll write more about it here.
Edit:
Checkout my implmentation of a RelativeLayout with foreground: https://gist.github.com/DreaminginCodeZH/9067a68d6e836389933c
Drop the attrs.xml into res/values, and ForegroundRelativeLayout.java into your own package, then replace all occurences of RelativeLayout to ImageView.
Then you can reference the custom view in your XML. Instead of using ImageView, use the fully qualified name of your custom view (com.example.android.ForegroundImageView for example) as the tag name, and add android:foreground="?selectableItemBackground" to it. This way it should work properly now.
(It should work properly if you don't target API 23 which will enable foreground for all views on API 23 (otherwise it won't be enabled), resulting in two foregrounds - His code is written far before the release of API 23. If you target API 23, you can workaround this by adding some API level check yourself.)
I was also planning to release a library for android:foreground backward-compatibility. If I had the time :)
One more thing, solution #3 of wrapping the ImageView with a FrameLayout should always work (easily), without all the work required above. You need to leverage it with the slight performance loss yourself.

Categories

Resources