Adicionar efeito cascata ao meu botão com a cor de fundo do botão?

125

Eu criei um botão e quero adicionar efeito cascata a esse botão!

Criei um arquivo XML de botão bg: (bg_btn.xml)

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient android:startColor="#FFFFFF" android:endColor="#00FF00" android:angle="270" />
<corners android:radius="3dp" />
<stroke android:width="5px" android:color="#000000" />
</shape>

E este é o meu arquivo de efeito cascata: (ripple_bg.xml)

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:color="#f816a463"
    tools:targetApi="lollipop">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="#f816a463" />
        </shape>
    </item>
</ripple>

E este é o meu botão que eu quero adicionar efeito cascata:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="@+id/button"
android:layout_centerHorizontal="true"
android:layout_marginTop="173dp"
android:textColor="#fff"
android:background="@drawable/ripple_bg"
android:clickable="true" />

Mas depois de adicionar o efeito cascata, o fundo do botão fica transparente e o botão é exibido apenas quando clicado, desta forma:

Antes de clicar

Ao clicar

Mas eu preciso da cor de fundo dos botões e do efeito cascata, encontrei parte desse código em diferentes blogs do Stack Overflow, mas ainda não está funcionando!

rakcode
fonte
por favor, faça screenshots muito menor na próxima vez .. (redimensionamento antes de enviar)
USER25
@ user25, você também pode adicionar um lou mao link da imagem. (ver minha edição)
Suragch

Respostas:

154

Aqui está outro xml extraível para aqueles que desejam adicionar todos os efeitos de fundo gradiente, raio de canto e ondulação:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorPrimaryDark">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="@color/colorPrimaryDark" />
            <corners android:radius="@dimen/button_radius_large" />
        </shape>
    </item>

    <item android:id="@android:id/background">
        <shape android:shape="rectangle">
            <gradient
                android:angle="90"
                android:endColor="@color/colorPrimaryLight"
                android:startColor="@color/colorPrimary"
                android:type="linear" />
            <corners android:radius="@dimen/button_radius_large" />
        </shape>
    </item>
</ripple>

Adicione isso ao fundo do seu botão.

<Button
    ...
    android:background="@drawable/button_background" />
Pei
fonte
4
@pei Como vocês conseguem essas informações? Quero dizer, como você sabe que existe um elemento XML chamado ripple para fazer esse trabalho?
1
É um dos conceitos usados ​​no design de materiais. Comece a digitar uma nova tag raiz em um xml desenhável no Android Studio e poderá ver todas as tags disponíveis, inclusive ripple.
Pei
1
qual é o uso do item de máscara?
Prashant
10
isso requer nível de API 21
M.kazem Akhgary 16/10
2
funciona, mas como funciona não é explicado. deve estar relacionado ao ID do item. Deve ser referenciado.
oiyio
155

Adicione o atributo "?attr/selectableItemBackground"ao seu modo de exibição, android:foregroundse ele já tiver um plano de fundo junto com android:clickable="true".

