How to make a smooth animation on ProgressBar?

6

I am trying to implement a smooth animation in my ProgressBar , but if I increase the duration time, the animation will no longer be "smooth".

Example with 5 seconds:

Examplewith30seconds:

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 animation method:

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();
}
    
asked by anonymous 10.06.2015 / 22:36

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 , starting from the maximum position until reaching the minimum position. The variation is done in a linear way ie the variation is proportional to the time variation.

Each frame of the animation is displayed at a specific time between the beginning and the end. When the animation system wants to display a frame it uses the LinearInterpolator to get the value, corresponding to that point in time, to assign to the ProgressBar .

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

The degree of softness of the displacement is a function of the time it takes for each new position to be displayed, the smaller the "soft" time will look like. / p>

Let's look at each case:

  • 5-second animation

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

    Each variation of the displacement will take:

    100 -> 5000
      1 -> x
    
    x = 5000/100 => x = 50 ms 
    
  • 30-second animation

    Amplitude of time - 30000 ms (0 - 30000)
    Displacement range - 100 (100 - 0)

    Each variation of the displacement will take:

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

You can see that the time in the second case is 6 times that of the first.

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

The way to decrease this difference is to increase the displacement amplitude by setting the value of the android:max attribute 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 change must also be reflected in the creation of ObjectAnimator :

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

Calculating this value :

Amplitude of time - 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 ProgressBar offset is updated every 30ms. With this value the offset is still "smooth" than in your first example.

The ideal value to choose is the one that produces an update time equal to the interval between frames where the animation is displayed. I do not know how many Frames per second fps animations in Android are displayed.

Assuming that there are 30 fps the value would be, in 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 use in attribute android:max would be 900

    
15.06.2015 / 18:06