【问题标题】:Modifying the resource image of Progress Bar修改进度条资源图片
【发布时间】:2016-04-04 19:33:10
【问题描述】:

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

我使用的是android定义的进度条:

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

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

示例:

【问题讨论】:

  • @NileshSingh 我的问题涉及图像,即颜色。
  • 您需要有自己的方法。放一些你写的代码,以便其他人能够提供帮助。

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


【解决方案1】:

通常你有 2 个选项

1.如前所述,使用animation-list 并交换图片。

这可能是更简单的解决方案,因为它们可以相对容易地使用AnimationDrawable 进行动画处理。唯一的缺点是您需要至少 16 张图像(所有分辨率)才能获得给定的结果。

2。使用自定义可绘制对象。

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

因此你必须extends Drawable implements Runnable, Animatable 并提供一些好的实现。

以下是一个基本的实现,计算一次位置,然后绘制它们。动画(单个圆圈的大小)可以而且应该进一步调整;)

导致 3 个变体:

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中查看完整的源代码

【讨论】:

    【解决方案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 转换为pngs 列表,我建议使用EzGif service

    p>@98

    另一种选择 - 您可以重复使用几十个加载指示器的自定义实现之一,例如 this one(它与您的指示器有一些足够接近)或 this one(尽管大多数开源指标是圆形的)。

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

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

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

      使用该库的示例:

      还要检查这个:How to make a Square progress-bar with changing color in certain time interval?

      您将在此处了解如何创建您自己的此库的实现。

      希望对你有帮助

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      相关资源
      最近更新 更多