我想为Android创建一个进度条。我的方形进度条有四个图像。
我正在使用android定义的进度条:
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@android:style/Widget.ProgressBar.Small"
android:layout_marginRight="5dp" />
但是,如果我想制作一个正方形而不是圆形,我该怎么办呢?如何将4张图像传递到进度条?
示例:
答案 0 :(得分:14)
通常你有 2个选项:
<强> 1。如前所述,使用animation-list
并只交换图片。
这个可能是更简单的解决方案,因为它们可以通过AnimationDrawable相对容易地进行动画制作。唯一的缺点是您需要至少16张图像(在所有分辨率下)才能得到您的结果。
<强> 2。使用自定义drawable。
这是更复杂的方法。你必须自己进行绘图和动画制作,对于大多数没有良好文档的人来说这是一项艰巨的任务。
因此,你必须extends Drawable implements Runnable, Animatable
并提供一些好的实现。
以下是基本的实现,计算一次位置,然后绘制它们。动画(各个圆圈的大小)可以而且应该进一步调整;)
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);
}
}
}
因此,就我而言,它看起来像:
所以你需要的只是你的指标和状态。自定义视图如上所述。
要获取指标的状态,您可以将gif
转换为png
的列表,我建议您使用EzGif service:
另一种选择 - 你可以重复使用加载指标的数十种自定义实现之一,例如(它有一些足够接近你的指标)或this one(尽管,大多数开源指标都是循环的。)
我希望它有所帮助。
答案 2 :(得分:4)
是的,您需要为此创建自定义视图,但还有一个额外的Android库可能对您有所帮助。
请检查:https://github.com/mrwonderman/android-square-progressbar
使用此库的示例:
另请检查:How to make a Square progress-bar with changing color in certain time interval?
在这里,您将找到如何创建自己的lib实现。
希望有所帮助