Разрабатывая 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>
Теперь мы свободно можем задавать цвет линий из разметки.
Автор: Prototik