Button (Кнопка)
Кнопка — один из самых распространенных элементов управления в программировании. Наследуется от TextView и является базовым классом для класса СompoundButton. От класса CompoundButton в свою очередь наследуются такие элементы как CheckBox, ToggleButton и RadioButton. В Android для кнопки используется класс android.widget.Button. На кнопке располагается текст и на кнопку нужно нажать, чтобы получить результат. Альтернативой ей может служить компонент ImageButton (android.widget.ImageButton), у которого вместо текста используется изображение.
В студии кнопка представлена компонентом Button в разделе Widgets. Управлять размером шрифта, цветом текста и другими свойствами можно через атрибут textAppearance, который задействует системные стили. Выпадающий список данного свойства содержит огромный перечень вариантов. Также вы можете вручную задать конкретные индивидуальные настройки через отдельные свойства.
Если вы растягиваете кнопку по всей ширине экрана (android:layout_width=»match_parent»), то дополнительно рекомендую использовать атрибут android:layout_margin (или родственные ему layout_marginRight и layout_marginLeft) для создания отступов от краев экрана (веб-мастера знакомы с этими терминами).
Так как кнопка является наследником TextView, то использует многие знакомые атрибуты: textColor, textSize и др.
Три способа обработки событий нажатий на кнопку
Если вы разместили на экране кнопку и будете нажимать на неё, то ничего не произойдёт. Необходимо написать код, который будет выполняться при нажатии. Существует несколько способов обработки нажатий на кнопку.
Первый способ — атрибут onClick
Относительно новый способ, специально разработанный для Android — использовать атрибут onClick (на панели свойств отображается как On Click):
Имя для события можно выбрать произвольное, но лучше не выпендриваться. Далее нужно прописать в классе активности придуманное вами имя метода, который будет обрабатывать нажатие. Метод должен быть открытым (public) и с одним параметром, использующим объект View. Вам нужно выучить пять слов для создания метода, а сам метод поместить в класс (если вы ещё путаетесь в структуре Java-кода, то вставьте метод перед последней фигурной скобкой):
Когда пользователь нажимает на кнопку, то вызывается метод onMyButtonClick(), который в свою очередь генерирует всплывающее сообщение.
Обратите внимание, что при подобном подходе вам не придётся даже объявлять кнопку через конструкцию (Button)findViewById(R.id.button1), так как Android сама поймёт, что к чему. Данный способ применим не только к кнопке, но и к другим элементам и позволяет сократить количество строк кода.
Второй способ — метод setOnClickListener()
Более традиционный способ в Java — через метод setOnClickListener(), который прослушивает нажатия на кнопку. Так как для начинающего программиста код может показаться сложным, то рекомендуется использовать подсказки студии. Вот как это будет выглядеть. Предположим, у вас на экране уже есть кнопка button. В коде вы объявляете её обычным способом:
Следующий шаг — написание метода для нажатия. Напечатайте имя элемента и поставьте точку button. — среда разработки покажет вам список доступных выражений для продолжения кода. Вы можете вручную просмотреть и выбрать нужный вариант, а можно продолжать набирать символы, чтобы ускорить процесс. Так как с нажатиями кнопок вам часто придётся работать, то запомните название его метода (хотя бы первые несколько символов) — набрав четыре символа (seto), вы увидите один оставшийся вариант, дальше можно сразу нажать клавишу Enter, не набирая оставшиеся символы. У вас появится строка такого вида:
Курсор будет находиться внутри скобок и появится подсказка OnClickListener l. Начинайте набирать new OnClickListener. Здесь также не обязательно набирать имя полностью. Набрав слово Oncl, вы увидете нужный вариант и снова нажимайте Enter. В результате вы получите готовую заготовку для обработки нажатия кнопки:
Теперь у вас есть рабочая заготовка и сразу внутри фигурных скобок метода onClick() вы можете писать свой код. Рекомендую потренироваться и набить руку в создании заготовки. Это не так сложно, и с практикой навык закрепится автоматически.
Как вариант, можно вынести код для OnClickListener в отдельное место, это удобно, когда кнопок на экране несколько и такой подход позволит упорядочить код. Удалите предыдущий пример и начните писать код заново. Принцип такой же, немного меняется порядок. В предыдущем примере мы сразу прописали в методе setOnClickListener слушателя new OnClickListener. с методом onClick(). Можно сначала отдельно объявить отдельную переменную myButtonClickListener:
Во время набора активно используйте подсказки через Ctrl+Space. Набрали несколько символов у первого слова и нажимайте эту комбинацию, набрали после слова new несколько символов и снова нажимайте указанную комбинацию — заготовка будет создана за несколько секунд, а вы избежите возможных опечаток.
У нас есть готовая переменная, и теперь, когда вы будете набирать код button.setOnClickListener, то вместо new OnClickListener впишите готовую переменную.
Для новичка описание может показаться сумбурным и не понятным, но лучше самостоятельно проделать эти операции и понять механизм.
Третий способ — интерфейс OnClickListener
Третий способ является родственным второму способу и также является традиционным для Java. Кнопка присваивает себе обработчика с помощью метода setOnClickListener (View.OnClickListener l), т.е. подойдет любой объект с интерфейсом View.OnClickListener. Мы можем указать, что наш класс Activity будет использовать интерфейс View.OnClickListener.
Опять стираем код от предыдущего примера. Далее после слов extends Activity дописываем слова implements OnClickListener. При появлении подсказки не ошибитесь. Обычно первым идёт интерфейс для диалогов, а вторым нужный нам View.OnClickListener.
Название вашего класса будет подчёркнуто волнистой красной чертой, щёлкните слово public и дождитесь появления красной лампочки, выберите вариант Implement methods. Появится диалоговое окно с выделенным методом onClick. Выбираем его и в коде появится заготовка для нажатия кнопки.
Метод будет реализован не в отдельном объекте-обработчике, а в Activity, который и будет выступать обработчиком. В методе onCreate() присвоим обработчик кнопке. Это будет объект this, т.е. текущий объект нашей активности.
На первых порах такой способ также покажется вам сложным и непонятным. Со временем и опытом понимание обязательно придёт.
Лично я рекомендую вам использовать первый способ, как самый простой и понятный. Использование второго и третьего способа дадут вам представление, как писать обработчики для других событий, так как кнопка может иметь и другие события. Например, кроме обычного нажатия существует долгое нажатие на кнопку (long click). Один из таких примеров с методом касания я привёл в конце этой статьи.
О том, как обрабатывать щелчки кнопки я написал отдельную статью Щелчок кнопки/Счетчик ворон. Также кнопки часто будут встречаться во многих примерах на сайте. Про обработку длительный нажатий можно прочитать в статье, посвященной ImageButton.
Плодитесь и размножайтесь — это про кошек, а не про кнопки
Когда у вас одна кнопка в окне, то у вас будет один метод, две кнопки — два метода и так далее. Если у вас несколько кнопок, то не обязательно для каждой прописывать свой метод, можно обойтись и одним, а уже в самом методе разделять код по идентификатору кнопки. Если вы посмотрите на код в предыдущих примерах, то увидите, что в методе присутствует параметр View, который и позволяет определить, для какой кнопки предназначен кусок кода:
Предположим, у вас есть три кнопки:
Как видите, мы сократили количество кода. Теперь у нас один обработчик onClick(), в котором прописаны действия для трёх кнопок.
Сделать кнопку недоступной
Иногда нужно сделать кнопку недоступной и активировать её при определённых условиях. Через XML нельзя сделать кнопку недоступной (нет подходящего атрибута). Это можно сделать программно через метод setEnabled():
Как альтернативу можете рассмотреть атрибут android:clickable, который позволит кнопке не реагировать на касания, но при этом вид кнопки останется обычным.
Сделать кнопку плоской
Стандартная кнопка на экране выглядит выпуклой. Но в некоторых случаях желательно использовать плоский интерфейс. Раньше для этих целей можно было использовать TextView с обработкой щелчка. Но теперь рекомендуют использовать специальный стиль borderlessButtonStyle:
Кнопка сохранит своё привычное поведение, будет менять свой цвет при нажатии и т.д.
С появлением Material Design добавились другие стили, например, style=»@style/Widget.AppCompat.Button.Borderless», который является предпочтительным вариантом. Попробуйте также style=»@style/Widget.AppCompat.Button.Borderless.Colored»
Коснись меня нежно
Если вы внимательно понаблюдаете за поведением кнопки, то увидите, что код срабатывает в тот момент, когда вы отпускаете свою лапу, извините, палец с кнопки. Для обычных приложений это вполне нормально, а для игр на скорость такой подход может оказаться слишком медленным. В подобных случаях лучше обрабатывать ситуацию не с нажатием кнопки, а с его касанием. В Android есть соответствующий слушатель OnTouchListener():
У метода onTouch() есть параметр MotionEvent, позволяющий более тонко определять касания экрана. Если произойдет событие, когда пользователь коснулся экрана, то ему будет соответствовать константа ACTION_DOWN. Соответственно, если пользователь уберёт палец, то нужно использовать константу ACTION_UP. Таким образом, можете расценивать щелчок кнопки как комбинацию двух событий — касания и отпускания.
Получить текст с кнопки
Навеяно вопросом с форума. Задача — получить текст кнопки в методе onClick(). У метода есть параметр типа View, у которого нет метода getText(). Для этого нужно привести тип к типу Button.
Если у вас несколько кнопок привязаны к методу onClick(), то щелчок покажет текст нажатой кнопки.
How to create custom buttons in Android?
In this blog, we’re going to see how to create custom buttons in android. Before going to create a custom button first, let’s discuss what is a button in android.
A Button is a Push-button that can be pressed by the user to act. The android.widget.button is a subclass of TextView class and CompoundButton is the subclass of the Button class. The button consists of text or an icon (or both text and an icon) that describes what action occurs when the user clicks it.
There are different types of attributes of a button that are used to create a button or make it visible for the user. We can find it by clicking this What is a button inAndoird.
We can create a button in the layout file in three ways using text, an icon, or both text and an icon:
<Button
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/button_text”
… />
<ImageButton
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:src=”@drawable/button_icon”
android:contentDescription=”@string/button_icon_desc”
… />
· With text and an icon, using the Button class with the android:drawableLeft attribute:
<Button
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/button_text”
android:drawableLeft=”@drawable/button_icon”
… />
Create Custom Buttons:
- Create an android project in Android Studio.
- First, we learn how to use android properties to customize the button background.
- In the first button, there is a property named android: layout_width, here we used this property as match_parent. This property is used to define the width of the view in full screen horizontally. And android: layout_height is used as wrap_content, it is used to display big enough to enclose its content only. Also, we used an android: layout_margin. It gives space to the layout from all sides. For highlighting the text we used background as colorPrimary.
<Button
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginTop=”20dp”
android:text=”Button 1"
android:textSize=”18sp”
android:background=”@color/colorPrimary”
android:textColor=”@android:color/white”/>
Output of the code snippet:
- In the second button, change the width of the button to 300dp. And set the background to black.
<Button
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Button 2"
android:textSize="18sp"
android:background="@android:color/black"
android:textColor="@android:color/white"/>
Output of the code snippet:
- In the third button, the layout width and height are set as much we need. Here width is 300dp and height is 80dp.
<Button
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:text="Button 3"
android:textSize="18sp"
android:background="@android:color/black"
android:textColor="@android:color/white"/>
Output of the code snippet:
- In the fourth button, let’s use a gradient background. For the gradient background, we need to create a drawable resource XML file inside the drawable directory (res > drawable > drawable resource file), and give the name of the file then paste the below code.
<?xml version=”1.0" encoding=”utf-8"?>
<shape xmlns:android=”http://schemas.android.com/apk/res/android"
android:shape=”rectangle”>
<gradient
android:startColor=”#E91E63"
android:centerColor=”#FF9191"
android:endColor=”#E978FF”
android:angle=”90"/><corners android:radius=”25dp”/>
</shape>
You can change the color, radius, and shape as per your requirement.
- Now set the background of the button as the drawable file name.
<Button
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:text="Button 4"
android:textSize="18sp"
android:background="@drawable/gradient_backgrnd"
android:textColor="@android:color/white"/>
Output of the code snippet:
- In the last button, set the width and height of the button as wrap_content and add some padding from all the sides to look good without the gradient background.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:padding="10dp"
android:text="Button 5"
android:textSize="18sp"
android:background="@android:color/black"
android:textColor="@android:color/white"/>
Output of the code snippet:
activity_main.xml
<?xml version=”1.0" encoding=”utf-8"?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android"
xmlns:tools=”http://schemas.android.com/tools"
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical”
tools:context=”.MainActivity2">
<Button
android:id=”@+id/button1"
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginTop=”20dp”
android:background=”@color/colorPrimary”
android:text=”Button 1"
android:textColor=”@android:color/white”
android:textSize=”18sp” />
<Button
android:id=”@+id/button2"
android:layout_width=”300dp”
android:layout_height=”wrap_content”
android:layout_marginTop=”20dp”
android:background=”@android:color/black”
android:text=”Button 2"
android:textColor=”@android:color/white”
android:textSize=”18sp” />
<Button
android:id=”@+id/button3"
android:layout_width=”300dp”
android:layout_height=”80dp”
android:layout_marginTop=”20dp”
android:background=”@android:color/black”
android:text=”Button 3"
android:textColor=”@android:color/white”
android:textSize=”18sp” />
<Button
android:id=”@+id/button4"
android:layout_width=”300dp”
android:layout_height=”80dp”
android:layout_marginTop=”20dp”
android:background=”@drawable/gradient_backgrnd”
android:text=”Button 4"
android:textColor=”@android:color/white”
android:textSize=”18sp” />
<Button
android:id=”@+id/button5"
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginTop=”20dp”
android:background=”@android:color/black”
android:padding=”10dp”
android:text=”Button 5"
android:textColor=”@android:color/white”
android:textSize=”18sp” />
MainActivity.java
package com.codewithgolap.fragment;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;public class MainActivity2 extends AppCompatActivity <
@Override
protected void onCreate(Bundle savedInstanceState) <
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Button button1 = findViewById(R.id.button1);
Button button2 = findViewById(R.id.button2);
Button button3 = findViewById(R.id.button3);
Button button4 = findViewById(R.id.button4);
Button button5 = findViewById(R.id.button5);
Output:
In this blog, I’m trying to give you a small idea of how to use the different attributes of the button view. You can change it as you want to use it in your code.
4.1: Buttons and clickable images
The user interface (UI) that appears on a screen of an Android-powered device consists of a hierarchy of objects called views. Every element of the screen is a view.
The View class represents the basic building block for all UI components. View is the base class for classes that provide interactive UI components, such as Button elements. Users tap these elements on a touchscreen or click them using a pointing device. Any element that users tap or click to perform an action is called a clickable element.
For an Android app, user interaction typically involves tapping, typing, using gestures, or talking. The Android framework provides corresponding user interface (UI) elements such as buttons, clickable images, menus, keyboards, text entry fields, and a microphone.
When designing an interactive app, make sure your app is intuitive; that is, your app should perform as your users expect it to perform. For example, when you rent a car, you expect the steering wheel, gear shift, headlights, and indicators to be in a certain place. Another example is that when you first enter a room, you expect the light switch to be in a certain place. Similarly, when a user starts an app, the user expects buttons and images to be clickable. Don't violate established expectations, or you'll make it harder for your users to use your app.
In this chapter you learn how to create buttons and clickable images for triggering actions.
Designing buttons
People like to press buttons. Show someone a big red button with a message that says "Do not press" and the person will probably press the button, just for the pleasure of pressing a big red button. (That the button is forbidden is also a factor.)
You use the Button class to make a button for an Android app. Buttons can have the following design:
- Text only, as shown on the left side of the figure below.
- Icon only, as shown in the center of the figure below.
- Both text and an icon, as shown on the right side of the figure below.
When the user touches or clicks a button, the button performs an action. The button's text or icon should provide a hint about what that action will be. (Buttons are sometimes called "push-buttons" in Android documentation.)
A button is usually a rectangle or rounded rectangle with a descriptive caption or icon in its center. Android Button elements follow the guidelines in the Android Material Design specification. (You learn more about Material Design in another lesson.)
Android offers several types of Button elements, including raised buttons and flat buttons as shown in the figure below. Each button has three states: normal, disabled, and pressed.
In the figure above:
- Raised button in three states: normal, disabled, and pressed
- Flat button in three states: normal, disabled, and pressed
Designing raised buttons
A raised button is an outlined rectangle or rounded rectangle that appears lifted from the screen—the shading around it indicates that it is possible to tap or click it. The raised button can show text, an icon, or both.
To use raised buttons that conform to the Material Design specification, follow these steps:
If your build.gradle (Module: app) file doesn't include the android.support:appcompat-v7 library, add it to the dependencies section:
In the snippet above, 26.1.0 is the version number. If the version number you specified is lower than the currently available library version number, Android Studio will warn you ("a newer version is available"). Update the version number to the one Android Studio tells you to use.
Make your Activity extend android.support.v7.app.AppCompatActivity :
In the figure above:
- Normal state: A raised Button .
- Disabled state: When disabled, the Button is dimmed out and not active in the app's context. In most cases you would hide an inactive Button , but there may be times when you would want to show it as disabled.
- Pressed state: The pressed state, with a larger background shadow, indicates that the Button is being touched or clicked. When you attach a callback to the Button (such as the android:onClick attribute), the callback is called when the Button is in this state.
Creating a raised button with text
Some raised Button elements are best designed as text, without an icon, such as a Save button, because an icon by itself might not convey an obvious meaning. The Button class extends the TextView class. To use it, add it to the XML layout:
The best practice with a text Button is to define a very short word as a string resource ( button_text in the example above), so that the string can be translated. For example, Save could be translated into French as Enregistrer without changing any of the code.
Creating a raised button with an icon and text
While a Button usually displays text that tells the user what the action is, a raised Button can also display an icon along with text.
Choosing an icon
To choose images of a standard icon that are resized for different displays, follow these steps:
- Expand app > res in the Project > Android pane, and right-click (or Command-click) the drawable folder.
- Choose New > Image Asset. The Configure Image Asset dialog appears.
- Choose Action Bar and Tab Icons in the drop-down menu. (For a complete description of this dialog, see Create app icons with Image Asset Studio.)
Click the Clipart: image (the Android logo) to select a clip art image as the icon. A page of icons appears as shown below. Click the icon you want to use.
Optional: Choose HOLO_DARK from the Theme drop-down menu to set the icon to be white against a dark-colored or black background.
Vector images of a standard icon are automatically resized for different sizes of device displays. To choose vector images, follow these steps:
- Expand app > res in the Project > Android pane, and right-click (or Command-click) the drawable folder.
- Choose New > Vector Asset for an icon that automatically resizes itself for each display.
- The Vector Asset Studio dialog appears for a vector asset. Click the Material Icon radio button, and then click the Choose button to choose an icon from the Material Design specification. (For a complete description of this dialog, see Add Multi-Density Vector Graphics.)
- Click Next after choosing an icon, and click Finish to finish. The icon name should now appear in the app > res > drawable folder.
Adding the button with text and icon to the layout
To create a button with text and an icon as shown in the figure below, use a Button in your XML layout. Add the android:drawableLeft attribute to draw the icon to the left of the button's text, as shown in the figure below:
Creating a raised button with only an icon
If the icon is universally understood, you may want to use it instead of text.
To create a raised button with just an icon or image (no text), use the ImageButton class, which extends the ImageView class. You can add an ImageButton to your XML layout as follows:
Changing the style and appearance of raised buttons
The simplest way to show a more prominent raised button is to use a different background color for the button. You can specify the android:background attribute with a drawable or color resource:
The appearance of your button—the background color and font—may vary from one device to another, because devices by different manufacturers often have different default styles for input controls. You can control exactly how your buttons and other input controls are styled using a theme that you apply to your entire app.
For instance, to ensure that all devices that can run the Holo theme will use the Holo theme for your app, declare the following in the <application> element of the AndroidManifest.xml file:
After adding the declaration above, the app will be displayed using the theme.
Apps designed for Android 4.0 and higher can also use the DeviceDefault public theme family. DeviceDefault themes are aliases for the device's native look and feel. The DeviceDefault theme family and widget style family offer ways for developers to target the device's native theme with all customizations intact.
For Android apps running on 4.0 and newer, you have the following options:
- Use a theme, such as one of the Holo themes, so that your app has the exact same look across all Android-powered devices running 4.0 or newer. In this case, the app's look does not change when running on a device with a different default skin or custom skin.
- Use one of the DeviceDefault themes so that your app takes on the look of the device's default skin.
- Don't use a theme, but you may have unpredictable results on some devices.
- If you're not familiar with Android's style and theme system, you should read Styles and themes.
- For information about using the Holo theme while supporting older devices, see the blog post Holo Everywhere.
- For a guide on styling and customizing buttons using XML, see Buttons in the Android developer documentation.
- For a comprehensive guide to designing buttons, see Buttons in the Material Design specification.
Designing flat buttons
A flat button, also known as a text button or borderless button, is a text-only button that looks flat and doesn't have a shadow. The major benefit of flat buttons is simplicity: a flat button doesn't distract the user from the main content as much as a raised button does. Flat buttons are useful for dialogs that require user interaction, as shown in the figure below. In this case, you want the button to use the same font and style as the surrounding text to keep the look and feel consistent across all the elements in the dialog.
Flat buttons have no borders or background, but they do change their appearance when they change to different states.
In the figure above:
- Normal state: In its normal state, the button looks just like ordinary text.
- Disabled state: When the text is dimmed out, the button is not active in the app's context.
- Pressed state: A background shadow indicates that the button is being tapped or clicked. When you attach a callback (such as the android:onClick attribute) to the button, the callback is called when the button is in this state.
To create a flat button, use the Button class. Add a Button to your XML layout, and apply "?android:attr/borderlessButtonStyle" as the style attribute:
Responding to button-click events
An event listener is an interface in the View class that contains a single callback method. The Android system calls the method when the user triggers the View to which the listener is registered.
To respond to a user tapping or clicking a button, use the event listener called OnClickListener , which contains one method, onClick() . To provide functionality when the user clicks, you implement this onClick() method.
For more about event listeners and other UI events, see Input events overview in the Android developer documentation.
Adding onClick() to the layout element
A quick way to set up an OnClickListener for a clickable element in your Activity code and assign a callback method is to add the android:onClick attribute to the element in the XML layout.
For example, a Button in the layout would include the android:onClick attribute:
When a user clicks the Button , the Android framework calls the sendMessage() method in the Activity :
The callback method for the android:onClick attribute must be public , return void , and define a View as its only parameter (this is the View that was tapped). Use the method to perform a task or call other methods as a response to the Button tap.
Using the button-listener design pattern
You can also handle the click event in your Java code using the button-listener design pattern, shown in the figure below. For more information on the "listener" design pattern, see Creating Custom Listeners.
Use the event listener View.OnClickListener , which is an interface in the View class that contains a single callback method, onClick() . The method is called by the Android framework when the view is triggered by user interaction.
The event listener must already be registered to the View in order to be called for the event. Follow these steps to register the listener and use it (refer to the figure below the steps):
- Use the findViewById() method of the View class to find the Button in the XML layout file:
- Get a new View.OnClickListener and register it to the Button by calling the setOnClickListener() method. The argument to setOnClickListener() takes an object that implements the View.OnClickListener interface, which has one method: onClick() .
- Override the onClick() method:
- Do something in response to the button click, such as perform an action.
Using the event listener interface for other events
Other events can occur with UI elements, and you can use the callback methods already defined in the event listener interfaces to handle them. The methods are called by the Android framework when the view—to which the listener has been registered—is triggered by user interaction. You therefore must set the appropriate listener to use the method. The following are some of the listeners available in the Android framework and the callback methods associated with each one:
- onClick() from View.OnClickListener : Handles a click event in which the user touches and then releases an area of the device display occupied by a View . The onClick() callback has no return value.
- onLongClick() from View.OnLongClickListener : Handles an event in which the user maintains touch on a View for an extended period. This method returns a boolean to indicate whether you have consumed the event, and the event should not be carried further. That is, return true to indicate that you have handled the event and the event should stop here. Return false if you have not handled the event, or if the event should continue to any other listeners.
- onTouch() from View.OnTouchListener : Handles any form of touch contact with the screen including individual or multiple touches and gesture motions, including a press, a release, or any movement gesture on the screen (within the bounds of the UI element). A MotionEvent is passed as an argument, which includes directional information, and it returns a boolean to indicate whether your listener consumes this event.
- onFocusChange() from View.OnFocusChangeListener : Handles when focus moves away from the current View as the result of interaction with a trackball or navigation key.
- onKey() from View.OnKeyListener : Handles when a key on a hardware device is pressed while a View has focus.
Using clickable images
You can turn any View , such as an ImageView , into a button by adding the android:onClick attribute in the XML layout. The image for the ImageView must already be stored in the drawable folder of your project.
For example, the following images in the drawable folder (icecream_circle.jpg, donut_circle.jpg, and froyo_circle.jpg) are defined for ImageView elements arranged in a LinearLayout :
Using a floating action button
A floating action button ( FloatingActionButton ), shown below as #1 in the figure below, is a circular button that appears to float above the layout.
You should use a floating action button only to represent the primary action for a screen. For example, the primary action for the Contacts app main screen is adding a contact, as shown in the figure above. A floating action button is the right choice if your app requires an action to be persistent and readily available on a screen. Only one floating action button is recommended per screen.
The floating action button uses the same type of icons that you would use for a button with an icon, or for actions in the app bar at the top of the screen. You can add an icon as described previously in "Choosing an icon for the button".
If you start your project or Activity with the Basic Activity template, Android Studio adds a floating action button to the layout file for the Activity . To create a floating action button yourself, use the FloatingActionButton class, which extends the ImageButton class. You can add a floating action button to your XML layout as follows:
- Floating action buttons, by default, are 56 x 56 dp in size. It is best to use the default size unless you need the smaller version to create visual continuity with other screen elements.
- You can set the mini size (30 x 40 dp) with the app:fabSize attribute: app:fabSize="mini"
- To set it back to the default size (56 x 56 dp): app:fabSize="normal"
For more design instructions involving floating action buttons, see Components– Buttons: Floating Action Button in the Material Design Spec.
Recognizing gestures
A touch gesture occurs when a user places one or more fingers on the touchscreen, and your app interprets that pattern of touches as a particular gesture, such as a tap, touch & hold, double-tap, fling, or scroll.
Android provides a variety of classes and methods to help you create and detect gestures. Although your app should not depend on touch gestures for basic behaviors (because the gestures may not be available to all users in all contexts), adding touch-based interaction to your app can greatly increase its usefulness and appeal.
To provide users with a consistent, intuitive experience, your app should follow the accepted Android conventions for touch gestures. The Gestures design guide shows you how to design common gestures in Android apps. For more code samples and details, see Using touch gestures in the Android developer documentation.
Detecting common gestures
If your app uses common gestures such as double tap, long press, fling, and so on, you can take advantage of the GestureDetector class for detecting common gestures. Use GestureDetectorCompat , which is provided as a compatibility implementation of the framework's GestureDetector class which guarantees the newer focal point scrolling behavior from Jellybean MR1 on all platform versions. This class should be used only with motion events reported for touch devices—don't use it for trackball or other hardware events.
GestureDetectorCompat lets you detect common gestures without processing the individual touch events yourself. It detects various gestures and events using MotionEvent objects, which report movements by a finger (or mouse, pen, or trackball).
The following snippets show how you would use GestureDetectorCompat and the GestureDetector.SimpleOnGestureListener class.
Creating an instance of GestureDetectorCompat
To use GestureDetectorCompat , create an instance ( mDetector in the snippet below) of the GestureDetectorCompat class, using the onCreate() method in the Activity (such as MainActivity ):
When you instantiate a GestureDetectorCompat object, one of the parameters it takes is a class that you must create, which is MyGestureListener in the snippet above. The class you create should do one of the following:
- Implement the GestureDetector.OnGestureListener interface to detect all standard gestures, or
- Extend the GestureDetector.SimpleOnGestureListener class, which you can use to process only a few gestures by overriding the methods you need.
SimpleOnGestureListener provides methods such as onDown() , onLongPress() , onFling() , onScroll() , and onSingleTapUp() .
Extending GestureDetector.SimpleOnGestureListener
Create the class MyGestureListener as a separate Activity (MyGestureListener ) to extend GestureDetector.SimpleOnGestureListener . Override the onFling() and onDown() methods to show log statements about the event:
Intercepting touch events
To intercept touch events, override the onTouchEvent() callback of the GestureDetectorCompat class:
Detecting all gestures
To detect all types of gestures, you need to perform two essential steps:
- Gather data about touch events.
- Interpret the data to see if it meets the criteria for any of the gestures your app supports.
The gesture starts when the user first touches the screen, continues as the system tracks the position of the user's finger or fingers, and ends when the system captures the event of the user's fingers leaving the screen. Throughout this interaction, an object of the MotionEvent class is delivered to onTouchEvent() , providing the details. Your app can use the data provided by the MotionEvent to determine if a gesture it cares about happened.
For example, when the user first touches the screen, the onTouchEvent() method is triggered on the View that was touched, and a MotionEvent object reports movement by a finger (or mouse, pen, or trackball) in terms of:
- An action code: Specifies the state change that occurred, such as a finger tapping down or lifting up.
- A set of axis values: Describes the position in X and Y coordinates of the touch and information about the pressure, size and orientation of the contact area.
The individual fingers or other objects that generate movement traces are referred to as pointers. Some devices can report multiple movement traces at the same time. Multi-touch screens show one movement trace for each finger. Motion events contain information about all of the pointers that are currently active even if some of them have not moved since the last event was delivered. Based on the interpretation of the MotionEvent object, the onTouchEvent() method triggers the appropriate callback on the GestureDetector.OnGestureListener interface.
Each MotionEvent pointer has a unique id that is assigned when it first goes down (indicated by ACTION_DOWN or ACTION_POINTER_DOWN) . A pointer id remains valid until the pointer eventually goes up (indicated by ACTION_UP or ACTION_POINTER_UP ) or when the gesture is canceled (indicated by ACTION_CANCEL ). The MotionEvent class provides methods to query the position and other properties of pointers, such as getX(int) , getY(int) , getAxisValue(int) , getPointerId(int) , and getToolType(int) .
The interpretation of the contents of a MotionEvent varies significantly depending on the source class of the device. On touchscreens, the pointer coordinates specify absolute positions such as view X/Y coordinates. Each complete gesture is represented by a sequence of motion events with actions that describe pointer state transitions and movements.
A gesture starts with a motion event with ACTION_DOWN that provides the location of the first pointer down. As each additional pointer goes down or up, the framework generates a motion event with ACTION_POINTER_DOWN or ACTION_POINTER_UP accordingly. Pointer movements are described by motion events with ACTION_MOVE . A gesture ends when the final pointer goes up as represented by a motion event with ACTION_UP , or when the gesture is canceled with ACTION_CANCEL .
To intercept touch events in an Activity or View , override the onTouchEvent() callback as shown in the snippet below. You can use the getActionMasked() method of the MotionEventCompat class to extract the action the user performed from the event parameter. ( MotionEventCompat is a helper for accessing features in a MotionEvent , which was introduced after API level 4 in a backwards compatible fashion.) This gives you the raw data you need to determine if a gesture you care about occurred:
You can then do your own processing on these events to determine if a gesture occurred.
Тайны кнопок в Android. Часть 1: Основы верстки
В своем цикле статей по разработке Android-приложений я хочу поделиться с вами интересными и полезными приемами верстки сложных элементов управления. Мы рассмотрим как базовые приемы верстки, так и продвинутые способы ее оптимизации, которые существенно облегчают развитие и сопровождение Android-приложений, экономят время и деньги.
Первая часть предназначена для начинающих разработчиков. Я покажу, как сделать достаточно сложную кнопку исключительно версткой, не применяя Java-кода, ни тем более собственных компонентов. Знание этих приемов верстки пригодится и при работе с другими компонентами Android. По ходу статьи я буду подробно пояснять, что означают те или иные константы, атрибуты, команды и тому подобное. Но я также буду давать ссылки на официальную документацию Google, где вы можете подробно изучить каждую тему. Данная статья обзорная, я не ставлю цели привести здесь всю документацию, переведенную на русский язык. Поэтому я рекомендую изучать официальные источники, в частности те статьи, ссылки на которые я привожу здесь.
Что мы хотим сделать в данной статье? Допустим, мы делаем приложение, позволяющее включать/выключать функцию телефонии на смартфоне, в приложении будет кнопка “вкл/выкл”. Мы создадим кнопку с нашим собственным фоном и рамкой со скругленными углами. Фон и рамка будут меняться, когда кнопка получает фокус или становится нажатой. У кнопки будет текстовое название и иконка, поясняющая назначение кнопки визуально. Цвет текста и иконки также будет меняться при нажатии. Что еще? Так как кнопки “вкл./выкл.” встречаются в приложениях довольно часто, в Android уже есть готовый функционал для хранения/изменения состояния. Мы будем использовать его вместо того, чтобы изобретать собственный велосипед. Но отображение этого состояния мы сделаем свое, чтобы оно подходило нам по стилю.
Выглядеть это будет примерно так:

