Заставляем LinearLayout действовать как кнопка

100

У LinearLayoutменя есть стиль, который я стилизовал под a button, и он содержит несколько элементов text / ImageView. Я хотел бы сделать все LinearLayoutдействие как a button, в частности, чтобы дать ему состояния, которые определены в a, чтобы у него был другой фон при нажатии.

Есть ли лучший способ, чем задать ImageButtonразмер всего макета и разместить его в абсолютном размере?

Джейсон Прадо
источник
В случае , если кто - то ищет способ , чтобы выделить строку таблицы (которая наследуется от LinearLayout) на прессе (например , кнопки), см stackoverflow.com/a/8204768/427545
Lekensteyn
1
Если кто-то хочет получить полное решение, проверьте этот репозиторий: github.com/shamanland/AndroidLayoutSelector, там есть настраиваемые кликабельные / проверяемые, LinearLayoutкакToggleButton
Алексей К.

Ответы:

154

Я столкнулся с этой проблемой только сейчас. Вам нужно будет сделать LinearLayout интерактивным. Вы можете сделать это в XML с помощью

android:clickable="true"

Или в коде с

yourLinearLayout.setClickable(true);

Ура!

Рокманинов
источник
2
Ответ ниже намного лучше!
Зак Сперске,
2
Кроме того, если у вас есть «кликабельный» элемент в качестве его дочернего элемента, не забудьте добавить android:clickable="false"к нему, чтобы он не блокировал события клика.
TheKalpit
не обязательно, мне было достаточно добавления прослушивателя кликов, и если вы не хотите, чтобы слушатель кликов был активным?
hmac
158

Если вы хотите добавить фоновое поведение Android по умолчанию, чтобы сделать Layoutдействия как «кликабельные» View, установите для цели Layout:

API 11+ (чистый Android):

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

API 7+ (библиотека поддержки Android + AppCompat):

android:background="?attr/selectableItemBackground"

Любой API:

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

Ответы выше по-прежнему верны, но мне не помогли просто добавить состояние пользовательского интерфейса по умолчанию нажата и отпущена (например, как в a ListView).

FabiF
источник
+1 для вас, это замечательно, если вы хотите получить обратную связь с пользовательским интерфейсом, но хотите обрабатывать логику кликов самостоятельно (и не должны быть вынуждены указывать метод onClickX, который требуется android: clickable)
Рик Баркхаус,
2
Это также работает с рябью материального дизайна. Лучший ответ.
Миро Маркараванес
3
Хорошо! При нажатии получается оранжевый / желтый цвет как эффект нажатия. Я хочу изменить цвет на зеленый. Как это сделать?
Han Whiteking
@HanWhiteking ты узнал?
Якоб Санчес
16

Я использовал первый и второй ответ. Но в моем линейном макете есть изображения и текст с цветом фона, поэтому мне пришлось изменить «фон» на «передний план».

linearlayout

android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
Римский
источник
9

Сначала вам понадобится селектор для определения различных состояний. Например, в файле 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>

Я не пробовал, но вы можете установить для этого селектора LinearLayout android: background и установить android: clickable на true, и он будет работать.

Если этого не произойдет, вы можете переключиться на использование RelativeLayout и сделать первый элемент кнопкой с этим селектором в качестве фона и fill_parent для ширины и высоты макета. В этом случае просто используйте обычную кнопку и установите android: background в свой селектор. Вам не нужно помещать текст на кнопку.

Tenfour04
источник
Да, я голосую за использование актуального Button. Вы можете переопределить, onDraw(Canvas)чтобы делать любые специальные вещи, которые вам нужны (например, рисовать изображения или текст внутри кнопки).
Дэйв
1
Спасибо! Установка фона LinearLayout работает, и он почти реагирует на события касания - если я нажимаю LinearLayout напрямую, его состояние обновляется. Если я нажму внутри него TextView, событие касания не будет соответствовать LinearLayout. Есть идеи, как сделать хит-тест макета?
Джейсон Прадо
Попробуйте android: clickable = "false" в TextView. Не пробовал, но у меня не было проблем с просмотром TextViews. Возможно, это потому, что у вашего TextView есть фон.
Tenfour04,
Это сработало, хотя звук щелчка не издается. Есть ли способ заставить его это сделать?
Стивен
@Steven Только что видел ваш старый комментарий, извините. Я думаю, что звук щелчка связан с назначением onClickListener. У меня было что-то с onTouchListener, и он не щелкал, пока я не добавил onClickListener (с пустым методом onClick).
Tenfour04,
7

В приложении, над которым я работаю, мне нужно динамически создать LinearLayout. В этом случае команда

ll.setClickable(true);

работает не так, как предполагалось. Хотя я могу что-то пропустить, мне удалось использовать setOnTouchListener, чтобы получить тот же результат, и я отправляю код на случай, если у кого-то такие же потребности.

Следующий код создает LinearLayout с двумя текстовыми представлениями и скругленными углами, меняя цвет при нажатии.

Сначала создайте два XML-файла в папке с возможностью рисования, один для нормального и один для нажатого состояния linearlayout.

Нормальное состояние xml (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 (drawable / rounded_edges_pressed.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="#add8e6" />
            <corners android:radius="7dp" />
        </shape>
    </item>
</layer-list>

Затем следующий код выполняет свою работу

Глобальная переменная:

public int layoutpressed = -1;

В 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;
                }
  });           
Эпаминонд
источник
6

Просто установите эти атрибуты

<LinearLayout 
    ...
    android:background="@android:drawable/btn_default" 
    android:clickable="true"
    android:focusable="true"
    android:onClick="onClick"
    >
...
</LinearLayout>
Даниэль Де Леон
источник
5

Просто добавьте background attr / selectableItemBackground в линейный макет, а также сделайте этот linearlayout интерактивным.

пример :

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

Это заставляет linearlayout действовать как кнопка при ее нажатии. :)

Эксель Стадерлин
источник
1

Это было полезно, но если вы хотите установить цвет фона и сделать линейный макет интерактивным, как элемент списка. Установите желаемый цвет фона и установите цвет переднего плана на? Android: attr / selectableItemBackground, установите focusable true и clickable true.

образец кода

   <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"
        />
Джеб Эб
источник
0

Предыдущие ответы были о том, как установить фон по умолчанию в файле xml. Вот то же самое в коде:

linearLayout1.setBackgroundResource(android.R.drawable.list_selector_background);
Юлисков
источник