Стандартный ProgressBar, как известно, является индикатором выполнения длительных процессов. Однако, его часто используют для наглядного отображения численных величин. К сожалению, этот элемент не поддерживает метода setText(), чтобы поместить на него надпись, поясняющую показываемую величину, что значительно экономило бы экранное пространство. Вспомните адресную строку в стандартном браузере, где позади URI отображается зелёная шкала, отображающая ход загрузки страницы. Как же реализовать такое поведение?
Под катом — один из вариантов решения этой задачи.
Итак, постановка задачи: реализовать элемент, который бы выполнял функции ProgressBar с горизонтальным стилем (style="@android:style/Widget.ProgressBar.Horizontal"), а также имел бы возможность размещать поверх себя текст.
Краткий план действий:
Нам потребуется двухслойный Drawable, который будет отвечать за графическое наполнение элемента.
В папке res/drawable создаём файл background.xml со следующим содержанием:
Как видно из кода, фон состоит из двух слоёв: первый отвечает за контейнер создаваемой шкалы, а второй — собственно за шкалу, которая будет характеризовать отображаемую величину. Оба представляют из себя скруглённые прямоугольники, залитые серым и жёлтым градиентом. Однако второй shape заключён в тег clip, а это значит, что показываться будет лишь его часть.
Хитрость описываемого метода состоит в том, что расширять мы будем не класс ProgressBar, а класс TextView. Ключевым моментом является создание метода, который бы прорисовывал новый фон и устанавливал новую надпись.
Метод setValue() устанавливает текст надписи элемента с помощью стандартной функции setText(), а затем изменяет фоновый рисунок в соответствии с новым значением. Для этого используется метод setLevel(), которому в качестве параметра передаётся величина от 0 (шкала не видна) до 10000 (шкала закрывает 100% контейнера).
Для удобства в классе также создан метод setMaxValue(), позволяющий задать значение, соответствующее полной шкале. Таким образом, можно определить диапазон возможных значений, отображаемых элементом.
В папке res/layout модифицируем содержание файла main.xml, отвечающего за внешний вид основного Activity.
Здесь мы указываем, что фоном элемента будет созданный нами Drawable с именем background (описан в background.xml), ну и не забываем прописать id, по которому будет осуществляться его поиск внутри Activity.
Не забываем правильно указать пространство имён, в котором был создан класс AdvancedTextView. В данном примере это ru.habrahabr.widgets.
Внедрение и использование элемента в программе является простым и понятным:
Результатом будет вот такой элемент:
Итак, используя собственный Drawable для прорисовки фона и класс, расширяющий TextView, мы получили возможность использовать шкалу выполнения процесса с поясняющей надписью на переднем плане.
Под катом — один из вариантов решения этой задачи.
Итак, постановка задачи: реализовать элемент, который бы выполнял функции ProgressBar с горизонтальным стилем (style="@android:style/Widget.ProgressBar.Horizontal"), а также имел бы возможность размещать поверх себя текст.
Краткий план действий:
- Создать Drawable, отвечающий за прорисовку фона.
- Создать класс, расширяющий TextView, и прописать необходимые методы.
- Внедрить созданный элемент в Layout.
- Использовать элемент в Activity.
Создание Drawable
Нам потребуется двухслойный Drawable, который будет отвечать за графическое наполнение элемента.
В папке res/drawable создаём файл background.xml со следующим содержанием:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/bar_background">
<shape>
<corners android:radius="2dp" />
<gradient android:startColor="#666666"
android:centerColor="#111111"
android:endColor="#555555"
android:centerY="0.75"
android:angle="270" />
</shape>
</item>
<item android:id="@+id/bar_value">
<clip>
<shape>
<corners android:radius="2dp" />
<gradient android:startColor="#cfb73f"
android:centerColor="#635a30"
android:endColor="#918030"
android:centerY="0.75"
android:angle="270" />
</shape>
</clip>
</item>
</layer-list>
Как видно из кода, фон состоит из двух слоёв: первый отвечает за контейнер создаваемой шкалы, а второй — собственно за шкалу, которая будет характеризовать отображаемую величину. Оба представляют из себя скруглённые прямоугольники, залитые серым и жёлтым градиентом. Однако второй shape заключён в тег clip, а это значит, что показываться будет лишь его часть.
Создание класса
Хитрость описываемого метода состоит в том, что расширять мы будем не класс ProgressBar, а класс TextView. Ключевым моментом является создание метода, который бы прорисовывал новый фон и устанавливал новую надпись.
public class AdvancedTextView extends TextView {
// Максимальное значение шкалы
private int mMaxValue = 100;
// Конструкторы
public AdvancedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AdvancedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AdvancedTextView(Context context) {
super(context);
}
// Установка максимального значения
public void setMaxValue(int maxValue){
mMaxValue = maxValue;
}
// Установка значения
public synchronized void setValue(int value) {
// Установка новой надписи
this.setText(String.valueOf(value));
// Drawable, отвечающий за фон
LayerDrawable background = (LayerDrawable) this.getBackground();
// Достаём Clip, отвечающий за шкалу, по индексу 1
ClipDrawable barValue = (ClipDrawable) background.getDrawable(1);
// Устанавливаем уровень шкалы
int newClipLevel = (int) (value * 10000 / mMaxValue);
barValue.setLevel(newClipLevel);
// Уведомляем об изменении Drawable
drawableStateChanged();
}
}
Метод setValue() устанавливает текст надписи элемента с помощью стандартной функции setText(), а затем изменяет фоновый рисунок в соответствии с новым значением. Для этого используется метод setLevel(), которому в качестве параметра передаётся величина от 0 (шкала не видна) до 10000 (шкала закрывает 100% контейнера).
Для удобства в классе также создан метод setMaxValue(), позволяющий задать значение, соответствующее полной шкале. Таким образом, можно определить диапазон возможных значений, отображаемых элементом.
Редактирование Layout
В папке res/layout модифицируем содержание файла main.xml, отвечающего за внешний вид основного Activity.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="wrap_content">
<ru.habrahabr.widgets.AdvancedTextView
android:id="@+id/advanced_text_view"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/background"
android:layout_margin="4dp" />
</LinearLayout>
Здесь мы указываем, что фоном элемента будет созданный нами Drawable с именем background (описан в background.xml), ну и не забываем прописать id, по которому будет осуществляться его поиск внутри Activity.
Не забываем правильно указать пространство имён, в котором был создан класс AdvancedTextView. В данном примере это ru.habrahabr.widgets.
Использование элемента в Activity
Внедрение и использование элемента в программе является простым и понятным:
AdvancedTextView advancedTextView = (AdvancedTextView) findViewById(R.id.advanced_text_view);
advancedTextView.setValue(42);
Результатом будет вот такой элемент:
Заключение
Итак, используя собственный Drawable для прорисовки фона и класс, расширяющий TextView, мы получили возможность использовать шкалу выполнения процесса с поясняющей надписью на переднем плане.