Освой Android играючи

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

Шкодим

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

ProgressBar - Индикатор прогресса

Progress Cat

Основы
Стилизация
Индикатор с текстом
Программное создание индикатора

Основы

Компонент ProgressBar (Индикатор прогресса) применяется в тех случаях, когда пользователю нужно показать, что программа не зависла, а выполняет продолжительную работу.

Находится в категории Widgets.

Студия предлагает несколько видов индикаторов: ProgressBar и ProgressBar (Horizontal). В свою очередь компонент имеет несколько модификаций и их отличия заложены в стилях, если посмотреть XML-описание компонентов. Стили постоянно меняются, поэтому проще выбрать атрибут style и посмотреть предлагаемые варианты из выпадающего списка на текущий момент.

Методы для работы с ProgressBar:

  • setProgress() — устанавливает заданное значение индикатора прогресса;
  • getProgress() — возвращает текущее значение индикатора прогресса;
  • incrementProgressBy() — устанавливает величину дискретизации приращения значения индикатора;
  • setMax() — устанавливает максимальное значение величины прогресса.

Круговые индикаторы Normal, Small и Large можно просто разместить на экране, и они будут бесконечно выводить анимацию вращения без единой строчки кода.

Как правило, "бесконечный" индикатор выводят в нужный момент, а когда задача выполнена, то его скрывают. Видимость можно установить через XML и программно.


<ProgressBar
  android:id="@+id/progressBar"
  android:visibility="invisible"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

В коде используется метод setVisibility()


ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setVisibility(ProgressBar.VISIBLE);
// запускаем длительную операцию
progressBar.setVisibility(ProgressBar.INVISIBLE);

Сейчас проекты в студии используют Material Design, поэтому цвет индикатора будет соответствовать ресурсу colorAccent.

Можно переопределить цвет, если вы хотите отказаться от этой связи с colorAccent, задав свой стиль.


<style name="CircularProgress" parent="Theme.AppCompat.Light">
    <item name="colorAccent">@android:color/holo_green_light</item>
</style>

Подключаем через тему.


<ProgressBar
    ...
    android:theme="@style/CircularProgress" />

Другая настройка связана с Tint - оттенками цвета (Android 5.0).


<ProgressBar
    android:indeterminateTintMode="src_in"
    android:indeterminateTint="@color/my_color"/>

Стилизация

Если вам не нравится внешний вид стандартных индикаторов, то можете придумать свой. Есть два варианта для реализации этой цели. В первом случае можно подготовить готовый png-файл (spin_custom.png) и поместить его в ресурс, например, в папку res/drawable.

Custom Spin

Затем в этой же папке создаём xml-файл spinner_png.xml с таким содержанием:


<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/spin_custom"
    android:pivotX="50%"
    android:pivotY="50%" />

Теперь в разметке активности можно определять ProgressBar так:


<ProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:indeterminateDrawable="@drawable/spinner_png"
    android:indeterminateOnly="true" />

Если запустить проект, то увидим такой индикатор:

В реальности индикатор выглядит немного корявым, подёргиваясь на экране. Кроме того, изображение можно улучшить, уменьшив количество цветов и сократив размер файла.

Второй вариант выглядит предпочтительней. На этот раз мы обойдёмся без графических файлов, а будем использовать только XML-разметку. В этой же папке поместим файл spinner_ring.xml следующего содержания:


<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX="50%"
    android:pivotY="50%" >

    <shape
        android:innerRadiusRatio="4"
        android:shape="ring"
        android:thicknessRatio="5.333"
        android:useLevel="false" >
        <size
            android:height="18dip"
            android:width="18dip" />

        <gradient
            android:centerColor="#886688cc"
            android:centerY="0.50"
            android:endColor="#ff6688cc"
            android:startColor="#006688cc"
            android:type="sweep"
            android:useLevel="false" />
    </shape>

</animated-rotate>

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


<ProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="20dip"
    android:indeterminateDrawable="@drawable/spinner_ring"
    android:indeterminateOnly="true" />

Получим следующий результат:

Индикатор с текстом

К сожалению, индикатор не выводит текст во время работы, что не очень удобно. Можно создать свой ProgressBar из TextView или создать свой компонент на основе ProgressBar. Другой простой способ - наложить текстовый блок прямо на индикатор, используя RelativeLayout. Пример для пояснения.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <RelativeLayout
        android:id="@+id/rl_progress_bar_set"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn_start"
        android:visibility="visible" >

        <ProgressBar
            android:id="@+id/pb_horizontal"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:max="100" />

        <TextView
            android:id="@+id/tv_progress_horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@id/pb_horizontal"
            android:background="@android:color/transparent"
            android:gravity="center" />

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_below="@id/pb_horizontal"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp" >

            <ProgressBar
                style="@android:style/Widget.ProgressBar.Large"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:background="@android:color/background_dark" />

            <TextView
                android:id="@+id/tv_progress_circle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:background="@android:color/transparent"
                android:gravity="center"
                android:textColor="@android:color/white" />
        </RelativeLayout>
    </RelativeLayout>

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
        android:onClick="onClick"
        android:text="Поехали"
        android:textSize="25dp" />