barra invertidaN
fonte
nem sempre funciona, mas você pode adicionar um fundo para o efeito cascata como observado nos comentários da resposta aceita
Tyler
Eu tive que usar esta solução, pois usei um plano de fundo personalizado para o meu botão. Funcionou muito bem.
bnayagrawal
@ROAR, está certo, mas pelo menos: "Isso não é um erro; o aplicativo simplesmente ignorará o atributo. No entanto, se o atributo for importante para a aparência ou a funcionalidade do seu aplicativo, considere encontrar uma maneira alternativa de obter o mesmo resultado apenas com os atributos disponíveis e, opcionalmente, você pode criar uma cópia do layout em uma pasta layout-vNN que será usada na API NN ou superior, na qual é possível aproveitar o atributo mais recente ". Por isso, funciona bem em dispositivos acima da API 23 e é ignorado quando abaixo (podemos apenas tools:ignore="UnusedAttribute).
JorgeAmVF 17/04/19
sem a biblioteca de suporte do Android, seria ?android:attr/selectableItemBackground(em android:attrvez de attr) #
217/06 fim de semana
1
android:foregroundatributo não tem efeito nos níveis de API inferiores a 23
Vadim Kotov
67

Adicionar Efeito Ripple / Animação a um botão do Android

Apenas substitua o atributo background do botão pelo android: background = "? Attr / selectableItemBackground" e seu código fica assim.

      <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackground"
        android:text="New Button" />

Outra maneira de adicionar efeito cascata / animação a um botão do Android

Usando esse método, você pode personalizar a cor do efeito cascata. Primeiro, você deve criar um arquivo xml no diretório de recursos desenhados. Crie um arquivo ripple_effect.xml e adicione o seguinte código. res / drawable / ripple_effect.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="#f816a463"
    tools:targetApi="lollipop">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="#f816a463" />
        </shape>
    </item>
</ripple>

E defina o plano de fundo do botão para o arquivo de recurso extraível acima

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple_effect"
    android:padding="16dp"
    android:text="New Button" />
Jigar Patel
fonte
1
Para mim, o efeito cascata não apareceu. era apenas uma mudança de cor para o botão: / Minha versão do Android é 5.1.1, portanto deve funcionar. Você pode ajudar? Eu segui seus passos
UrviG 5/17/17
android: cor deve ser diferente do mastro Android: cor, ou se você quiser ver o efeito cascata
SpyZip
2
se você quer um fundo que você acabou de adicionar outro item para a ondulação, como: <item Android: = drawable / "attr / colorPrimary?">
Tyler
36

Além da solução de Jigar Patel , adicione-a ao ripple.xml para evitar o fundo transparente dos botões.

<item
    android:id="@android:id/background"
    android:drawable="@color/your-color" />

XML completo :

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:color="@color/your-color"
    tools:targetApi="lollipop">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="@color/your-color" />
        </shape>
    </item>
    <item
        android:id="@android:id/background"
        android:drawable="@color/your-color" />
</ripple>

Usa isto ripple.xml como plano de fundo no seu botão:

android:background="@drawable/ripple"
Sudheesh R
fonte
2
Não precisamos usar o <item android:id="@android:id/mask"> [...]. A menos que você queira uma máscara oval. Obrigado pela sua resposta!
Filipe Brito
O que esse <item Android: id = "@ android: id / mask"> fazer de qualquer maneira, eu criei 2 elementos semelhantes com e sem esse atributo, e olham exatamente o mesmo
Sartheris Stormhammer
@SartherisStormhammer de documentos oficiais: se uma camada de máscara for definida, o efeito cascata será mascarado nessa camada antes de ser desenhado sobre o composto das camadas filho restantes. Se nenhuma camada de máscara estiver definida, o efeito cascata será mascarado contra o composto das camadas filho. Este é o link, developer.android.com/reference/android/graphics/drawable/…
Sudheesh R
@SudheeshR que só torna mais confuso
Sartheris Stormhammer
@SartherisStormhammer A partir dessa documentação oficial, é bem claro, eu acho. O efeito cascata será desenhado sobre camadas filho / mascaradas. Por favor, leia o documento novamente, você entenderá.
Sudheesh R
33

Quando o botão tem um plano de fundo do drawable, podemos adicionar efeito cascata ao parâmetro do primeiro plano. Verifique abaixo o código que está funcionando para o meu botão com um plano de fundo diferente

    <Button
    android:layout_width="wrap_content"
    android:layout_height="40dp"
    android:gravity="center"
    android:layout_centerHorizontal="true"                                                             
    android:background="@drawable/shape_login_button"
    android:foreground="?attr/selectableItemBackgroundBorderless"
    android:clickable="true"
    android:text="@string/action_button_login"
     />

Adicione abaixo o parâmetro para o efeito cascata

   android:foreground="?attr/selectableItemBackgroundBorderless"
   android:clickable="true"

Para referência, consulte o link abaixo https://jascode.wordpress.com/2017/11/11/how-to-add-ripple-effect-to-an-android-app/

Jasmine John
fonte
2
Atributo Android: primeiro plano não tem efeito sobre os níveis de API menor do que 23
Ali Cáqui
Uma desvantagem dessa abordagem é que, mesmo que o fundo do meu botão tenha sido oval, a ondulação se propagou até as bordas retangulares.
iCantC 17/03
14

AppCompat v7 +

Se você não prefixar ?android:seu aplicativo, ele falhará.

Você deve usar "?android:attr/selectableItemBackground"ou "?android:attr/selectableItemBackgroundBorderless", com base em sua preferência. Eu prefiro Borderless.

Você pode colocá-lo android:backgroundou android:foregroundmanter as propriedades existentes.

O elemento deve ter android:clickable="true"e android:focusable="true"para que isso funcione, mas muitos elementos, como botões, os possuem truepor padrão.

<Button
    ...
    android:background="@color/white"
    android:foreground="?android:attr/selectableItemBackgroundBorderless"
/>
<TextView
    ...
    android:background="?android:attr/selectableItemBackgroundBorderless"
    android:clickable="true"
    android:focusable="true"
/>

Programaticamente (Java)

TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, value, true);
myView.setBackgroundResource(value.resourceId);
myView.setFocusable(true); // If needed for view type

Programaticamente (Kotlin)

val value = TypedValue()
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, value, true)
myView.setBackgroundResource(value.resourceId)
myView.setFocusable(true) // If needed for view type

Função de extensão Kotlin reutilizável

myView.ripple()

