Ripple effect has a small delay that makes it invisible - android

I am using android:background="?attr/selectableItemBackground" on a LinearLayout (which acts as a button) to get the ripple effect. When this button is clicked, the current activity slides left during a transition. The problem is that the ripple effect takes some time to be triggered and at the time it becomes visibile, the activity transition has already started, which makes the use of the touch feedback completely useless. I don't want to add a delay to the activity transition, that would be stupid IMO.
XML file looks like this:
<android.support.v7.widget.CardView>
<LinearLayout
android:clickable="true"
android:background="?attr/selectableItemBackground"/>
</android.support.v7.widget.CardView>
How can I make the ripple effect useful and visible ?

Try to use own drawable for background:
<android.support.v7.widget.CardView>
<LinearLayout
android:clickable="true"
android:background="#drawable/ripple"/>
</android.support.v7.widget.CardView>
And ripple.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#80585554">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#your color"/>
</shape>
</item>
</ripple>

On CardView you can apply
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:foreground="?attr/selectableItemBackground"
android:clickable="true">
<!--linearlayout etc...-->
</android.support.v7.widget.CardView>

The pressed state is delayed if one of the view's parents returns true in the shouldDelayChildPressedState method. Typically, subclasses of the ViewGroup that do not scroll should override this method and return false.

Related

Android app - basic icon button without text

How do I make a basic icon button without text or background? For example, just a simple vector image from #drawables that, when clicked, shows that circular response thing around it. I don't want the icon to have any background color to it. Just an icon that can be clicked, that's literally it.
I can only figure out how to do it by creating a menu and setting the icon as an item with app:showAsAction="always". It seems like there must be a better way to do this.
Edit: Here's an example of what I want to achieve. It's very basic. Just a clickable icon with responsive feedback when touched. https://material-ui.com/components/buttons/#icon-buttons
It's exactly the same as creating the following. I just thought there was likely an easier way to do this without having to create and load a menu just for one single icon:
<menu 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"
tools:context="com.mycompany.myapp.MainActivity">
<item
android:id="#+id/action_contacts"
android:icon="#drawable/ic_contacts_24"
android:title="#string/action_contacts"
app:iconTint="#android:color/white"
app:showAsAction="always" />
</menu>
First create a vector drawable and then add to the ImageView like
this:
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
app:srcCompat="#drawable/ic_delete" />
You can use a MaterialButton, ImageButton and even an ImageView for this. Here's an example of how you'd do it with an ImageView...
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground"
android:src="#drawable/your_icon" />
All you need to do is set the selectableItemBackground, this will use your theme's primary color (or maybe the secondary color, I can't remember).
Now if you want a different color for ripple effect, for example a grey ripple, then you can create the drawable yourself...
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#dddddd">
<item android:id="#android:id/mask">
<color android:color="#dddddd" />
</item>
</ripple>
and set the view background below..
android:background="?attr/selectableItemBackground"
it'll work with any view provided the view is clickable
Yes, you can use ImageView if you like, but if you want to generate the complete image (including frame/borders) yourself you don't have to go that far. You could practically use plain View (except that you'd have to supply android:layout_width/height explicitly). Just use Button and have the android:background specify a selector which will select between images.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/clear1" android:state_pressed="true"/>
<item android:drawable="#drawable/clear0"/>
</selector>

Add onFocus as well as background image to a view

I have a LinearLayout view to which I need to set the background image programmatically. However, when this view gets the focus, I need to show a stroke around it.
What am I doing:
The background resource (view_onfocus_background.xml) to show onFocus effect:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape android:shape="rectangle">
<stroke android:width="5dp" android:color="#F7CA18" />
</shape>
</item>
</selector>
In the layout XML, I am adding the background as follows to apply the background with onFocus effect.:
android:background="#drawable/view_onfocus_background"
However, in the code, I have to set the different background image to the layout.
myLayout.setBackgroundResource(R.drawable.custom_image);
So, obviously, the view_onfocus_background I added in the layout XML doesn't apply anymore!
Question:
How can I achieve onFocus effect as well as custom image background to the layout?
I figured out that there is no way I can apply background effect through XML as well as the image background to the LinearLayout. The only thing I could do is to have two LinearLayouts (parent and child). Apply XML to the parent layout. Apply image background to the child layout. Add some padding in the parent layout to show the onFocus effect.
Example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/customFocusLayout"
android:padding="5dp"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:background="#drawable/view_onfocus_background"
>
<LinearLayout
android:id="#+id/customTestLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="false"
android:padding="0dp"
android:layout_gravity="bottom"
android:background="#drawable/custom_image"
android:orientation="vertical">
<!-- more stuff here-->
</LinearLayout>
</LinearLayout>

