Освой программирование играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Стандартный ProgressBar, как известно, является индикатором выполнения длительных процессов. Однако, его часто используют для наглядного отображения численных величин. К сожалению, этот элемент не поддерживает метода setText(), чтобы поместить на него надпись, поясняющую показываемую величину, что значительно экономило бы экранное пространство. Как же реализовать такое поведение?
Итак, постановка задачи: реализовать компонент, который бы выполнял функции ProgressBar с горизонтальным стилем, а также имел бы возможность размещать поверх себя текст.
Краткий план действий:
Нам потребуется двухслойный 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:angle="270"
android:centerColor="#111111"
android:centerY="0.75"
android:endColor="#555555"
android:startColor="#666666" />
</shape>
</item>
<item android:id="@+id/bar_value">
<clip>
<shape>
<corners android:radius="2dp" />
<gradient
android:angle="270"
android:centerColor="#635a30"
android:centerY="0.75"
android:endColor="#918030"
android:startColor="#cfb73f" />
</shape>
</clip>
</item>
</layer-list>
Как видно из кода, фон состоит из двух слоёв: первый отвечает за контейнер создаваемой шкалы, а второй — собственно за шкалу, которая будет характеризовать отображаемую величину. Оба представляют из себя скруглённые прямоугольники, залитые серым и жёлтым градиентом. Однако второй shape заключён в тег clip, а это значит, что показываться будет лишь его часть.
Создавать элемент мы будем не из класса View, а из класса TextView, который является его подклассом. Ключевым моментом является создание метода, который бы прорисовывал новый фон и устанавливал новую надпись.
package ru.alexanderklimov.customviewdemo;
import android.content.Context;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.widget.TextView;
public class ProgressTextView extends TextView {
// Максимальное значение шкалы
private int mMaxValue = 100;
// Конструкторы
public ProgressTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ProgressTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ProgressTextView(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 (шкала не видна) до 100 (шкала закрывает 100% контейнера).
Для удобства в классе также создан метод setMaxValue(), позволяющий задать значение, соответствующее полной шкале. Таким образом, можно определить диапазон возможных значений, отображаемых элементом.
Добавляем в разметку созданный компонент.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ru.alexanderklimov.customviewdemo.ProgressTextView
android:id="@+id/progressTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="@drawable/background"
android:gravity="center" />
</LinearLayout>
Здесь мы указываем, что фоном элемента будет созданный нами Drawable с именем background (описан в background.xml), ну и не забываем прописать id.
Внедрение и использование элемента в программе является простым и понятным:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ProgressTextView progressTextView = (ProgressTextView) findViewById(R.id.progressTextView);
progressTextView.setValue(49); // устанавливаем нужное значение
}
В результате получим такой элемент:
Итак, используя собственный Drawable для прорисовки фона и класс, расширяющий TextView, мы получили возможность использовать шкалу выполнения процесса с поясняющей надписью на переднем плане.