Custom Themes для Custom Widgets

от автора

Разрабатывая HoloEverywhere столкнулся с тем, что большинство присылаемых мне вопрос так или иначе относятся к тому, как стилизовать какие-либо виджеты.

То-есть народ особо не понимает сам принцип работы тем и аттрибутов.
Попробуем немного разжевать эту тему.

Для начала: что такое вообще стили? Набор значений для аттрибутов.
А где список этих аттрибутов, как получить их значения?
Styleable-ресурсы.

Давайте пока по старинке: создадим свою вьюху:

package habra.tutorial.customwidget;  import android.content.Context; import android.util.AttributeSet; import android.view.View;  public class HabraWidget extends View {     public HabraWidget(Context context) {         super(context);     }      public HabraWidget(Context context, AttributeSet attrs) {         super(context, attrs);     }      public HabraWidget(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);     } } 

Вы никогда не задумывались, что это за последний, третий, аргумент в конструкторе? int defStyle?

У вас будет время подумать, а мы пока создадим свой первый аттрибут, значение которого будет лежать в теме для Activity или даже для всего приложения…
Создаем values/attrs.xml (название не принципиальное, можно хоть в strings.xml)

<?xml version="1.0" encoding="utf-8"?> <resources> 	<attr name="habraWidgetStyle" format="reference" /> </resources> 

В Android имена аттрибутов для стилей для виджетов принято задавать именем виджета в camelCase + постфикс Style.
А format задает, как ни странно, формат значений. Оставим тут reference, т.е. ссылку на ресурc, в данном случае — на стиль.

Теперь модифицируем конструкторы нашего виджета. Сейчас они просто вызывают родительский конструктор.
И теперь фича defStyle — он задает имя аттрибута, по умолчанию будет использоваться значения из стиля, на который ссылается этот аттрибут.

    public HabraWidget(Context context) {         this(context, null);     }      public HabraWidget(Context context, AttributeSet attrs) {         this(context, attrs, R.attr.habraWidgetStyle);     } 

Т.е. конструктор HabraWidget(Context) будет вызывать HabraWidget(Context, AttributeSet) со вторым аргументов null,
а он в свою очередь вызывает HabraWidget(Context, AttributeSet, int) с нашим аттрибутом.

Теперь определимся, а что, собственно, наш виджет делать будет? Пусть он рисует простой крест из своих углов:

    private final Paint paint;      public HabraWidget(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         paint = new Paint();         paint.setColor(0xFF00EEFF);         paint.setStyle(Style.FILL_AND_STROKE);     }      @Override     protected void onDraw(Canvas canvas) {         canvas.drawLine(0, 0, getWidth(), getHeight(), paint);         canvas.drawLine(getWidth(), 0, 0, getHeight(), paint);     } 

Отлично, но цвет линии жестко указан в коде (0xFF00EEFF), вы думаете о том-же, о чем и я? Вынести в стили!
Сначала создадим styleable с аттрибутом… ну, скажем, lineColor:
attrs.xml

	<declare-styleable name="HabraWidget"> 		<attr name="lineColor" format="color|reference"/> 	</declare-styleable> 

И создадим дефолтовый стиль:
styles.xml

	<style name="HabraWidget"> 		<item name="lineColor">#f00</item> 	</style> 

И как теперь вытащить цвет?
TypedArray:

    public HabraWidget(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HabraWidget, defStyle,                 R.style.HabraWidget);         paint = new Paint();         paint.setColor(a.getColor(R.styleable.HabraWidget_lineColor, 0xFFFF0000));         paint.setStyle(Style.FILL_AND_STROKE);         a.recycle();     } 

0xFFFF0000 — дефолтный цвет. Можно и передавать какой-нибудь ноль, поскольку дефолтовую тему мы таки указали.
Ну и не забываем сделать recycle после того, как вытащили все данные.
Дальше особенность, касаемая создание layout. Мы привыкли, что все аттрибуты задаются через неймспейс android:.
Но поскольку наши аттрибуты не находятся в пакете android, то и неймспейс другой будет.
Приведу пример:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 	xmlns:habra="http://schemas.android.com/apk/res-auto" 	android:layout_width="match_parent" 	android:layout_height="match_parent" 	android:orientation="vertical" > 	<habra.tutorial.customwidget.HabraWidget 		android:layout_width="match_parent" 		android:layout_height="0dp" 		android:layout_weight="1" 		habra:lineColor="#00f" /> 	<habra.tutorial.customwidget.HabraWidget 		android:layout_width="match_parent" 		android:layout_height="0dp" 		android:layout_weight="1" 		habra:lineColor="#0f0" /> </LinearLayout> 

image

Теперь мы свободно можем задавать цвет линий из разметки.

ссылка на оригинал статьи http://habrahabr.ru/post/157393/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *