Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ProgressBar drawable work?

Background

I wanted to make a rounded progress bar that is determinate (meaning android:indeterminate="false"), so I searched the Internet and found a short answer of Romain Guy, here.

So I grabbed the code and used it in a sample project:

the (part of the) layout file:

<ProgressBar
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="@color/backColor"
    android:indeterminate="false"
    android:indeterminateOnly="false"
    android:max="100"
    android:progress="33"
    android:progressDrawable="@drawable/progress" />

drawable/progress.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<!--    <item android:drawable="@drawable/progress_circular_background"/> -->
    <item>
        <shape  
            android:innerRadiusRatio="3.4"
            android:shape="ring"
            android:thicknessRatio="6.0" >
            <gradient
                android:endColor="#ffffffff"
                android:startColor="#ff000000"  
                android:type="sweep"
                android:useLevel="true" />

        </shape>
    </item>

    <item>
        <rotate
            android:drawable="@drawable/progress_particle"
            android:fromDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="360" />
    </item>

</layer-list>

screenshots (not exactly of the current code) :

enter image description here

The question

It works fine, but I don't understand how it works.

How does the progress bar know what to change exactly on the drawables, and how ?

For example, how does it know how to take only the ring shape from 0 degrees on the right, and not from other places?

Is it possible to customize how it work?

like image 604
android developer Avatar asked May 28 '14 15:05

android developer


People also ask

What is the use of ProgressBar?

ProgressBars are used as loading indicators in android applications. These are generally used when the application is loading the data from the server or database. There are different types of progress bars used within the android application as loading indicators.

What is meant by ProgressBar describe with example?

We can display the android progress bar dialog box to display the status of work being done e.g. downloading file, analyzing status of work etc. In this example, we are displaying the progress dialog for dummy file download operation. Here we are using android. app. ProgressDialog class to show the progress bar.

What is difference between ProgressBar and SeekBar?

What is difference between ProgressBar and SeekBar? An example of SeekBar is your device's brightness control and volume control. Important Note: Attribute of a SeekBar are same as ProgressBar and the only difference is user determine the progress by moving a slider (thumb) in SeekBar.

How do you set up a progress bar?

In android there is a class called ProgressDialog that allows you to create progress bar. In order to do this, you need to instantiate an object of this class. Its syntax is. ProgressDialog progress = new ProgressDialog(this);


1 Answers

The ProgressBar works by changing the level of the associated drawable. In doRefreshProgress():

final int level = (int) (scale * MAX_LEVEL);
(progressDrawable != null ? progressDrawable : d).setLevel(level);

A Drawable's level is, basically, an integer number that may have different meanings for different kinds of Drawable subclasses.

This allows a drawable to vary its imagery based on a continuous controller, for example to show progress or volume level.

Returns true if this change in level has caused the appearance of the Drawable to change (hence requiring an invalidate), otherwise returns false.

In particular, a GradientDrawable (with useLevel="true", such as this one) uses the level value to know which fraction of the drawable should be drawn. For example, for a left-to-right linear gradient, the rectangle is calculated as:

final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;    
x0 = r.left;            y0 = r.top;
x1 = level * r.right;   y1 = y0;

In the case of a ring gradient such as this one, the level determines what fraction of the total 360 deg angle should be drawn:

float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;

In short, as the setProgress() method is called, this value changes, and the ring is progressively filled.

As for the RotateDrawable, it uses the same exact mechanism to rotate the progress_particle bitmap (which is just a transparent square with a white dot at 90 deg) around its center:

mState.mCurrentDegrees = mState.mFromDegrees +
    (mState.mToDegrees - mState.mFromDegrees) * ((float) level / MAX_LEVEL);

Finally, about the "how does it know how to take only the ring shape from 0 degrees on the right" part, that's just a matter of convention. Ring GradientDrawables start from the right. The first lines in the ring path calculation are:

// inner top
ringPath.moveTo(x + radius, y);
// outer top
ringPath.lineTo(x + radius + thickness, y);
like image 158
matiash Avatar answered Oct 04 '22 00:10

matiash