среда, 15 декабря 2010 г.

Создание атрибутов разметки для собственных компонентов в Android

Относительно недавно мы рассматривали способ, как писать собственые компоненты на примере VerticalProgressBar. Однако была в той реализации некоторая некрасивость: свойства компонента (такие как progress и max) можно было инициализировать только в коде:

mProgressBar = (VerticalProgressBar)findViewById(R.id.progress);
mProgressBar.setMax(100);
mProgressBar.setProgress(0);

А было бы лучше выставлять их прямо в XML-разметке. В этой статье мы разберем, как это делается.

Новых компонентов выдумывать не будем, рассмотрим тот же VerticalProgressBar.

Объявление атрибутов

Атрибуты объявляются в ресурсах. Создадим файл attrs.xml и добавим в него следующее содержимое:

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="VerticalProgressBar">
        <attr name="android:max" />
        <attr name="android:progress" />
    </declare-styleable>
</resources>

У атрибута есть название (name) и тип (format). В данном случае мы навесили на наш компонент два стандартных андроидовских атрибута. format для них указывать не нужно и даже вредно, т.к. возникнет ошибка "Attribute has already been defined". К слову, список стандартных атрибутов можно увидеть в исходниках андроида (~/base/core/res/res/values/public.xml)

Для полноты картины добавим еще два собственных атрибута — в которых можно будет задавать цвет прогресса:

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="VerticalProgressBar">
        <attr name="android:max" />
        <attr name="android:progress" />
        <attr name="proceedColor" format="color" />
        <attr name="finishedColor" format="color" />
    </declare-styleable>
</resources>

Тут уже все по-честному, format задается, а префикс android не пишется.

Чтение значений

Итак, атрибуты объявлены, нужно их как-то прочитать. Как известно, у View имеется конструктор со следующей сигнатурой:

View (Context context, AttributeSet attrs)

Он вызывается при создании компонента из XML-разметки. А в параметре attrs передаются все атрибуты, указанные в разметке для данного компонента. Отсюда-то мы и станем их читать:

VerticalProgressBar.java

public class VerticalProgressBar extends View 
{
    public VerticalProgressBar(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalProgressBar);

        mProgress = a.getInteger(R.styleable.VerticalProgressBar_android_progress, DEFAULT_PROGRESS);
        mMax = a.getInteger(R.styleable.VerticalProgressBar_android_max, DEFAULT_MAX);
        mProceedColor = a.getColor(R.styleable.VerticalProgressBar_proceedColor, DEFAULT_PROCEED_COLOR);
        mFinishedColor = a.getColor(R.styleable.VerticalProgressBar_finishedColor, DEFAULT_FINISHED_COLOR);
    }

    private static final int DEFAULT_PROGRESS = 0;
    private static final int DEFAULT_MAX = 100;
    
    private static final int REMAIN = Color.rgb(49, 49, 49);
    private static final int DEFAULT_PROCEED_COLOR = Color. rgb(22, 72, 237);
    private static final int DEFAULT_FINISHED_COLOR = Color.rgb(124, 209, 15);
    
    private int mProgress;
    private int mMax;
    
    private int mProceedColor;
    private int mFinishedColor;

    ...
}    

Использование

Теперь в XML-разметке активности можно писать вот так:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res/demo.verticalprogress"
    
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dip"
    >
<demo.verticalprogress.VerticalProgressBar android:layout_width="wrap_content" 
    android:layout_height="fill_parent" android:layout_marginRight="20dip"
    android:progress="50" android:max="90" />
    
<demo.verticalprogress.VerticalProgressBar android:layout_width="wrap_content"
    android:layout_height="fill_parent" android:layout_marginRight="20dip"
    android:progress="20" android:max="60" app:proceedColor="@color/yellow"/>
    
<demo.verticalprogress.VerticalProgressBar android:layout_width="wrap_content" android:layout_height="fill_parent"
    android:progress="60" android:max="60" app:finishedColor="@color/red"/>
    
</LinearLayout>

И наблюдать следующий результат:

Результат работы VerticalProgressBar

Заключение

Итак, мы рассмотрели, как навешивать на компонент произвольные атрибуты. Причем, как стандартные андроидские, так и собственные.

Исходники

Ссылки

2 комментария:

Антон комментирует...

Замечательный пост. Давно ждал новых сообщений от Вас. Спасибо.

Exelero комментирует...

Шикарный блог! Помогает мне в разработке.
Дарья, спасибо большое!