Fazendo um LinearLayout agir como um botão

100

Eu tenho um LinearLayoutque eu estilo para se parecer com um buttone contém alguns elementos text / ImageView. Eu gostaria de fazer todo o LinearLayoutato como um button, em particular para dar-lhe estados que são definidos em um para que tenha um fundo diferente quando for pressionado.

Existe uma maneira melhor do que ImageButtondimensionar todo o layout e posicionar de forma absoluta?

Jason Prado
fonte
Caso alguém esteja procurando uma maneira de destacar uma TableRow (que é herdada de um LinearLayout) ao pressionar (como um botão), consulte stackoverflow.com/a/8204768/427545
Lekensteyn
1
se alguém quiser obter a solução completa, verifique este repositório: github.com/shamanland/AndroidLayoutSelector há um clicável / verificável personalizado LinearLayoutcomoToggleButton
Oleksii K.

Respostas:

154

Corri para este problema agora. Você terá que definir o LinearLayout para clicável. Você pode fazer isso no XML com

android:clickable="true"

Ou em código com

yourLinearLayout.setClickable(true);

Felicidades!

Rockmaninoff
fonte
2
A resposta abaixo é muito melhor!
Zach Sperske
2
Além disso, se você tiver um elemento "clicável" como filho, não se esqueça de adicioná android:clickable="false"-lo para evitar que bloqueie eventos de clique.
TheKalpit
não é necessário, adicionar um ouvinte de cliques foi o suficiente para mim e se você não deseja um ouvinte de cliques, por que deseja que algo seja clicável?
hmac de
158

Se você deseja adicionar o comportamento de segundo plano padrão do Android para fazer com que um Layoutaja como um "clicável" View, defina no destino Layout:

API 11+ (Android puro):

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

API 7 (Android + AppCompat Support Library):

android:background="?attr/selectableItemBackground"

Qualquer API:

android:background="@android:drawable/list_selector_background"

As respostas acima ainda são verdadeiras, mas não me ajudaram por apenas adicionar o estado padrão da IU pressionada e liberada (como em um ListViewpor exemplo).

FabiF
fonte
+1 para você, isso é ótimo se você quiser o feedback de toque da IU, mas quiser lidar com a lógica do clique você mesmo (e não ser forçado a especificar um método onClickX, que é o que o android: clicável requer)
Rick Barkhouse,
2
Isso também funciona com ondulações de design de material. Melhor resposta.
Miro Markaravanes
3
Boa! Quando pressionado, resulta em cores como laranja / amarelo como efeito pressionado. Eu quero mudar a cor para verde. Como fazer isso?
Han Whiteking de
@HanWhiteking você descobriu?
Jacob Sánchez de
16

Usei a primeira e a segunda resposta. Mas meu linearlayout tem imagens e texto com cor de fundo, então eu tive que mudar "background" para "foreground"

layout linear

android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
romano
fonte
9

Primeiro você vai querer um seletor para definir os diferentes estados. Por exemplo, em um arquivo XML:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/button_pressed"
          android:state_pressed="true" />
    <item android:drawable="@drawable/button_focused"
          android:state_focused="true" />
    <item android:drawable="@drawable/button_normal" />
</selector>

Eu não tentei, mas você pode definir android: background do LinearLayout para este seletor e definir android: clickable como true e funcionará.

Caso contrário, você poderia mudar para o uso de RelativeLayout e tornar o primeiro elemento um botão com este seletor como plano de fundo e fill_parent para a largura e altura do layout. Nesse caso, basta usar um botão normal e definir android: background para o seu seletor. Você não precisa colocar texto em seu botão.

Tenfour04
fonte
Sim, eu voto por usar um real Button. Você pode substituir onDraw(Canvas)para fazer qualquer coisa especial que você precisa (ou seja, desenhar imagens ou texto dentro do botão).
Dave,
1
Obrigado! Definir o plano de fundo do LinearLayout funciona e responde a eventos de toque, quase - se eu pressiono LinearLayout diretamente, seu estado é atualizado. Se eu pressiono TextView dentro dele, o evento de toque não parece compor o LinearLayout. Alguma ideia de como fazer o teste de acerto do Layout?
Jason Prado,
Experimente android: clickable = "false" no TextView. Ainda não tentei isso, mas não tive problemas ao clicar em TextViews. Talvez seja porque seu TextView tem um fundo.
Tenfour04,
Isso funcionou, embora não faça o som do clique. Existe uma maneira de fazer isso?
Steven
@Steven Acabei de ver seu comentário antigo, desculpe. Acho que o som do clique está vinculado a ter um onClickListener atribuído. Eu tinha algo com um onTouchListener e ele não clicava até que eu também adicionasse um onClickListener (com um método onClick vazio).
Tenfour04 de
7

