Ниже рассказывается как ��оздать кнопки в стиле Twitter Bootstrap для Android приложения. Данный стиль взят для примера что бы разобраться в концпеции создания собственных стилей. Пример кода выложен на github. Репозиторий будет попoлняться примерами для других элементов. Так что можно подписываться.


Android SDK предлагает несколько вариантов для создания собственных стилей.

Начнём с самого простого. Создададим кнопку на основе нескольких графических файлов отображающих отдельные состояни кнопок. (default, selected, focused, pressed и т.д.) Поддерживаются форматы .png, .jpg, или .gif.



Добавляем в активити код для кнопки.

<Button
                android:id="@+id/button_primary"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/default_margin"
                android:background="@drawable/button_primary_selector"
                android:text="Button"
                android:textColor="@android:color/white" />


В папке res/drawable создаём файл button_primary_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_selected="true" android:drawable="@drawable/button_primary_selected"/>
   <item android:state_pressed="true" android:drawable="@drawable/button_primary_pressed"/>
   <item android:state_focused="true" android:drawable="@drawable/button_primary_focused"/>
   <item android:drawable="@drawable/button_primary_normal"/>
</selector>


Этот файл делает роутинг графиков в зависимости от текущего состояния кнопки
Добавляем графики для каждого состояния кнопки в ту же папку. Расширение файла указывать не надо. Недостатком данного примера является невозможность динамического скалирования кнопок.

Использование формата Nine-Patch File

Решаем проблему скалирования элементов следующим образом. В случае кнопки нужны по крайней мере два png файла соответствующие нормальному и нажатому состояниям.
Исходный график нормального состояния для primary button

Конвертация происходит с помощью утилиты draw9patch. Её можно найти в ANDROID_SDK_HOME/tools/.
После запуска перетягиваем график в открывшееся окно. И по краю картинки помечаем пиксели входящие в скалируемого контента. Примерно так


Справа предлагается превью. Если результат удовлетворительный. Через меню сохраняем файл в папку drawable. Повторяем процедуру для графиков всех состояний кнопки.
Подключение кнопки происходит также как в предыдущем примере

Shape Drawable

Вместо графиков можно описывать элементы с помощью XML.
Пример селектора для двух состояний:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <gradient
                android:startColor="#002A80"
                android:endColor="#04C"
                android:angle="270" />
            <stroke
                android:width="1dp"
                android:color="#04C" />
            <corners
                android:radius="4dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
     <item>
        <shape>
            <gradient
                android:startColor="#006DCC"
                android:endColor="#04C"
                android:angle="270" />
            <stroke
                android:width="1dp"
                android:color="#04C" />
            <corners
                android:radius="4dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>        
    </item>
</selector>

При изменении состояния файл читается сверху вниз и первый элемент с подходящим статусом будет выполнен.
Последний элемент в данном примере будет выполнятся если состояние предыдущих элементов не соответствует состоянию кнопки.

Этот пример можно дополнить для отображения других состояний добавив элементы item с соответствующим атрибутом
Например для selected
...
android:state_selected="true"
...

Описание состояний можно также вынести в отдельные файлы. Например нажатая кнопка будет описываться так в файле button_primary_pressed.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:startColor="#04C"
                android:endColor="#006DCC"
                android:angle="270" />
            <stroke
                android:width="1dp"
                android:color="#04C" />
            <corners
                android:radius="4dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>

В селекторе расширение (.xml) также не указывается.

Вместо StateList можно также использоват�� LayerList. Этот подход отличается от предудыщего тем что элементы не имеют атрибута состояния. Все элементы будут отработаны. Последний элемент отрисовывается сверху.

Пример:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
      <bitmap android:src="@drawable/android_red"
        android:gravity="center" />
    </item>
    <item android:top="10dp" android:left="10dp">
      <bitmap android:src="@drawable/android_green"
        android:gravity="center" />
    </item>
    <item android:top="20dp" android:left="20dp">
      <bitmap android:src="@drawable/android_blue"
        android:gravity="center" />
    </item>
</layer-list>


В результате получаем


Примеры кода для создания стиля кнопок с помощью StateList и Shape Drawable можно посмотреть здесьandroid-custom-style-ui.

Дополнительная информация и источники можно найти здесь.