How to make a smooth animation in Progressbar?

Asked

Viewed 767 times

6

I’m trying to implement a smooth animation in my ProgressBar, but, if I increase the duration time, the animation stops being "smooth".

Example with 5 seconds:

5 segundos

Example with 30 seconds:

30 segundos

ProgressBar background:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <padding android:top="1dp" />
            <solid android:color="#10444444" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" />
            <solid android:color="#20444444" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" />
            <solid android:color="#30444444" />
        </shape>
    </item>
    <item android:id="@android:id/background">
        <shape>
            <solid android:color="@color/black_thirty" />
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <solid android:color="#3500D0" />
            </shape>
        </clip>
    </item>
</layer-list> 

Layout of ProgressBar:

<ProgressBar
    android:id="@+id/pb_loading"
    android:layout_width="match_parent"
    android:layout_height="8dp"
    android:indeterminate="false"
    android:layout_centerInParent="true"
    android:progress="100"
    android:progressDrawable="@drawable/my_progress_bar" />

My method of animation:

private void startAnimation(){
    ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.pb_loading);
    ObjectAnimator progressAnimator = ObjectAnimator.ofInt(mProgressBar, "progress", 100, 0);
    progressAnimator.setDuration(30000);
    progressAnimator.setInterpolator(new LinearInterpolator());
    progressAnimator.start();
}

1 answer

5


First a small explanation to understand why this happens. Knowing why the solution is simple.

The animation consists of varying the position of the Progressbar, from the maximum position to the minimum position. The variation is made in a linear way, that is, the variation is proportional to the variation in time.

Each frame of the animation is displayed at a specific time between the beginning and the end.
When the animation system wants to present a frame uses the Linearinterpolator to obtain the value, corresponding to that point in time, to be assigned to the Progressbar.

It is in the transformation of the time value into the position value that the "problem" manifests.
Due to the difference between the amplitude of the time value and that of the displacement value there will be times when, over the variation of time, there will be no variation of the position. The greater the difference, the greater the effect.

The degree of "softness" shift is a function of the time it takes for each new position to be displayed, the shorter the time "soft" will seem.

Let’s look at each case:

  • Animation of 5 seconds

    Time range - 5000 ms (0 -- 5000)
    Displacement amplitude - 100 (100 -- 0)

    Each variation of the displacement will take:

    100 -> 5000
      1 -> x
    
    x = 5000/100 => x = 50 ms 
    
  • Animation of 30 seconds

    Time amplitude - 30000 ms (0 -- 30000)
    Displacement amplitude - 100 (100 -- 0)

    Each variation of the displacement will take:

    100 -> 30000
      1 -> x
    
    x = 30000/100 => x = 300 ms  
    

You can observe that the time in the second case is 6 times higher than the first.

In fact, the greater the difference between the amplitudes of the values, the less "soft" is the movement.

The way to decrease this difference is to increase the offset amplitude by defining the attribute value android:max of Progressbar, for example, to 1000:

<ProgressBar
    android:id="@+id/pb_loading"
    android:layout_width="match_parent"
    android:layout_height="8dp"
    android:indeterminate="false"
    android:layout_centerInParent="true"
    android:progress="1000"
    android:max="1000"
    style="@android:style/Widget.ProgressBar.Horizontal"
    android:progressDrawable="@drawable/my_progress_bar"/>  

This amendment must also be reflected in the creation of Objectanimator:

ObjectAnimator progressAnimator = ObjectAnimator.ofInt(mProgressBar, "progress", 1000, 0);

Calculating for this value:

Time amplitude - 30000 ms (0 -- 30000)
Displacement amplitude - 1000 (1000 -- 0)

Each variation of the displacement will take:

1000 -> 30000
  1 -> x

x = 30000/1000 => x = 30 ms  

The displacement of Progressbar is updated every 30ms. With this value the offset is even more "soft" than in your first example.

The ideal value to choose is one that produces an upgrade time equal to the interval between frames where the animation is presented.
I don’t know how many Frames per second (fps) the animations on Android are presented.

Assuming there are 30 fps, for the case of 30s:

30 fps => 33.34 frames por milisegundo

x -> 30000
1 -> 33,34

x = 30000/33.33 => x = 900 

the value to be used in the attribute android:max will be 900

  • The attribute android:max was the key! I had tried only with android:progress="1000". Thank you very much

Browser other questions tagged

You are not signed in. Login or sign up in order to post.