- PVSM.RU - https://www.pvsm.ru -

Пишем свой Drawable для ProgressBar

Все началось с того, что необходимо было стилизовать ProgressBar в одном из приложений. Как известно в андройде для этого используются Drawable [1] объекты, описанные либо в виде XML, либо унаследованные от абстрактного класса Drawable [1], который входит в состав AndroidSDK. Про первый способ информации довольно много, а вот о втором — пойдет речь в данном посте.

Для начала создадим два класса CustomProgressDrawable и CustomProgressIndeterminateDrawable, для determinate и indeterminate состояний нашего прогресс бара соотвественно.

Начнем с CustomProgressDrawable:
В конструкторе созданим объект класса Paint [2], для того, чтобы в дальнейшем мы могли с помощью него рисовать на Canvas [3].

public CustomProgressDrawable(int color) {
    super();
    mPaint = new Paint();
    mPaint.setColor(color);
}

Далее переопределяем метод onLevelChange [4], именно этот метод вызывется, когда мы вызываем метод setProgress [5] у нашего объекта ProgressBar [6]. В конце метода вызываем метод invalidateSelf [7], который заставит наш Drawable [1] отрисоваться.

@Override
protected boolean onLevelChange(int level) {
    final  float drawTo = START_ANGLE + HALF_CIRCLE_DEGREES * level / (float)MainActivity.PROGRESS_MAX_VALUE;
    boolean update = drawTo != mDrawTo;
    mDrawTo = drawTo;
    invalidateSelf();

    return update;
}

Так как класс Drawable [1] является абстрактным, нам также будет необходимо реализовать все абстрактные методы данного класса, но их реализация довольно простая и ее в статье я опустил. Ниже есть ссылка на полный код примера.

Логику отрисовки реализуем в методе draw [8]:

@Override
public void draw(Canvas canvas) {
    canvas.rotate(CANVAS_1ST_ARC_ROTATE_DEGREES, getBounds().centerX(), getBounds().centerY());
    mPaint.setStyle(Paint.Style.STROKE);
    canvas.drawOval(mBoundsF, mPaint);
    mPaint.setStyle(Paint.Style.FILL);
    canvas.drawArc(mInnerBoundsF, START_ANGLE, mDrawTo, true, mPaint);
    canvas.rotate(CANVAS_2ND_ARC_ROTATE_DEGREES, getBounds().centerX(), getBounds().centerY());
    canvas.drawArc(mInnerBoundsF, START_ANGLE, mDrawTo, true, mPaint);
}

Переходим к CustomProgressIndeterminateDrawable:
В целом логика реализации аналогична предыдущему классу, за исключением того, что вместо переопределения метода onLevelChange [4], нам необходимо имплементировать два интерфейса Animatable [9] и Runnable [10].

@Override
public void run() {
    invalidateSelf();
    scheduleSelf(this, AnimationUtils.currentAnimationTimeMillis());
}

@Override
public boolean isRunning() {
    return mIsRunning;
}

@Override
public void start() {
    if (!isRunning()) {
        mIsRunning = true;
        mStartTicks = AnimationUtils.currentAnimationTimeMillis();
        run();
    }
}

@Override
public void stop() {
    if (isRunning()) {
        unscheduleSelf(this);
        mIsRunning = false;
    }
}

Сама анимация происходит в методе run [11], сначала мы перерисовываем наш Drawable [1], вызывая метод invalidateSelf [7]. Затем, используя метод scheduleSelf [12] класса Drawable [1], вновь вызываем метод run [11].

Теперь, там где нам необходимо, инициализируем наши Drawable [1] и устанавливаем их обычному элементу ProgressBar [6], и далее работаем с ним через методы setProgress [5] и setIndeterminate [13].

final int color = getResources().getColor(R.color.green);

// initialize drawables
CustomProgressDrawable progressDrawable = new 
CustomProgressDrawable(color);
CustomProgressIndeterminateDrawable barIndeterminateDrawable = new 
CustomProgressIndeterminateDrawable(color);

// set drawables and max value
mCustomProgressBar = (ProgressBar) 
findViewById(R.id.custom_progress_bar);
mCustomProgressBar.setIndeterminateDrawable(barIndeterminateDrawable);
mCustomProgressBar.setProgressDrawable(progressDrawable);
mCustomProgressBar.setMax(PROGRESS_MAX_VALUE);

И вот, что в итоге у нас получилось:

image

Весь код на github тыц [14].


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/pesochnitsa/77279

Ссылки в тексте:

[1] Drawable: http://developer.android.com/reference/android/graphics/drawable/Drawable.html

[2] Paint: http://developer.android.com/reference/android/graphics/Paint.html

[3] Canvas: http://developer.android.com/reference/android/graphics/Canvas.html

[4] onLevelChange: http://developer.android.com/reference/android/graphics/drawable/Drawable.html#onLevelChange%28int%29

[5] setProgress: http://developer.android.com/reference/android/widget/ProgressBar.html#setProgress%28int%29

[6] ProgressBar: http://developer.android.com/reference/android/widget/ProgressBar.html

[7] invalidateSelf: http://developer.android.com/reference/android/graphics/drawable/Drawable.html#invalidateSelf%28%29

[8] draw: http://developer.android.com/reference/android/graphics/drawable/Drawable.html#draw%28android.graphics.Canvas%29

[9] Animatable: http://developer.android.com/reference/android/graphics/drawable/Animatable.html

[10] Runnable: http://developer.android.com/reference/java/lang/Runnable.html

[11] run: http://developer.android.com/reference/java/lang/Runnable.html#run%28%29

[12] scheduleSelf: http://developer.android.com/reference/android/graphics/drawable/Drawable.html#scheduleSelf%28java.lang.Runnable,%20long%29

[13] setIndeterminate: http://developer.android.com/reference/android/widget/ProgressBar.html#setIndeterminate%28boolean%29

[14] тыц: https://github.com/Artemych/custom-progress-drawables