По левому краю кнопки располагаем иконку. Текст кнопки выравниваем по вертикали по центру, а по горизонтали левому краю. Но при этом текст не должен оказаться поверх иконки. По правому краю кнопки выравниваем индикатор включенного или выключенного телефона. Пространство между текстом на кнопке и правой иконкой индикатора “тянется” при необходимости. При нажатии кнопки фон становится серым, а рамка и все элементы на кнопке становятся белыми.
Делать все это будем только версткой. Почему верстка, а не код? Правильно сверстанная страница может легко стилизоваться, то есть ее можно менять практически до неузнаваемости простой заменой стиля. Можно даже предлагать пользователю выбирать тот стиль, который ему больше по душе. Стили в Android — это аналог каскадных таблиц CSS в HTML.
Решения, выполненные версткой, обычно компактнее аналогичных решений, выполненных кодом, при этом меньше шансов допустить ошибку. И большинство сверстанных без применения кода страниц можно просматривать и отлаживать в режиме дизайн (то есть прямо в IDE), для этого не нужно запускать приложение, ожидать деплоя и т.п.
Создаем каркас приложения
Приступим к реализации. Для демонстрации я буду использовать Android Developer Tools (ADT), построенный на Eclipse.
Создадим новый проект. File->New->Android Application Project.
Application Name: MysteriesOfButtonsPart1
Project Name: MysteriesOfButtonsPart1
Package Name: com.mysteriesofbuttons.part1
Остальные параметры оставим по умолчанию: 
Next. На следующей странице для экономии времени позволим ADT создать для нас тестовую Activity: 
Next. Иконки оставим по умолчанию, в данном случае речь не о них.
Next. Создаем пустую Activity, то есть опять же все по умолчанию: 
Next. Имя Activity оставляем без измений: 
Finish. Наконец-то можем перейти к делу.
Простейшая кнопка
Начнем с кода Layout. Откроем файл /res/layout/activity_main.xml и заменим все его содержимое следующим кодом:
RelativeLayout — макет, в котором дочерние элементы размещаются относительно друг друга, например, расположить кнопку слева от другой кнопки и т.п. Подробнее о работе RelativeLayout можно почитать здесь.
Button — наша кнопка. Мы задаем ей атрибут android:id , по которому сможем идентифицировать ее в приложении. Формат @+id/ означает, что в ресурсах должен быть создан новый идентификатор. Если бы мы указали @id/ , то это бы означало, что в ресурсах указанный идентификатор уже должен быть.
А вот так мы задаем отображаемый пользователю текст: android:text=»Телефония»
Забегая вперед, скажу, что весь текст, который видит пользователь, должен храниться не в коде макетов страниц и не в Java-коде, а в ресурсах strings.xml , чтобы приложение могло поддерживать более одного языка, но об этом подробнее в следующей части. Пока что мы укажем текст прямо в макете, чтобы улучшить наглядность примера.
Как RelativeLayout , так и Button имеют атрибуты android:layout_width и android:layout_height . Это обязательные атрибуты любого View . Как следует из названия, они обозначают соответственно ширину и высоту элементов. Их можно задавать в различных единицах, но мы не используем конкретные размеры, как вы могли заметить. Мы используем константы match_parent и wrap_content .
match_parent означает, что элемент должен полностью заполнить своего родителя по горизонтали либо по вертикали, в зависимости от того, задаем ли мы ширину или высоту.
wrap_content означает, что размер элемента должен быть минимальным, но таким, чтобы все содержимое элемента в него поместилось.
Есть еще константа fill_parent , которая означает ровно то же самое, что и match_parent . Зачем использовать две одинаковых константы? fill_parent был введен до версии API 8, а с восьмой версии является устаревшим и не рекомендуется к использованию. Дело в том, что для англоязычных разработчиков match_parent точнее отражает смысл константы, чем fill_parent .
Я стараюсь использовать эти константы match_parent и wrap_content везде, где только возможно, всячески избегая указания фиксированных размеров, так как приложения Android работают на устройствах с сильно отличающимися размерами экранов.
Теперь, когда с основой окна разобрались, давайте перейдем к коду нашей Activity MainActivity.java :
В этом коде мы видим только одну имеющую смысл команду: setContentView(R.layout.activity_main);
Этот метод устанавливает ресурс макета страницы, с которым будет работать Activity.
Давайте запустим наше приложение и посмотрим, что получилось:
А теперь откроем в Eclipse файл activity_main.xml и нажмем кнопку Graphical Layout : 
Мы видим ту же кнопку с теми же размерами, в тех же цветах, что и на эмуляторе. Только чтобы это увидеть, нам не пришлось ждать запуска эмулятора и деплоя приложения. Сохранили время? Первый профит от верстки. В дальнейшем будем стараться обходиться без эмулятора, тестируя на нем не каждый шаг, а только готовую версию.
Стили текста
Теперь займемся выравниванием. Сейчас текст на кнопке выровнен по центру. Это стиль по умолчанию для кнопки. Но нам нужно выровнять текст по левому краю, сохранив выравнивание по центру по вертикали. Как это сделать? Добавим к кнопке атрибут android:gravity :
Этот атрибут может принимать одно или два значения, в нашем случае два. Значения разделяются вертикальной чертой |
Как это выглядит: 
О различных вариантах выравнивания и о том, что они означают, можно подробно почитать здесь
Попробуйте “поиграть” с этими вариантами и посмотреть, как это влияет на внешний вид кнопки. Если хотите сделать текст на кнопке жирным и/или курсивом, воспользуйтесь параметром android:textStyle , например android:textStyle=»bold|italic» . Если нужно изменить размер текста на кнопке, подойдет параметр android:textSize , например: android:textSize=»24sp» .
sp — Scale-independent Pixels — единица измерения, основанная на плотности экрана и на настройках размера шрифта. Чтобы текст выглядел одинаково хорошо на разных экранах, рекомендуется задавать его размер именно в sp .
Зададим эти параметры нашей кнопке:

