Плавная анимация хода выполнения

Я пытаюсь реализовать плавную анимацию для моего ProgressBar, но когда я увеличиваю время (30 секунд), анимация перестает быть гладкой.

Пример с 5 секундами:

5 seconds

Пример с 30 секундами:

30 seconds

Мой прогресс:

<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> 

Моя схема выполнения:

<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" />

Мой метод анимации:

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

Поскольку вы используете ofInt, вы можете перемещаться только по целым числам. Другими словами, если у вас есть индикатор выполнения с шириной 1000 и прогресс от 0 до 100, так как вы двигаетесь с целым темпом, вы считаете 1, 2, 3, 4, что соответствует 10px, 20px, 30px и 40px. Это объясняет неровность, которую вы видите.

Чтобы исправить это, у вас есть несколько вариантов. Первый - увеличить ваши целые числа от 0 до someBigInt Это даст аниматору больше номеров для работы.

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

Другой вариант - использовать ofFloat, который делает то же самое, что и ofInt, но использует целые числа с плавающей запятой.

ObjectAnimator progressAnimator = ObjectAnimator.ofFloat(mProgressBar, "progress", 100.0, 0.0);

Ответ 2

Если вы изменяете значение прогресса каждый раз на 1 (например, от 45 до 46), вы не увидите анимацию. Лучше изменить ход на 100 пунктов (или, возможно, другой), для этого вам просто нужно умножить максимальное значение на 100 и каждое значение прогресса до 100. Например:

    private void setProgressMax(ProgressBar pb, int max) {
        pb.setMax(max * 100);
    }

    private void setProgressAnimate(ProgressBar pb, int progressTo) 
    {
        ObjectAnimator animation = ObjectAnimator.ofInt(pb, "progress", pb.getProgress(), progressTo * 100);
        animation.setDuration(500);
        animation.setInterpolator(new DecelerateInterpolator());
        animation.start();
    }

Ответ 3

Просто установите android:max="1000" и делай  ObjectAnimator progressAnimator = ObjectAnimator.ofInt(mProgressBar, "progress", 1000, 0);

в этом случае вы будете анимировать на 1/1000 на каждом шаге, который в 10 раз плавно, если по умолчанию 100-процентная шкала. и он выглядит намного лучше

Ответ 4

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

попробуйте изменить ObjectAnimator.ofInt в ObjectAnimator.ofFloat

надеюсь, что поможет:)

Ответ 5

XML

       <ProgressBar
        android:id="@+id/progress_bar"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="4dp"
        android:indeterminate="false"
        android:progress="0"
        android:max="100"/>

JAVA

@BindView(R.id.progress_bar) ProgressBar progressBar;
ObjectAnimator.ofInt(progressBar, "progress", 79).start();

79

  • любое число от 0 до 100 для этого примера

Ответ 6

Вы можете не использовать ofFloat, потому что атрибут progressBar progress не принимает значения float, только целые. Вот почему ваш ProgressBar прекратил работу после этого решения.

Как говорили другие, правильный способ сделать то, что вы хотите, - установить android:max на какое-то большое целое.

Извините за восстановление потока, но мне кажется, что это нужно было сказать.

Ответ 7

Использование библиотеки может помочь вам дать время, в которое вы хотите заполнить индикатор выполнения, очень плавно, без задержки, но вы немного настроите его, чтобы использовать это.

Просто добавьте зависимость к вашему build.gradle:

compile 'com.carlosmuvi.segmentedprogressbar:library:0.2'

Затем добавьте его в макет

  <com.carlosmuvi.segmentedprogressbar.SegmentedProgressBar
      android:id="@+id/segmented_progressbar"
      android:layout_width="match_parent"
      android:layout_height="5dp"/>

Наконец, настройте его программно и воспроизведите его!

segmentedProgressBar = (SegmentedProgressBar) findViewById(R.id.segmented_progressbar);

// number of segments in your bar
segmentedProgressBar.setSegmentCount(7); 

//empty segment color
segmentedProgressBar.setContainerColor(Color.BLUE); 
//fill segment color
segmentedProgressBar.setFillColor(Color.GREEN); 

//play next segment specifying its duration
segmentedProgressBar.playSegment(5000);

//pause segment
segmentedProgressBar.pause();

//set filled segments directly
segmentedProgressBar.setCompletedSegments(3);

GoToLibrary

Ответ 8

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

private void setProgressBarValues() {
        progressBarCircle.setMax((int) (timeCountInMilliSeconds / 10));
        progressBarCircle.setProgress((int) (timeCountInMilliSeconds / 10));
        Log.e("progres", "" + (timeCountInMilliSeconds / 10));
    }

private void startCountDownTimer() {

        smoothAnimation = ObjectAnimator.ofInt(progressBarCircle, "progress", progressBarCircle.getProgress(), progressBarCircle.getMax());
        smoothAnimation.setDuration(500);
        smoothAnimation.setInterpolator(new AccelerateInterpolator());

        countDownTimer = new CountDownTimer(timeCountInMilliSeconds, 10) {
            @Override
            public void onTick(long millisUntilFinished) {

                Log.e("getMax", "" + progressBarCircle.getMax());
                Log.e("getprogres", "" + progressBarCircle.getProgress());
                textViewTime.setText(hmsTimeFormatter(millisUntilFinished));
                progressBarCircle.setProgress((int) (timeCountInMilliSeconds / 10 - millisUntilFinished / 10));
            }

            @Override
            public void onFinish() {

                textViewTime.setText(hmsTimeFormatter(timeCountInMilliSeconds));
                // call to initialize the progress bar values
                setProgressBarValues();
                // hiding the reset icon
                buttonReset.setEnabled(false);
                // making edit text editable
                editTextMinute.setEnabled(true);
                // changing the timer status to stopped
                status = TimerStatus.STOPPED;
                smoothAnimation.end();
            }

        }.start();
        smoothAnimation.start();
        countDownTimer.start();
    }

Резюме:

  • setMax и setProgress

  • setAnimation для отображения от progess до max значений progressbar

  • создать таймер с обратным вызовом ~ 10 миллисекундов

  • обновить прогресс в onTick i.e total - finished

Ответ 9

Вы можете сделать пользовательские классы вот так:

public class CustomProgressBar extends ProgressBar {
private static final long DEFAULT_DELAY = 500;
private static final long DEFAULT_DURATION = 1000;

public CustomProgressBar(Context context) {
    super(context);
}

public CustomProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public synchronized void setProgress(float progress) {
    super.setProgress((int) progress);
}

@Override
public synchronized void setProgress(int progress) {
    super.setProgress(progress);
}

public void startLcpProgressAnim(int progressTo) {
   startLcpProgressAnim(DEFAULT_DELAY, progressTo);
}

public void startLcpProgressAnim(long delay, int progressTo) {
   startLcpProgressAnim(DEFAULT_DURATION, delay, progressTo);
}

public void startLcpProgressAnim(long duration, long delay, float progressTo) {
    ObjectAnimator animation = ObjectAnimator.
            ofFloat(this, "progress",
                    (float)this.getProgress(), progressTo);
    animation.setDuration(duration);
    animation.setStartDelay(delay);
    animation.start();
}
}