Pull to refresh

Разработка для Android: Добавляем текст на ProgressBar

Reading time4 min
Views11K
Стандартный ProgressBar, как известно, является индикатором выполнения длительных процессов. Однако, его часто используют для наглядного отображения численных величин. К сожалению, этот элемент не поддерживает метода setText(), чтобы поместить на него надпись, поясняющую показываемую величину, что значительно экономило бы экранное пространство. Вспомните адресную строку в стандартном браузере, где позади URI отображается зелёная шкала, отображающая ход загрузки страницы. Как же реализовать такое поведение?
Под катом — один из вариантов решения этой задачи.

Итак, постановка задачи: реализовать элемент, который бы выполнял функции ProgressBar с горизонтальным стилем (style="@android:style/Widget.ProgressBar.Horizontal"), а также имел бы возможность размещать поверх себя текст.

Краткий план действий:
  1. Создать Drawable, отвечающий за прорисовку фона.
  2. Создать класс, расширяющий TextView, и прописать необходимые методы.
  3. Внедрить созданный элемент в Layout.
  4. Использовать элемент в 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);


Результатом будет вот такой элемент:
image

Заключение


Итак, используя собственный Drawable для прорисовки фона и класс, расширяющий TextView, мы получили возможность использовать шкалу выполнения процесса с поясняющей надписью на переднем плане.
Tags:
Hubs:
Total votes 13: ↑10 and ↓3+7
Comments6

Articles