Я предпочитаю оставлять стили ближе к значениям по умолчанию, так как они тщательно подбирались высоко оплачиваемыми дизайнерами, и с моим чувством вкуса я очень сомневаюсь, что смогу сделать лучше. Данный пример призван показать читателю как можно больше возможностей, и не претендует на звание произведения искусства, поэтому прошу не пинать за то, что раньше оно выглядело лучше.
Помещаем иконку на кнопку
Идем дальше. Теперь нам нужно добавить иконку на кнопку. Иконка задается следующим файлом icon_phone_normal.png :
кликните, чтобы скачать
Импортируем его в ресурсы приложения в каталог drawable-hdpi . Чтобы задать иконку кнопке, добавим ей атрибут android:drawableLeft :

Кроме android:drawableLeft , есть еще несколько атрибутов, которые позволяют задавать иконки, размещая их в других частях кнопки: android:drawableTop , android:drawableBottom , android:drawableRight , android:drawableStart , android:drawableEnd .
Как вы заметили, мы указали путь к иконке без расширения PNG , а также без суффикса -hdpi . Это не опечатка. Расширение никогда не указывается, так как в имени идентификатора не может быть точки. А суффикс -hdpi будет подставлен Android автоматически, так как это единственный каталог drawable , в котором есть иконка icon_phone_normal . Если бы иконка была не только в каталоге drawable-hdpi , но и в drawable-mdpi , к примеру, то Android выбрал бы наиболее полходящую для разрешения экрана того устройства, на котором запущено приложение. Так вы можете поставлять качественные продукты, одинаково хорошо выглядящие на устройствах с разным размером и плотностью экрана. О поддержке разных экранов у Google есть очень хорошая статья.
Собственный фон для кнопки
Теперь, когда мы разобрались с drawable-ресурсами, давайте заменим фон нашей кнопки на тот, который нам нужен. Для этого мы будем использовать такую картинку button_normal.png :
кликните, чтобы скачать
Импортируйте ее в drawable-hdpi . На картинке мы видим черные полоски вдоль каждой из границ экрана. Они служат для того, чтобы Android правильно растягивал картинку под нужный нам размер. Левая и верхняя линии показывают, какая область картинки будет растягиваться по вертикали и горизонтали соответственно. А правая и нижняя линии показывают, в какую область растянутой картинки нужно вписывать содержимое элемента, если у него есть дочерние элементы. При этом сами черные линии конечно же не видны на результирующей картинке.
Это называется nine-patch drawable, об этой технике верстки подробно можно почитать здесь
Чтобы ресурс считался 9-patch, в его имени перед расширением должна присутствовать девятка, отделенная от остального имени еще одной точкой, как у нас: button_normal.9.png
Как назначить элементу такой растягиваемый фон? Откроем текст нашей кнопки и добавим ей атрибут android:background :