fun View.ripple(): View {
    val value = TypedValue()
    context.theme.resolveAttribute(android.R.attr.selectableItemBackground, value, true)
    setBackgroundResource(value.resourceId)
    isFocusable = true // Required for some view types
    return this
}
Gibolt
fonte
7

Adicionar atributos de primeiro plano e clicáveis ​​funcionou para mim.

<Button
    ... 
    android:background="@color/your_color"
    android:foreground="?attr/selectableItemBackgroundBorderless"
    android:clickable="true" />
Ashwin
fonte
6

Além de Sudheesh R

Adicione Efeito de Ondulação / Animação a um botão Android com forma de retângulo com canto

Crie o arquivo xml res / drawable / your_file_name.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/colorWhite"
    tools:targetApi="lollipop">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="@color/colorPrimaryDark" />
            <corners android:radius="50dp" />
        </shape>
    </item>

    <item android:id="@android:id/background">
        <shape android:shape="rectangle">
            <gradient
                android:angle="90"
                android:endColor="@color/colorAccent"
                android:startColor="@color/colorPrimary"
                android:type="linear" />
            <corners android:radius="50dp" />
        </shape>
    </item>
</ripple>
Digvijay Machale
fonte
4

Ao usar o android: background, você substitui grande parte do estilo e da aparência de um botão por uma cor em branco.

Atualização: a partir da versão 23.0.0 do AppCompat, existe um novo estilo colorido Widget.AppCompat.Button.A que usa colorButtonNormal do seu tema para a cor desativada e colorAccent para a cor ativada.

Isso permite que você o aplique diretamente no botão via

<Button
 ...
style="@style/Widget.AppCompat.Button.Colored" />

Você pode usar um drawable em seu diretório v21 para o seu plano de fundo, como:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?attr/colorControlHighlight">
<item android:drawable="?attr/colorPrimary"/>
</ripple>

Isso garantirá que a cor do plano de fundo seja? Attr / colorPrimary e tenha a animação de ondulação padrão usando o padrão? Attr / colorControlHighlight (que você também pode definir no seu tema, se desejar).

Nota: você precisará criar um seletor personalizado para menos de v21:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/primaryPressed"            android:state_pressed="true"/>
<item android:drawable="@color/primaryFocused" android:state_focused="true"/>
<item android:drawable="@color/primary"/>
</selector>
Atman Bhatt
fonte
Estou usando minSDK lvl 21
rakcode 13/10
não há nenhuma pasta v21 drawable, apenas uma pasta que pasta em si V21 pasta
rakcode
Sim, eu usei esse API também, se eu usar essa API depois de clicar em meu aplicativo está falhando
rakcode
na verdade, im testar meu aplicativo no meu telefone com o modo de depuração, e meu OS é CyanogenMod13 (Android 6, Marshmellow)
rakcode
4

tente isso

<Button
            android:id="@+id/btn_location"
            android:layout_width="121dp"
            android:layout_height="38dp"
            android:layout_gravity="center"
            android:layout_marginBottom="24dp"
            android:layout_marginTop="24dp"
            android:foreground="?attr/selectableItemBackgroundBorderless"
            android:clickable="true"
            android:background="@drawable/btn_corner"
            android:gravity="center_vertical|center_horizontal"
            android:paddingLeft="13dp"
            android:paddingRight="13dp"
            android:text="Save"
            android:textColor="@color/color_white" />
Raveendra
fonte
4

Uma abordagem simples é definir um tema de exibiçã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>
Adam Hurwitz
fonte
3

Apenas use :

android:backgroundTint="#f816a463"

Ao invés de:

android:background="#f816a463"

Não esqueça de mudar Buttonparaandroid.support.v7.widget.AppCompatButton

Gilad Shapira
fonte
1
O ruim é que, se você precisar de um botão para preencher 100% da tela horizontal, não precisará.
Filipe Brito
1

Uma solução alternativa para usar o <ripple> tag (que eu pessoalmente prefiro não fazer, porque as cores não são "padrão") é a seguinte:

Crie um drawable para o segundo plano do botão e inclua <item android:drawable="?attr/selectableItemBackground">no<layer-list>

Então (e acho que essa é a parte importante) programaticamente definida backgroundResource(R.drawable.custom_button)na sua instância de botão.

Atividade / Fragmento

Button btn_temp = view.findViewById(R.id.btn_temp);
btn_temp.setBackgroundResource(R.drawable.custom_button);

Layout

<Button
    android:id="@+id/btn_temp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/custom_button"
    android:text="Test" />

custom_button.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <item android:drawable="?attr/selectableItemBackground" />
</layer-list>
Aidan Host
fonte
Por que programaticamente deve definir backgroundResource novamente, enquanto o layout xml define o plano de fundo de Button?
SunnyShiny9