</RelativeLayout>

Код, чтобы увидеть работу индикатора. При каждом щелчке кнопки значение индикаторов увеличиваются на 10 процентов.


package ru.alexanderklimov.test;

import ...

public class MainActivity extends Activity {

	private int progress = 0;
	private ProgressBar pbHorizontal;
	private TextView tvProgressHorizontal;
	private TextView tvProgressCircle;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		pbHorizontal = (ProgressBar) findViewById(R.id.pb_horizontal);
		tvProgressHorizontal = (TextView) findViewById(R.id.tv_progress_horizontal);
		tvProgressCircle     = (TextView)findViewById(R.id.tv_progress_circle); 
	}

	public void onClick(View v) {
		progress = progress + 10;
		postProgress(progress);
	}

	private void postProgress(int progress) {
		String strProgress = String.valueOf(progress) + " %";
		pbHorizontal.setProgress(progress);
		
		if (progress == 0) {
			pbHorizontal.setSecondaryProgress(0);
		} else {
			pbHorizontal.setSecondaryProgress(progress + 5);
		}
		tvProgressHorizontal.setText(strProgress);
		tvProgressCircle.setText(strProgress);
	}
}

ProgressBar

Индикаторы прогресса также можно использовать в заголовках приложения у старых устройств, а также в ActionBar и ToolBar у новых устройств.

Компонент постоянно дорабатывается. Например, в Android 8 появились новые методы isAnimating(), getMin(), setMin().

Анимация ObjectAnimator

Можно подключить готовую анимацию для визуализации компонента.


private static final TimeInterpolator GAUGE_ANIMATION_INTERPOLATOR = new DecelerateInterpolator(2);
private static final int MAX_LEVEL = 100;
private static final long GAUGE_ANIMATION_DURATION = 5000;
private ProgressBar mProgressBar;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mProgressBar = findViewById(R.id.progressBar);
}

// По щелчку кнопки
public void onClick(View view) {
    ObjectAnimator animator = ObjectAnimator.ofInt(mProgressBar, "progress", 0, MAX_LEVEL);
    animator.setInterpolator(GAUGE_ANIMATION_INTERPOLATOR);
    animator.setDuration(GAUGE_ANIMATION_DURATION);
    animator.start();
}

Дополнительное чтение

Меняем стандартный индикатор через drawable - простой и быстрый способ.

Material ProgressBar - статья про создание собственного индикатора в стиле Material Design

Indeterminate - серия статей на тему создания индикаторов прогресса, ссылка на первую часть.

How to create your own progressBar in Android. – Medium

Make an android custom view, publish and open source.

Библиотеки

skydoves/ProgressView: A polished and flexible ProgressView, fully customizable with animations.

GitHub - nipun-birla/BoxLoaderView

GitHub - VladimirWrites/Lemniscate: An easy way to make your progress view nice and sleek.

yuriy-budiyev/circular-progress-bar: Circular progress bar

timqi/SectorProgressView: a simple progress prompt or chart widget of android using circle and a sector

kofigyan/StateProgressBar: Android library to realize the various states and transitions in a ProgressBar.

JustZak/DilatingDotsProgressBar: A customizable indeterminate progress bar

DreaminginCodeZH/MaterialProgressBar: Material Design ProgressBar with consistent appearance

castorflex/SmoothProgressBar

Todd-Davies/ProgressWheel

passsy/android-HoloCircularProgressBar

daimajia/NumberProgressBar

lsjwzh/MaterialLoadingProgressBar

amanjeetsingh150/CoolProgressViews: Android library with collection of cool progress views.

Подборка индикаторов

glomadrian/loading-balls: A highly configurable library to do loading progress with animated balls - анимация для длительных операций.
loading-balls

droidchef/tinglingsquares: A delightful progress animation

Индикатор прогресса в виде пирога. Домашняя страница FilipPudak/ProgressPieView

cdeange/RopeProgressBar: Android ProgressBar that "bends" under its own weight. Inspired by http://drbl.in/nwih

biodunalfet/SlidingSquaresLoader: A simple progress loader

Реклама