修改进度条的资源图像

时间:2015-12-30 19:37:49

标签: java android xml android-layout android-progressbar

我想为Android创建一个进度条。我的方形进度条有四个图像。

我正在使用android定义的进度条:

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

但是,如果我想制作一个正方形而不是圆形,我该怎么办呢?如何将4张图像传递到进度条?

示例:

enter image description here

3 个答案:

答案 0 :(得分:14)

通常你有 2个选项

<强> 1。如前所述,使用animation-list并只交换图片。

这个可能是更简单的解决方案,因为它们可以通过AnimationDrawable相对容易地进行动画制作。唯一的缺点是您需要至少16张图像(在所有分辨率下)才能得到您的结果。

<强> 2。使用自定义drawable。

这是更复杂的方法。你必须自己进行绘图和动画制作,对于大多数没有良好文档的人来说这是一项艰巨的任务。

因此,你必须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);

或者,您可以在工作项目here

中查看完整的源代码

答案 1 :(得分:9)

我正在使用大量图片和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);
        }
    }
}

因此,就我而言,它看起来像:

enter image description here

所以你需要的只是你的指标和状态。自定义视图如上所述。

要获取指标的状态,您可以将gif转换为png的列表,我建议您使用EzGif service

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here {{ 3}} enter image description here enter image description here

另一种选择 - 你可以重复使用加载指标的数十种自定义实现之一,例如enter image description here(它有一些足够接近你的指标)或this one(尽管,大多数开源指标都是循环的。)

我希望它有所帮助。

答案 2 :(得分:4)

是的,您需要为此创建自定义视图,但还有一个额外的Android库可能对您有所帮助。

请检查:https://github.com/mrwonderman/android-square-progressbar

使用此库的示例:

enter image description here enter image description here enter image description here enter image description here enter image description here

另请检查:How to make a Square progress-bar with changing color in certain time interval?

在这里,您将找到如何创建自己的lib实现。

希望有所帮助