Выглядит не очень красиво, так как кнопка “прижалась” к сторонам экрана вплотную. Это случилось потому, что в фоне по умолчанию, который мы сменили на наш собственный, рамка кнопки была нарисована с отступом, и этот отступ мы видели на предыдущих скриншотах. Мы также можем перерисовать фон кнопки, но можем задать отступ и другим способом, и хорошо бы сразу для всех элементов окна, чтобы не дублировать код для каждого. Для этого подойдет атрибут android:padding у тега RelativeLayout :

Что такое dp ? Density-independent pixel — мера, которая будет автоматически масштабироваться на устройствах с разной плотностью пикселей экрана так, чтобы элемент выглядел одинаково. Всегда используйте dp , а не px , когда необходимо задать конкретный размер, иначе приложение будет выглядеть хорошо только на вашем телефоне.
Атрибут android:padding задает одинаковые отступы со всех сторон. Если мы хотим задать разные отступы с каждой стороны отдельно, можем использовать атрибуты android:paddingLeft , android:paddingRight , android:paddingTop , android:paddingBottom , android:paddingStart и android:paddingEnd .
Рассмотренные нами до сих пор атрибуты есть не только у кнопки, но и у других элементов. Например, android:background есть у всех видимых элементов, android:drawableLeft — у TextEdit и так далее.
Идем дальше. Если запустить наше приложение, мы увидим, что при щелчке на кнопку ее внешний вид никак не меняется, то есть визуально не видно, нажата кнопка или нет. В таком виде оставлять нашу кнопку нельзя, так как пользователь не сможет понять, работает приложение, или нет.
Работаем с состояниями в Android
Здесь нам на помощь приходят состояния. Когда с кнопкой ничего не происходит, она находится в не нажатом состоянии. Если на кнопке находится фокус ввода, она переходит в состояние state_focused . Если нажать на кнопку пальцем, она будет находиться в состоянии state_pressed , пока мы не отпустим палец. Как это нам поможет? Мы можем задавать внешний вид элементов для каждого состояния отдельно. Дальше мы детально рассмотрим, как это делается. Обратите внимание, что состояние можно использовать для отрисовки всего, что видно пользователю: иконки, картинки, отдельные цвета и т.п.
Начнем с фона. Зададим для нашей кнопки красную рамку, когда она в фокусе, и рамку с инвертированными цветами, когда она нажата. Для этого импортируйте в каталог drawable-hdpi следующие изображения:
кликните, чтобы скачать
кликните, чтобы скачать
Теперь у нас есть 3 картинки фона на 3 состояния. Но атрибут android:background можно задать только один раз. Чтобы выйти из ситуации, мы создадим новый drawable-ресурс selector , объединяющий наши 3 картинки.
Щелкнем правой кнопкой мыши на каталоге drawable-hdpi , выберем New->Android XML File. Введем название файла button_background и выберем корневой элемент selector : 
Finish.
Мы получили заготовку следующего содержания:
Добавим в селектор картинки для состояния state_focused и state_pressed :
Обратите внимание, что для картинки button_normal состояние не указывается. Это означает, что такая картинка будет использована всегда, если кнопка не в состоянии state_focused или state_pressed . Кроме рассмотренных состояний можно использовать еще несколько, полный перечень описан здесь
Как работает селектор? Когда селектор назначен какому-то элементу, он постоянно получает состояние элемента-хозяина, и возвращает ему первый из перечисленных ресурсов, который соответствует состоянию владельца.
Откроем текст нашего макета activity_main.xml и заменим фон кнопки на button_background :
Также затемним фон всего окна, чтобы лучше видеть белую рамку нажатой кнопки:
Теперь, если запустить приложение на эмуляторе, и нажать кнопку, мы увидим, что она меняет свой фон: 
Изменяем иконку при нажатии
Уже неплохо, но можно и лучше. Давайте повторим процесс создания селектора для смены иконки телефона в нажатом состоянии. Импортируйте в drawable-hdpi иконку icon_phone_pressed.png :
кликните, чтобы скачать
Создайте селектор icon_phone со следующим текстом:
И в тексте кнопки замените drawableLeft на наш новый селектор icon_phone :