Perform ripple effect for long clicks

I'm currently implementing an app which has a RecyclerView in which there are several custom views. From each one of these views the user can open a context menu (which requires a long click) but it's quite hard to figure out as generally, they will just perform a simple click and then think there is nothing more to it. But if I manage to give some UI feedback it could be much clearer. The idea is a simple ripple animation that highlights the background an which wouldn't complete from a simple click but which would go all the way for a long click action.
As I have been stuck on this for two days I have done my research and actually found some SO questions asking the same thing, for example this one from Cheok Yan Cheng is very well written and he even posted a video showing the desired effect (my question is pretty much the exact same) but there are no good answers as the first one says that we should use ?attr/selectableItemBackground but the given effect is different from the one I'm aiming for and I tried the second one, it doesn't do anything for a simple click as you start the animation in onLongClick.
EDIT :
Note that the expected behavior cannot be achieved from
?attr/selectableItemBackground nor by creating a ripple xml file and then set it as the background as these will give a normal onClick animation and a different longClick animation from the desired one again, look at this video to see what the desired effect is.
Try to follow these steps, it might help:
Step1:
Create ripple.xml in drawable: (This is for Android >= v21)
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="#android:id/mask">
<color android:color="#android:color/transparent" />
</item>
</ripple>
In this line <color android:color="#android:color/transparent" /> will make your button transparent.
Step2:
in your item.xml where I used ConstraintLayout:
<Button
android:id="#+id/btnItemClickOnRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerInParent="true"
android:layout_marginTop="16dp"
android:background="#drawable/ripple"
android:paddingBottom="4dp"
android:text="#string/view_details"
android:textColor="#color/White"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
And That's it.
Since your button will be fully covering your Item and it will hover on top of other view, it will act like an item.
To implement longClick listener on the button, make sure you register it in holder and then holder.button.setOnLongClick......
Try it, If any doubts please comment.
Make a xml file named ripple.xml then set the ripple.xml as the foreground of your view. It will work like a charm!!!
<?xml version="1.0" encoding="utf-8"?>
<!-- An white rectangle ripple. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#3fce29"
tools:targetApi="lollipop">
<item
android:id="#android:id/mask"
android:gravity="center">
<shape android:shape="rectangle">
<solid android:color="#3fce29"/>
</shape>
</item>
</ripple>
Try this first make ripple effect xml
ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#color/light_gray"
tools:targetApi="lollipop">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#color/light_gray"/>
</shape>
</item>
</ripple>
than your adapter decalr xml parent layout like LinearLayout or if use RelativLayout set background as below
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/ripple"
>......

Changing gradient background color by item in an adapter

I wan to create something like this. I'm want to use it in android kotlin application.
https://dribbble.com/shots/3830441-To-Do-App
Do you have any idea how to change background color soothly like you can see in that link ? Thanks a lot.
Create a drawable like this:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#376F9D"
android:centerColor="#4E9EB4"
android:endColor="#4F9FB5"
android:angle="0"
android:type="linear"/>
</shape>
Then use it as a back ground on the root element on the layout of your activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gradient">
<RelativeLayout
android:paddingTop="56dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/logo"/>
</RelativeLayout>
You are probably looking for things like this:
ViewPager for the UI
Set onPageChangeListener() for your ViewPager to detect when your ViewPager has been changed its screen
Use ViewPager.setBackgroundColor() api to change ViewPager background during the change
Use ArgbEvaluator.evaluate(positionOffSet, yourCurrentColorValue, yourNextColorValue) to get the smoothy animated color value for your above ViewPager.setBackgroundColor()
For more reference on the full solution, you can google it or you can look for something like this: http://kubaspatny.github.io/2014/09/18/viewpager-background-transition/
Kotlin is probably having similar way to solve this problem.

