Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

ProgressBar из TextView

Стандартный ProgressBar, как известно, является индикатором выполнения длительных процессов. Однако, его часто используют для наглядного отображения численных величин. К сожалению, этот элемент не поддерживает метода setText(), чтобы поместить на него надпись, поясняющую показываемую величину, что значительно экономило бы экранное пространство. Как же реализовать такое поведение?

Итак, постановка задачи: реализовать компонент, который бы выполнял функции ProgressBar с горизонтальным стилем, а также имел бы возможность размещать поверх себя текст.

Краткий план действий:

  • Создать Drawable, отвечающий за прорисовку фона
  • Создать класс, расширяющий TextView, и прописать необходимые методы
  • Внедрить созданный элемент в разметку
  • Использовать элемент в активности

Создание 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: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(), позволяющий задать значение, соответствующее полной шкале. Таким образом, можно определить диапазон возможных значений, отображаемых элементом.

Редактирование Layout

Добавляем в разметку созданный компонент.


<?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.

Использование элемента в Activity

Внедрение и использование элемента в программе является простым и понятным:


@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	ProgressTextView progressTextView = (ProgressTextView) findViewById(R.id.progressTextView);
	progressTextView.setValue(49); // устанавливаем нужное значение
}

В результате получим такой элемент:

ProgressTextView

Итак, используя собственный Drawable для прорисовки фона и класс, расширяющий TextView, мы получили возможность использовать шкалу выполнения процесса с поясняющей надписью на переднем плане.

Реклама