Изменяем цвет текста при нажатии
Теперь иконка меняется при нажатии на кнопку так же, как и фон. Осталось разобраться с цветом текста. Он пока что остается черным в любом состоянии. Если бы в нажатом виде текст тоже становился белым, как рамка и иконка, кнопка выглядела бы куда интереснее.
Управление цветом несколько отличается от картинок. Пойдем по порядку. Во-первых, цвета хранятся в отдельном каталоге, который мы должны создать. Добавим подкаталог color в каталоге res , на одном уровне с каталогом drawable-hdpi : 
Далее в каталоге color создадим Android XML File с именем text_color и корневым элементом selector : 
И заменим его содержимое следующим:
По аналогии с картинками, здесь задаются цвета для состояния state_pressed и состояния по умолчанию. Цвета здесь задаются двумя способами: android:color=»@android:color/white» и android:color=»#484848″
В первом случае мы используем заранее созданный цвет в пространстве имен android . Во втором — указываем RGB-значение цвета в шестнадцатиричной системе исчисления. В данном случае мы задали цвет по умолчанию такой же, как цвет рамки в ненажатом виде.
Теперь вернемся к исходнику нашей кнопки и пропишем цвет текста android:textColor=»@color/text_color» :
Теперь мы не можем видеть результат в Graphical Layout, это известная проблема плагина, которую, я надеюсь, Google когда-нибудь починит. К сожалению, тестировать цвета с состоянием можно только на эмуляторе или реальном устройстве.
На этом художественная часть верстки завершена. Сейчас кнопка выглядит так: 
Прикручиваем ToggleButton
Далее поговорим о том, как отображать состояние телефонии на кнопке (вкл/выкл). Мы помним, что у кнопки иконка может быть не только слева. Для отображения текущего состояния мы добавим кнопке иконку справа. Пусть это будет галочка для состояния Вкл и крестик для состояния Выкл. Как мы будем менять иконки? Самый очевидный вариант — это определить обработчик события OnClickListener и поочередно менять иконку drawableRight . Вполне рабочий вариант. Но что делать, если на странице не одна, а 10 кнопок, и вообще кнопка может быть не только на этой странице. Тогда наш путь приведет к дублированию кода, который будет копипастом кочевать из одной Activity в другую, не самое красивое решение. Да и если нужно будет что-то изменить, менять придется во многих местах. Хотелось бы этого избежать.
К счастью, Android предоставляет для этих целей специальный компонент — ToggleButton . Эта кнопка может находиться в двух состояниях: включено и выключено. Заменим в нашем макете тег Button на ToggleButton :
Так как ToggleButton наследуется от Button , к ней применимы все атрибуты Button , но есть нюанс. ToggleButton игнорирует атрибут text , зато вводит два новых: textOn и textOff . Они задают текст для включенного и выключенного состояний соответственно. Но мы хотим отображать состояние картинкой, а текст хотим оставить как есть. Поэтому пропишем наш текст обоим атрибутам, а атрибут text уберем за ненадобностью:
Теперь подготовим картинки для отображения состояния кнопки. Импортируйте в drawable-hdpi ресурсы icon_on_normal.png , icon_on_pressed.png , icon_off_normal.png и icon_off_pressed.png (представлены в порядке перечисления):
кликните, чтобы скачать
кликните, чтобы скачать
кликните, чтобы скачать
кликните, чтобы скачать
Внимание: белые иконки на прозрачном фоне не очень здорово видны в браузере на белом фоне.
Зачем четыре иконки? Вспомним, что мы хотим отображать все элементы кнопки белыми, когда пользователь удерживает кнопку нажатой. Поэтому для каждого состояния Вкл и Выкл мы должны дать по две иконки: в нажатом и отпущенном состоянии. Итого четыре.
Создадим новый drawable селектор с именем icon_on_off :
Здесь видно, что компонент может иметь сразу несколько состояний, например он может быть одновременно отмеченным и нажатым, или отмеченным и ненажатым и так далее.
android:state_checked=»true» соответствует кнопке в режиме Вкл, а android:state_checked=»false» — кнопке в режиме Выкл.
Теперь вернемся к нашей кнопке и добавим ей атрибут android:drawableRight=»@drawable/icon_on_off» . Для наглядности я добавил его сразу после android:drawableLeft :
Что у нас получится, если запустить приложение? Мы видим кнопку ненажатую, в режиме Выключено. При этом если ее нажать и держать, все элементы отображаются белым на сером фоне: 
Отпускаем кнопку, состояние меняется на Включено. Если нажать еще раз, снова увидим серый фон и белые иконки, после чего состояние опять будет Выключено: 
Именно то, что нам нужно.
Немного кода
На всякий случай давайте посмотрим, как можно в коде нашего приложения понять, включена кнопка или выключена. Для этого мы можем анализировать значение isChecked() кнопки: true — включена, false — выключена. Добавим атрибут android:onClick=»onToggleButtonClick» к нашей кнопке:
В MainActivity.java добавим соответствующий метод:
Запустив приложение и нажав кнопку, мы увидим внизу экрана текстовые подсказки true / false . А это значит, что все работает.
Заключение
Как видите, возможности верстки в Android весьма обширны: в данной статье весь функционал, кроме подсказок, реализован только версткой. Но это далеко не все.
В данной статье код XML намеренно оставлен неидеальным. Изучение базовых возможностей верстки и продвинутая оптимизация — это две разные темы. Конечно, настоящие гуру должны сразу писать оптимально. Но данная статья преследует учебные цели и рассчитана на начинающих разработчиков, поэтому я решил усложнять постепенно.