Faire agir un LinearLayout comme un bouton

100

J'ai un LinearLayoutstyle que j'ai stylé pour ressembler à un button, et il contient quelques éléments text / ImageView. Je voudrais faire en sorte que l'ensemble LinearLayoutagisse comme un button, en particulier pour lui donner des états qui sont définis dans un afin qu'il ait un arrière-plan différent lorsqu'il est enfoncé.

Y a-t-il un meilleur moyen que de faire une ImageButtontaille de la mise en page entière et le positionnement absolument?

Jason Prado
la source
Au cas où quelqu'un cherche un moyen de mettre en évidence un TableRow (qui est hérité d'un LinearLayout) en appuyant sur (comme un bouton), voir stackoverflow.com/a/8204768/427545
Lekensteyn
1
si quelqu'un veut obtenir une solution complète, consultez ce référentiel: github.com/shamanland/AndroidLayoutSelector, il y a un clic / vérifiable personnalisé LinearLayoutcomme unToggleButton
Oleksii K.

Réponses:

154

Je suis tombé sur ce problème tout à l'heure. Vous devrez définir LinearLayout sur cliquable. Vous pouvez soit le faire dans le XML avec

android:clickable="true"

Ou en code avec

yourLinearLayout.setClickable(true);

À votre santé!

Rockmaninov
la source
2
La réponse ci-dessous est bien meilleure!
Zach Sperske
2
De plus, si vous avez un élément "cliquable" comme enfant, n'oubliez pas de l'ajouter android:clickable="false"pour éviter qu'il ne bloque les événements de clic.
TheKalpit
pas nécessaire, l'ajout d'un écouteur de clic me suffisait et si vous ne voulez pas d'écouteur de clic, pourquoi voudriez-vous que quelque chose soit cliquable?
hmac
158

Si vous souhaitez ajouter le comportement d'arrière-plan par défaut d'Android pour créer des Layoutactes comme un "clikable" View, définissez sur la cible Layout:

API 11+ (Android pur):

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

API 7+ (bibliothèque de support Android + AppCompat):

android:background="?attr/selectableItemBackground"

Toute API:

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

Les réponses ci-dessus sont toujours vraies mais ne m'ont pas aidé pour simplement ajouter l'état de l'interface utilisateur par défaut enfoncé et libéré (comme dans un ListViewexemple).

FabiF
la source
+1 pour vous, c'est génial si vous voulez le retour tactile de l'interface utilisateur, mais que vous voulez gérer vous-même la logique de clic (et ne pas être obligé de spécifier une méthode onClickX, ce qui est ce que nécessite Android:
clickable
2
Cela fonctionne également avec les ondulations de conception matérielle. Meilleure réponse.
Miro Markaravanes
3
Bien! Lorsqu'il est pressé, il devient une couleur comme l'orange / jaune comme effet pressé. Je veux changer de couleur en vert. Comment faire?
Han Whiteking
@HanWhiteking avez-vous découvert?
Jacob Sánchez
16

J'ai utilisé la première et la deuxième réponse. Mais ma disposition linéaire contient des images et du texte avec une couleur d'arrière-plan, j'ai donc dû changer "arrière-plan" en "premier plan"

linéaire

android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
romain
la source
9

Vous aurez d'abord besoin d'un sélecteur pour définir les différents états. Par exemple, dans un fichier 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>

Je ne l'ai pas essayé, mais vous pouvez éventuellement définir android: background de LinearLayout sur ce sélecteur, et définir android: clickable sur true et cela fonctionnera.

Si ce n'est pas le cas, vous pouvez passer à l'utilisation d'un RelativeLayout et faire du premier élément un bouton avec ce sélecteur en arrière-plan et fill_parent pour sa largeur et sa hauteur de disposition. Dans ce cas, utilisez simplement un bouton standard et définissez android: background sur votre sélecteur. Vous n'êtes pas obligé de mettre du texte sur votre bouton.

Tenfour04
la source
Ouais, je vote pour utiliser un réel Button. Vous pouvez remplacer onDraw(Canvas)pour faire toutes les choses spéciales dont vous avez besoin (par exemple, dessiner des images ou du texte dans le bouton).
Dave
1
Merci! La définition de l'arrière-plan du LinearLayout fonctionne et il répond aux événements tactiles, presque - si j'appuie directement sur LinearLayout, son état est mis à jour. Si j'appuie sur le TextView à l'intérieur, l'événement tactile ne semble pas le rattraper au LinearLayout. Une idée comment faire le test de mise en page?
Jason Prado
Essayez Android: clickable = "false" sur TextView. Je n'ai pas essayé cela, mais je n'ai pas eu de problème en cliquant sur TextViews. C'est peut-être parce que votre TextView a un arrière-plan.
Tenfour04
Cela a fait l'affaire, même si cela ne fait pas le clic. Y a-t-il un moyen de le faire faire?
Steven
@Steven Je viens de voir votre ancien commentaire, désolé. Je pense que le son du clic est lié à l'attribution d'un onClickListener. J'avais quelque chose avec un onTouchListener et il ne cliquait pas jusqu'à ce que j'aie également ajouté un onClickListener (avec une méthode onClick vide).
Tenfour04
7

Dans l'application sur laquelle je travaille, j'ai besoin de créer un LinearLayout de manière dynamique. Dans ce cas, la commande

ll.setClickable(true);

ne fonctionne pas comme prévu. Bien que je puisse manquer quelque chose, j'ai réussi à exploiter setOnTouchListener pour obtenir le même résultat et je soumets le code au cas où quelqu'un aurait les mêmes besoins.

Le code suivant crée un LinearLayout avec deux vues de texte et des coins arrondis, changeant de couleur lorsque vous appuyez sur.

Tout d'abord, créez deux fichiers xml dans un dossier dessinable, un pour l'état normal et un pour l'état de disposition linéaire pressé.

XML à l'état normal (drawable / round_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>

Etat pressé xml (drawable / round_edges_pressed.xml). La seule différence réside dans la couleur ...

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

Ensuite, le code suivant fait le travail

Variable globale:

public int layoutpressed = -1;

Dans 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;
                }
  });           
Épaminondas
la source
6

Définissez simplement ces attributs

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

Ajoutez simplement un arrière-plan attr / selectableItemBackground à la disposition linéaire et rendez également cette disposition linéaire cliquable

exemple :

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

Cela permet à la disposition linéaire d'agir comme un bouton lorsqu'elle est enfoncée. :)

Exel Staderlin
la source
1

Cela a été utile, mais si vous souhaitez mettre une couleur d'arrière-plan et rendre la mise en page linéaire cliquable comme l'élément de liste. Définissez l'arrière-plan avec votre couleur préférée et définissez la couleur de premier plan sur? Android: attr / selectableItemBackground, définissez focusable true et clickable true

exemple de code

   <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
la source
0

Les réponses précédentes portaient sur la façon de définir l'arrière-plan par défaut dans un fichier xml. Voici la même chose dans le code:

linearLayout1.setBackgroundResource(android.R.drawable.list_selector_background);
yuliskov
la source