Adding Ripple Effect to RecyclerView item

I am trying to add Ripple Effect to RecyclerView's item. I had a look online, but could not find what I need. I assume it has to be a custom effect. I have tried android:background attribute to the RecyclerView itself and set it to "?android:selectableItemBackground" but it did not work.:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:clickable="true"
android:background="?android:selectableItemBackground"
android:id="#+id/recyclerView"
android:layout_below="#+id/tool_bar"/>
This is the RecyclerView that I am trying to add the effect to:
I figured out. The only thing that I had to do is to add this attribute:
android:background="?android:attr/selectableItemBackground"
to the root element of the layout that my RecyclerView adapter inflates like that:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="?android:attr/selectableItemBackground"
tools:background="#drawable/bg_gradient">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
android:layout_marginLeft="15dp"
android:layout_marginStart="15dp"
android:id="#+id/shoppingListItem"
android:hint="#string/enter_item_hint"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/shopping_list_item_checkbox_label"
android:id="#+id/shoppingListCheckBox"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:checked="false"/>
</RelativeLayout>
Result:
If you are still not able to see ripple effect, add these lines also to the root element of the layout.
android:clickable="true"
android:focusable="true"
As already answered, the simplest solution is to just add one of the following as your RecyclerView row's background:
android:background="?android:attr/selectableItemBackground"
android:background="?attr/selectableItemBackground"
However if you are experiencing problems with this method or if you want finer control over the colors, then you can do the following.
Custom Ripple Effect
This answer is starting with this simple Android RecyclerView example. It will look like the following image.
Add selector for pre API 21 devices
Before API 21 (Android 5.0 Lollipop), clicking a RecyclerView item just changed its background color (no ripple effect). That is what we are going to do, too. If you still have users with those devices, they are used to that behavior, so we aren't going to worry about them too much. (Of course, if you really want the ripple effect for them, too, you could use a custom library.)
Right click your res/drawable folder and choose New > Drawable resource file. Call it custom_ripple. Click OK and paste in the following code.
custom_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#color/colorAccent" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#android:color/transparent" />
</shape>
</item>
</selector>
I used colorAccent as the highlight color for the pressed state because it was already available, but you can define whatever color you want.
Add Ripple Effect for API 21+ devices
Right click your res/drawable folder and choose New > Drawable resource file. Call it custom_ripple again. Don't click OK, yet this time, though. From the Available qualifiers list choose Version, then click the >> button and write 21 for the Platform API level. Now click OK and paste in the following code.
v21/custom_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorAccent">
<item
android:id="#android:id/mask"
android:drawable="#android:color/white" />
</ripple>
Again, I used colorAccent for the ripple color because it was available, but you can use whatever color you want. The mask confines the ripple effect to just the row layout. The mask color apparently doesn't matter so I just used an opaque white.
Set as the background
In your RecyclerView item's root layout, set the background to the custom ripple that we created.
android:background="#drawable/custom_ripple"
In the example project that we started with, it looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#drawable/custom_ripple"
android:padding="10dp">
<TextView
android:id="#+id/tvAnimalName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"/>
</LinearLayout>
Finished
That's it. You should be able to run your project now. Thanks to this answer and this YouTube video for help.
I think there is one small detail that is missed.
If you still do not get the ripple effect after adding android:background="?android:attr/selectableItemBackground" try adding these following lines in the root of the layout.
android:clickable="true"
android:focusable="true"
These will make sure that the view is clickable and will enable the ripple effect with the background attribute mentioned above
add this lines in your adapter xml root view
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
A simple and custom approach is to set a view theme as outlined here.
some_view.xml
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:focusable="true"
android:src="#drawable/up_arrow"
android:theme="#style/SomeButtonTheme"/>
some_style.xml
<style name="SomeButtonTheme" >
<item name="colorControlHighlight">#color/someColor</item>
</style>
Other custom implementations may be found here.
Using a Button Style
This has worked for me countlessly.
Add the Borderless Button Style to the root element of your layout.
There's no need for focusable or clickable attributes, the default styling encapsulates all that for you.
<androidx.constraintlayout.widget.ConstraintLayout
style="#android:style/Widget.Material.Button.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content">

Categories

Resources