Hacer que un LinearLayout actúe como un botón

100

Tengo un estilo LinearLayoutque he diseñado para que se parezca a un button, y contiene algunos elementos de texto / ImageView. Me gustaría hacer todo el LinearLayoutacto como a button, en particular para darle estados que están definidos en a para que tenga un fondo diferente cuando se presiona.

¿Hay una mejor manera que hacer un ImageButtontamaño de todo el diseño y posicionarlo absolutamente?

Jason Prado
fuente
En caso de que alguien esté buscando una manera de resaltar un TableRow (que se hereda de un LinearLayout) al presionar (como un Botón), consulte stackoverflow.com/a/8204768/427545
Lekensteyn
1
si alguien quiere obtener una solución completa, consulte este repositorio: github.com/shamanland/AndroidLayoutSelector hay una opción personalizada en la que se puede hacer clic / verificar LinearLayoutcomoToggleButton
Oleksii K.

Respuestas:

154

Me encontré con este problema hace un momento. Tendrá que configurar LinearLayout para hacer clic. Puede hacer esto en el XML con

android:clickable="true"

O en código con

yourLinearLayout.setClickable(true);

¡Salud!

Rockmaninoff
fuente
2
¡La respuesta a continuación es mucho mejor!
Zach Sperske
2
Además, si tiene un elemento "en el que se puede hacer clic" como hijo, no olvide agregarlo android:clickable="false"para evitar que bloquee los eventos de clic.
TheKalpit
no es necesario, agregar un oyente de clics fue suficiente para mí y si no quieres un oyente de clics, ¿por qué querrías que se pueda hacer clic en algo?
hmac
158

Si desea agregar el comportamiento de fondo predeterminado de Android para que Layoutactúe como un "clikable" View, configure el objetivo Layout:

API 11+ (Android puro):

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

API 7+ (Biblioteca de compatibilidad de Android + AppCompat):

android:background="?attr/selectableItemBackground"

Cualquier API:

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

Las respuestas anteriores siguen siendo ciertas, pero no me ayudaron simplemente a agregar el estado predeterminado de IU presionado y liberado (como en, ListViewpor ejemplo).

FabiF
fuente
+1 para usted, esto es genial si desea la retroalimentación táctil de la interfaz de usuario, pero desea manejar la lógica del clic usted mismo (y no verse obligado a especificar un método onClickX, que es lo que requiere android: clickable)
Rick Barkhouse
2
Esto también funciona con ondas de diseño de materiales. La mejor respuesta.
Miro Markaravanes
3
¡Bueno! Cuando se presiona, resulta un color como naranja / amarillo como efecto presionado. Quiero cambiar el color a verde. ¿Cómo hacerlo?
Han Whiteking
@HanWhiteking ¿te enteraste?
Jacob Sánchez
16

Usé la primera y la segunda respuesta. Pero mi diseño lineal tiene imágenes y texto con color de fondo, así que tuve que cambiar "fondo" a "primer plano"

diseño lineal

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

Primero querrá un selector para definir los diferentes estados. Por ejemplo, en un archivo 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>

No lo he probado, pero es posible que pueda configurar el android: background de LinearLayout en este selector y configurar android: clickable en true y funcionará.

Si no es así, puede cambiar a un RelativeLayout y hacer que el primer elemento sea un botón con este selector como fondo y fill_parent para su ancho y alto de diseño. En este caso, simplemente use un botón normal y configure android: background en su selector. No tienes que poner texto en tu botón.

Tenfour04
fuente
Sí, voto por usar un archivo real Button. Puede anular onDraw(Canvas)para hacer cualquier cosa especial que necesite (es decir, dibujar imágenes o texto dentro del botón).
Dave
1
¡Gracias! Establecer el fondo de LinearLayout funciona y responde a eventos táctiles, casi - si presiono LinearLayout directamente, su estado se actualiza. Si presiono TextView dentro de él, el evento táctil no parece estar a la altura del LinearLayout. ¿Alguna idea de cómo hacer la prueba de impacto de Layout?
Jason Prado
Prueba android: clickable = "false" en TextView. No he probado esto, pero no he tenido problemas para hacer clic en TextViews. Tal vez sea porque su TextView tiene un fondo.
Tenfour04
Esto funcionó, aunque no hace sonar el clic. ¿Hay alguna forma de conseguirlo?
Steven
@Steven Acabo de ver tu comentario anterior, lo siento. Creo que el sonido del clic está relacionado con tener un onClickListener asignado. Tenía algo con un onTouchListener y no hacía clic hasta que también agregué un onClickListener (con un método onClick vacío).
Tenfour04
7

En la aplicación en la que estoy trabajando, necesito crear un LinearLayout dinámicamente. En este caso el comando

ll.setClickable(true);

no está funcionando como se supone que debe hacerlo. Aunque me pueda perder algo, logré explotar setOnTouchListener para obtener el mismo resultado y envío el código en caso de que alguien tenga las mismas necesidades.

El siguiente código crea un LinearLayout con dos vistas de texto y esquinas redondeadas, cambiando de color cuando se presiona.

Primero, cree dos archivos xml en la carpeta dibujable, uno para el estado normal y otro para el estado de diseño lineal presionado.

XML de estado normal (dibujable / bordes redondeados_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 presionado (dibujable / bordes redondeados_presionado.xml). La única diferencia está en el color ...

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

Entonces el siguiente código hace el trabajo

Variable global:

public int layoutpressed = -1;

En 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
fuente
6

Simplemente configure estos atributos

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

Simplemente agregue attr de fondo / selectableItemBackground al diseño lineal y también haga que se pueda hacer clic en ese diseño lineal

ejemplo:

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

Eso hace que el diseño lineal actúe como un botón cuando se presiona. :)

Exel Staderlin
fuente
1

Esto fue útil, pero si desea poner un color de fondo y hacer clic en el diseño lineal como el elemento de la lista. Establezca el fondo con su color preferido y establezca el color de primer plano en? Android: attr / selectableItemBackground, establezca enfocable verdadero y haga clic en verdadero

Código de muestra

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

Las respuestas anteriores trataban sobre cómo establecer el fondo predeterminado en un archivo xml. Aquí lo mismo en el código:

linearLayout1.setBackgroundResource(android.R.drawable.list_selector_background);
yuliskov
fuente