Подтвердить что ты не робот

Изменение изображения ресурса панели прогресса

Я хочу создать индикатор прогресса для Android. У меня есть четыре изображения для моего квадратного индикатора хода.

Я использую андроид, определенный индикатор выполнения:

<ProgressBar
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     style="@android:style/Widget.ProgressBar.Small"
     android:layout_marginRight="5dp" />

Но если я хочу сделать квадрат вместо круга, как я могу это сделать? Как передать 4 изображения на индикатор выполнения?

Пример:

введите описание изображения здесь

4b9b3361

Ответ 1

Как правило, у вас есть 2 варианта:

1. Как уже упоминалось, используйте animation-list и просто меняйте фотографии.

Это, вероятно, более легкое решение, поскольку они могут относительно легко быть анимированными с помощью AnimationDrawable. Единственный недостаток заключается в том, что для данного результата вам потребуется как минимум 16 изображений (во всех разрешениях).

2. Используйте настраиваемый вариант.

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

Поэтому вы должны extends Drawable implements Runnable, Animatable и снабдить некоторые хорошие реализации.

Ниже приводится базовое изменение, вычисление позиций один раз, а затем их рисование. Анимация (размер отдельных кругов) может и должна быть дополнительно изменена;)

Результат в 3 вариантах:
Progree Bars

public class RectProgressDrawable extends Drawable implements Runnable, Animatable {
    private static final long FRAME_DELAY = 1000 / 60;
    private static final String TAG = "RectProgressDrawable";
    private boolean mRunning = false;
    private long mStartTime;
    private int mDuration = 1000;

    private Paint mPaint;

    private float[] posX;
    private float[] posY;
    private float mSize;
    private int mPoints = 5;

    /**
     * The padding in px.
     */
    private int mPadding = 4;
    private int mAnimatedPoints = 5;

    public void setPoints(int points) {
        if (points != mPoints) {
            mPoints = points;
            init();
        }
    }

    private void init() {
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(Color.WHITE);
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL);
        }

        posX = new float[(mPoints - 1) * 4];
        posY = new float[(mPoints - 1) * 4];

        Rect bounds = new Rect();
        bounds.set(getBounds());
        bounds.inset(mPadding, mPadding);

        float cellWidth = ((float) bounds.width()) / ((float) mPoints);
        float cellHeight = ((float) bounds.height()) / ((float) mPoints);

        float min = Math.min(cellWidth, cellHeight);
        mSize = min / (mPoints - 1);

        for (int i = 0; i < mPoints; i++) { // top row
            posX[i] = bounds.left + cellWidth * (float) i + cellWidth / 2;
            posY[i] = bounds.top + cellHeight / 2;
        }
        for (int i = 0; i < mPoints - 2; i++) { // sides
            // right side top bottom
            posX[mPoints + i] = bounds.left + cellWidth * (mPoints - 1) + cellWidth / 2;
            posY[mPoints + i] = bounds.top + cellHeight * (i + 1) + cellHeight / 2;
            //left side bottom top
            posX[3 * mPoints - 2 + i] = bounds.left + cellWidth / 2;
            posY[3 * mPoints - 2 + i] = bounds.top + cellHeight * (mPoints - 2 - i) + cellHeight / 2;
        }
        for (int i = 0; i < mPoints; i++) { // bottom from right to left
            posX[2 * mPoints - 2 + i] = bounds.left + cellWidth * (mPoints - 1 - i) + cellWidth / 2;
            posY[2 * mPoints - 2 + i] = bounds.top + cellHeight * (mPoints - 1) + cellHeight / 2;
        }
    }

    @Override
    public void draw(Canvas canvas) {
        if (isRunning()) {
            // animation in progress
            final int save = canvas.save();

            long timeDiff = SystemClock.uptimeMillis() - mStartTime;

            float progress = ((float) timeDiff) / ((float) mDuration); // 0..1
            int level = ((int) (progress * posX.length)) % posX.length; // current value 0..posX.length

            for (int i = 0; i < posX.length; i++) {
                if ((i >= level && i < level + mAnimatedPoints) || level + mAnimatedPoints > posX.length && i < (level + mAnimatedPoints) % posX.length) {
                    float num = (i - level + posX.length) % posX.length; // 0..5
                    float size = mSize * (1 + (num * (1f / mAnimatedPoints)));
                    float sizeNext = mSize * (1 + ((num + 1) * (1f / mAnimatedPoints)));

                    float levelProgress = progress * posX.length - (int) (progress * posX.length);
                    float currentSize;
                    if (num == (mAnimatedPoints - 1)) {
                        // grow to next size
                        currentSize = mSize + (size - mSize) * levelProgress;
                    } else {
                        // shrink
                        currentSize = size + (sizeNext - size) * (1 - levelProgress);
                    }

                    canvas.drawCircle(posX[i], posY[i], currentSize, mPaint);
                } else {
                    canvas.drawCircle(posX[i], posY[i], mSize, mPaint);
                }
            }

            canvas.restoreToCount(save);
        } else {
            // draw normal
            for (int i = 0; i < posX.length; i++) {
                canvas.drawCircle(posX[i], posY[i], mSize, mPaint);
            }
        }
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        super.setBounds(left, top, right, bottom);
        init();
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return 0;
    }

    @Override
    public void start() {
        if (mRunning) stop();
        mRunning = true;
        mStartTime = SystemClock.uptimeMillis();
        invalidateSelf();
        scheduleSelf(this, SystemClock.uptimeMillis() + FRAME_DELAY);
    }

    @Override
    public void stop() {
        unscheduleSelf(this);
        mRunning = false;
    }

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

    @Override
    public void run() {
        invalidateSelf();
        long uptimeMillis = SystemClock.uptimeMillis();
        if (uptimeMillis + FRAME_DELAY < mStartTime + mDuration) {
            scheduleSelf(this, uptimeMillis + FRAME_DELAY);
        } else {
            mRunning = false;
            start();
        }
    }

    public void setAnimatedPoints(int animatedPoints) {
        mAnimatedPoints = animatedPoints;
    }
}

