Adicionando efeito Ripple ao item RecyclerView

105

Estou tentando adicionar o efeito Ripple ao item do RecyclerView. Eu dei uma olhada online, mas não consegui encontrar o que preciso. Presumo que seja um efeito personalizado. Eu tentei o atributo android: background no próprio RecyclerView e configurei-o como "? Android: selectableItemBackground", mas não funcionou .:

    <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"/>

Este é o RecyclerView ao qual estou tentando adicionar o efeito:

insira a descrição da imagem aqui

Georgi Koemdzhiev
fonte
1
Estou reabrindo isto porque não é uma duplicata desta pergunta . Embora as soluções possam ser semelhantes, há certos aspectos de ter um CardViewnaquela questão que não pertencem a esta questão mais geral.
Suragch
@Suragch Obrigado por notar a diferença :)
Georgi Koemdzhiev

Respostas:

222

Eu descobri. A única coisa que tive que fazer foi adicionar este atributo:

android:background="?android:attr/selectableItemBackground"

ao elemento raiz do layout que meu adaptador RecyclerView infla assim:

<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>

Resultado:

insira a descrição da imagem aqui

Se você ainda não conseguir ver o efeito de ondulação, adicione essas linhas também ao elemento raiz do layout.

android:clickable="true"
android:focusable="true"
Georgi Koemdzhiev
fonte
3
E se o elemento raiz for CardView?
Nabin
6
@SpiderMan Você deve escrever seu código dentro de um Layout Relativo ou Linear e então colocá-lo dentro do Layout de Cartão.
SanVed em
7
@pronoobsanved, isso me ajudou! Para aqueles que ainda enfrentam o problema, CardView adota um único layout como uma criança. Para essa criança, defina clicável, focalizável como verdadeiro e plano de fundo como? Attr / selectedableItemBackground
Vamsi Challa
42
@NabinKhadka para um CardView defini-lo como primeiro plano, ou sejaandroid:foreground="?android:attr/selectableItemBackground"
Lorne Laliberte
6
Tive que adicionar a opção android:clickable="true"também para fazer este trabalho
Joaquin Iurchuk
69

Como já respondido, a solução mais simples é apenas adicionar um dos seguintes como RecyclerViewplano de fundo da linha:

  • android:background="?android:attr/selectableItemBackground"
  • android:background="?attr/selectableItemBackground"

No entanto, se você estiver tendo problemas com esse método ou se quiser um controle mais preciso sobre as cores, faça o seguinte.

Efeito de ondulação personalizado

Esta resposta começa com este exemplo simples do Android RecyclerView . Será semelhante à imagem a seguir.

GIF de exemplo de efeito ondulação

Adicionar seletor para dispositivos pré API 21

Antes da API 21 (Android 5.0 Lollipop), clicar em um RecyclerViewitem apenas alterava sua cor de fundo (sem efeito cascata). Isso é o que vamos fazer também. Se você ainda tem usuários com esses dispositivos, eles estão acostumados com esse comportamento, então não vamos nos preocupar muito com eles. (Claro, se você realmente quiser o efeito cascata para eles também, você pode usar uma biblioteca personalizada .)

Clique com o botão direito na res/drawablepasta e escolha Novo> Arquivo de recursos Drawable . Ligue custom_ripple. Clique em OK e cole o código a seguir.

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>

Usei colorAccentcomo cor de destaque para o estado pressionado porque já estava disponível, mas você pode definir a cor que quiser.

Adicionar efeito Ripple para dispositivos API 21+

Clique com o botão direito na res/drawablepasta e escolha Novo> Arquivo de recursos Drawable . Ligue custom_ripplenovamente. Não clique em OK, ainda desta vez. Na lista de qualificadores disponíveis, escolha Versão , clique no botão >> e escreva 21para o nível de API da plataforma . Agora clique em OK e cole o código a seguir.

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>

Novamente, usei colorAccentpara a cor ondulada porque ela estava disponível, mas você pode usar a cor que quiser. A máscara limita o efeito de ondulação apenas ao layout da linha. A cor da máscara aparentemente não importa, então usei apenas um branco opaco.

Definir como plano de fundo

No layout raiz do seu item RecyclerView, defina o plano de fundo para a ondulação personalizada que criamos.

android:background="@drawable/custom_ripple"

No projeto de exemplo com o qual começamos, é assim:

<?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>

Acabado

É isso aí. Você deve conseguir executar seu projeto agora. Obrigado a esta resposta e este vídeo do YouTube para obter ajuda.

Suragch
fonte
Se você quiser ter uma cor de fundo padrão, basta remover a linha 'android: id = "@ android: id / mask' e definir a cor do drawable para o que você quiser.
Jordan Hochstetler
26

Acho que há um pequeno detalhe que está faltando.

Se você ainda não obtiver o efeito cascata após adicionar, android:background="?android:attr/selectableItemBackground"tente adicionar as seguintes linhas na raiz do layout.

android:clickable="true"
android:focusable="true"

Isso garantirá que a visualização seja clicável e permitirá o efeito cascata com o atributo de fundo mencionado acima

Sriram R
fonte
5

adicione estas linhas na visualização da raiz xml do adaptador

android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
Gundu Bandgar
fonte
2

Uma abordagem simples e personalizada é definir um tema de visualização conforme descrito aqui .

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>

Outras implementações personalizadas podem ser encontradas aqui .

Adam Hurwitz
fonte
1

Usando um estilo de botão

Isso tem funcionado para mim incontáveis.

Adicione o Estilo de botão sem borda ao elemento raiz do seu layout. Não há necessidade de atributos focusableou clickable, o estilo padrão encapsula tudo isso para você.

<androidx.constraintlayout.widget.ConstraintLayout
    style="@android:style/Widget.Material.Button.Borderless"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
Felix Favor Chinemerem
fonte
legal, mas adicionando preenchimento
ededede
@ededede Você pode usar os atributos min-height, max-height, width ... XML para ajustá-lo a seu gosto.
Felix Favor Chinemerem