No aplicativo que estou trabalhando, preciso criar um LinearLayout dinamicamente. Neste caso, o comando

ll.setClickable(true);

não está funcionando como deveria. Embora eu possa perder algo, consegui explorar setOnTouchListener para obter o mesmo resultado e envio o código caso alguém tenha as mesmas necessidades.

O código a seguir cria um LinearLayout com duas textviews e cantos arredondados, mudando de cor quando pressionado.

Primeiro, crie dois arquivos xml na pasta drawable, um para normal e outro para o estado linearlayout pressionado.

Xml de estado normal (drawable / rounded_edges_normal.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="#FFFFFF" />
            <corners android:radius="7dp" />
            <padding android:left="5dip" android:top="5dip" android:right="5dip" android:bottom="5dip" />
        </shape>
    </item>
    <item android:bottom="3px">
        <shape android:shape="rectangle">
            <solid android:color="#F1F1F1" />
            <corners android:radius="7dp" />
        </shape>
    </item>
</layer-list>

Xml de estado pressionado (drawable / rounded_edges_pressed.xml). A única diferença está na cor ...

<?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="#FFFFFF" />
            <corners android:radius="7dp" />
            <padding android:left="5dip" android:top="5dip" android:right="5dip" android:bottom="5dip" />
        </shape>
    </item>
    <item android:bottom="3px">
        <shape android:shape="rectangle">
            <solid android:color="#add8e6" />
            <corners android:radius="7dp" />
        </shape>
    </item>
</layer-list>

Em seguida, o código a seguir faz o trabalho

Variável global:

public int layoutpressed = -1;

Em onCreate():

// Create some textviews to put into the linear layout...
TextView tv1 = new TextView(this);
TextView tv2 = new TextView(this);
tv1.setText("First Line");
tv2.setText("Second Line");

// LinearLayout definition and some layout properties...
final LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.VERTICAL);

// it is supposed that the linear layout will be in a table.
// if this is not the case for you change next line appropriately...
ll.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

ll.setBackgroundResource(R.drawable.rounded_edges_normal);
ll.addView(tv1);
ll.addView(tv2);
ll.setPadding(10, 10, 10, 10);
// Now define the three button cases
ll.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View arg0, MotionEvent arg1) {
                if (arg1.getAction()==MotionEvent.ACTION_DOWN){
                        ll.setBackgroundResource(R.drawable.rounded_edges_pressed);
                        ll.setPadding(10, 10, 10, 10);
                        layoutpressed = arg0.getId();
                }
                else if (arg1.getAction()== MotionEvent.ACTION_UP){
                        ll.setBackgroundResource(R.drawable.rounded_edges_normal);
                        ll.setPadding(10, 10, 10, 10);
                        if(layoutpressed == arg0.getId()){
                            //  ...........................................................................
                            // Code to execute when LinearLayout is pressed...
                            //  ........................................................................... 
                     }
          }
          else{
                ll.setBackgroundResource(R.drawable.rounded_edges_showtmimata);
                ll.setPadding(10, 10, 10, 10);
                layoutpressed = -1;
          }
          return true;
                }
  });           
Epaminondas
fonte
6

Basta definir esses atributos

<LinearLayout 
    ...
    android:background="@android:drawable/btn_default" 
    android:clickable="true"
    android:focusable="true"
    android:onClick="onClick"
    >
...
</LinearLayout>
Daniel De León
fonte
5

Basta adicionar background attr / selectableItemBackground ao layout linear e também tornar esse linearlayout clicável

exemplo:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/linear1"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">

Isso faz com que o linearlayout atue como um botão quando pressionado. :)

Exel Staderlin
fonte
1

Isso foi útil, mas se você quiser colocar uma cor de fundo e tornar o layout linear clicável como o item da lista. Defina o plano de fundo com sua cor preferida e defina a cor de primeiro plano como? Android: attr / selectableItemBackground, defina focalizável verdadeiro e clicável verdadeiro

Código de amostra

   <LinearLayout

        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:background="#FF0"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
         android:paddingTop="10dp"
        android:onClick="onClickMethod"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?android:attr/selectableItemBackground"
        />
Jeb Eb
fonte
0

Aswers anteriores foram sobre como definir o plano de fundo padrão no arquivo xml. Aqui a mesma coisa no código:

linearLayout1.setBackgroundResource(android.R.drawable.list_selector_background);
Yuliskov
fonte