Использовать с

    ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress);
    progressBar.setIndeterminateDrawable(new RectProgressDrawable());
    progressBar.setIndeterminate(true);

В качестве альтернативы вы можете увидеть полный исходный код в рабочем проекте здесь

Ответ 2

Я делаю это с кучей изображений и animation-list:

<?xml version="1.0" encoding="utf-8"?>
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loadingAnimationImageView"
    android:layout_width="36dp"
    android:layout_height="36dp"
    android:background="@drawable/loading_progress_indicator_animation" />

И res\drawable\loading_progres_indicator_animation.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/selected"
    android:oneshot="false">
    <item
        android:drawable="@drawable/loading_progress_indicator_0"
        android:duration="40" />
    <item
        android:drawable="@drawable/loading_progress_indicator_1"
        android:duration="40" />
    <item
        android:drawable="@drawable/loading_progress_indicator_2"
        android:duration="40" />
    .....
    <item
        android:drawable="@drawable/loading_progress_indicator_11"
        android:duration="40" />
    <item
        android:drawable="@drawable/loading_progress_indicator_12"
        android:duration="40" />
</animation-list>

Где каждый loading_progress_indicator_XX изображение является индикатором состояния прогресса.

Пользовательский вид с индикатором:

public final class LoadingAnimationView extends FrameLayout {

    ImageView loadingAnimationImageView;
    AnimationDrawable loadingProgressAnimation;
    Handler handler = new Handler(Looper.getMainLooper());

    public LoadingAnimationView(Context context) {
        super(context);
        initialize();
    }

    private void initialize() {
        LayoutInflater.from(getContext()).inflate(R.layout.view_loading_videoview, this);
        loadingAnimationImageView = (ImageView)getView().findViewById(R.id.loadingAnimationImageView);
        loadingProgressAnimation = (AnimationDrawable) loadingAnimationImageView.getBackground();
        adaptToVisibility(getVisibility());
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);
        adaptToVisibility(visibility);
    }

    void adaptToVisibility(final int visibility) {
        if (visibility == VISIBLE) {
            loadingProgressAnimation.start();
            //This is to avoid "blinking" of progress indicator (if page is loading from cache)
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    loadingAnimationImageView.setVisibility(visibility);
                }
            }, 200);
        } else {
            loadingProgressAnimation.stop();
            loadingAnimationImageView.setVisibility(visibility);
        }
    }
}

В результате в моем случае это выглядит так:

введите описание изображения здесь

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

Чтобы получить состояние вашего индикатора, вы можете преобразовать gif в список png Я бы предложил использовать службу EzGif

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь ввести описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

Другая опция - вы можете повторно использовать одну из десятков пользовательских реализаций индикатора загрузки, например этот ( он имеет несколько достаточно близко к вашим индикаторам) или этот (хотя большинство индикаторов с открытым исходным кодом являются круговыми).

Надеюсь, это поможет.

Ответ 3

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

Пожалуйста, проверьте: https://github.com/mrwonderman/android-square-progressbar

Примеры использования этой библиотеки:

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

Также проверьте следующее: Как сделать квадрат прогресса с изменяющимся цветом в определенный интервал времени?

Здесь вы найдете, как создать свою собственную реализацию этой библиотеки.

Надеюсь, что это поможет