Modificación de la imagen de recurso de la barra de progreso
Quiero crear una barra de progreso para Android. Tengo cuatro imágenes para mi barra de progreso cuadrada.
Estoy usando la barra de progreso definida para Android:
- Centrar un botón en un diseño Lineal
- Cambiar el color de Switch en Android
- Android Pluralización no funciona, necesita ayuda
- Integración de ZbarScanner con la aplicación Android
- Androide: pregunta LinearLayout y fill_parent simple
<ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" style="@android:style/Widget.ProgressBar.Small" android:layout_marginRight="5dp" />
Pero si quiero hacer un cuadrado en lugar del círculo, ¿cómo puedo hacerlo? ¿Cómo paso mis 4 imágenes a la barra de progreso?
ejemplo:
- Android: Hacer caracteres en negrita en xml
- Parsing XML Android - Análisis de la descripción <description>
- Cómo configurar el fondo de un TextView dinámicamente desde un archivo Xml
- Problema de renderizado con Android Studio 0.4.0
- Rellene Spinner del origen de matriz de cadena, con un String ArrayAdapter
- ¿Cómo acceder a <item> desde un recurso <string-array> en un XML android?
- ¿Cómo declarar varios atributos estilables con el mismo nombre para diferentes etiquetas?
- Deshabilitar elementos de vista de lista con selector y isEnabled ()
Generalmente usted tiene 2 opciones :
1. Como ya se mencionó, utilice una animation-list
y simplemente intercambiar imágenes.
Esta es probablemente la solución más fácil, ya que pueden ser relativamente fáciles de animar con AnimationDrawable . El único inconveniente sería que necesitas al menos 16 imágenes (en todas las resoluciones) para el resultado dado.
2. Utilizar un dibujable personalizado.
Este es el enfoque más complicado. Usted tendrá que hacer el dibujo y animarse a sí mismo, que es una tarea difícil para la mayoría de la gente con poca documentación buena.
Por lo tanto, tiene que extends Drawable implements Runnable, Animatable
y proporcionar algunas implementaciones buenas.
Lo siguiente es una impelmentación básica, calculando las posiciones una vez, luego dibujándolas. La animación (el tamaño de los círculos individuales) puede y debe ser más ajustado;)
Resultado en 3 variantes:
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; } }
Usar con
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress); progressBar.setIndeterminateDrawable(new RectProgressDrawable()); progressBar.setIndeterminate(true);
Alternativamente, puede ver el código fuente completo en un proyecto de trabajo aquí
Lo estoy haciendo con un montón de imágenes y 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" />
Y 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>
Donde cada imagen loading_progress_indicator_XX
es un indicador de estado de progreso.
La vista personalizada con el indicador:
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); } } }
Como resultado, en mi caso se ve como:
Así que todo lo que necesitará son los estados de su indicador y vista personalizada como la anterior.
Para obtener los estados de su indicador, puede convertir gif
a lista de png
s Sugeriría utilizar el servicio EzGif :
Otra opción – usted puede reutilizar uno de docenas de implementaciones personalizadas de indicador de carga como éste (tiene algunos lo suficientemente cerca de sus indicadores) o éste (aunque, la mayoría de los indicadores opensource son circulares).
Espero que ayude.
Sí, necesitas crear una vista personalizada para esto, pero hay una biblioteca adicional de Android que podría ser útil para ti.
Por favor, consulte: https://github.com/mrwonderman/android-square-progressbar
Ejemplos de uso de esta biblioteca:
Compruebe también esto: ¿Cómo hacer una barra de progreso cuadrada con el cambio de color en cierto intervalo de tiempo?
Aquí encontrará cómo crear su propia implementación de este lib.
Espero que ayude