修改进度条的资源图像

我想为安卓创建一个进度条。我有四个图像用于我的方形进度条。

我正在使用机器人定义的进度条:

<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


答案 1

通常你有2个选择

1.如前所述,使用动画列表,只需交换图片即可。

这个可能是更简单的解决方案,因为它们可以相对容易地使用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);
        }
    }
}

因此,在我的情况下,它看起来像:

enter image description here

因此,您所需要的只是指标和自定义视图的状态,如上所示。

要获取指标的状态,您可以转换为我建议使用EzGif服务的列表:gifpng

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 enter image description here enter image description here enter image description here

另一个选项 - 你可以重用加载指标的数十个自定义实现之一,比如这个(它有足够接近你的指标)或这个(虽然,大多数开源指标都是循环的)。

我希望它有帮助。


推荐