Personalizar una ProgressBar para convertirse en un termómetro

Cómo personalizar un ProgressBar para que parezca un termómetro? con la posibilidad de cambiar de color.

Termómetro azul completoTermómetro azul vacíoTermómetro rojo completoTermómetro rojo vacío

Mi sugerencia era girar la barra de progreso 90 ° para convertirse en vertical a continuación, tienen que superponer una imagen de un termómetro vacío, pero es malo y solución desordenada.

Creo que lo mejor será extender la clase View o ProgressBar y personalizar el método de dibujo, pero no tengo idea de cómo dibujar Termómetro, cualquier ayuda sería apreciada.

2 Solutions collect form web for “Personalizar una ProgressBar para convertirse en un termómetro”

Primero daría 2 setters, uno para el color y otro para el valor de la temperatura, normalizado desde 0 … 1, donde 0 significa que no hay barra visible, y 1 significa una barra completamente visible.

public void setColor(int color) { mColor = color; invalidate(); // important, this triggers onDraw } public void setValue(float value) { mValue = -(value - 1); invalidate(); // important, this triggers onDraw } 

Aviso de valor, invertir el valor, ya que dibujar la barra de abajo hacia arriba, en lugar de arriba hacia abajo. Tiene sentido en el método canvas.drawRect.

Si su CustomView puede tener tamaños personalizados, defina su tamaño de la barra de progreso (me refiero a la barra interna como onSizeChanged ) en onSizeChanged , ya que se llama cuando la vista ha cambiado su tamaño. Si es un tamaño fijo, sólo puede proporcionar esos valores de forma estática en una función init o el constructor.

 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mProgressRect = new Rect( /*your bar left offset relative to base bitmap*/, /*your bar top offset relative to base bitmap*/, /*your bar total width*/, /*your max bar height*/ ); } 

Luego en el retiro, tomar estos valores en cuenta y dibujar en consecuencia.

  • Primero dibuje el mapa de bits, dependiendo del color seleccionado (proporcionaría la base del termómetro como un mapa de bits, siempre y cuando no tenga que estar completamente dibujado dinámicamente (requisitos especiales)
  • A continuación, dibujar la barra de progreso , con una altura basada en mValue * totalHeight de la barra, utilizando el color proporcionado en el setter.

Por ejemplo:

 @Override protected void onDraw(Canvas canvas) { // draw your thermometer base, bitmap based on color value canvas.drawBitmap( /*your base thermometer bitmap here*/ ); // draw the "progress" canvas.drawRect(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.right, mProgressRect.bottom, mPaint); } 

Espero que ayude.

PS: Si quieres que la imagen de la base del termómetro también se dibuje dinámicamente, es una historia ligeramente diferente, implicaría crear una ruta primero y dibujarla con un objeto Paint, en lugar de dibujar el mapa de bits.

EDITAR:

Incluso mejor, si desea una solución simple para la "redondez" de la barra, dibujar una línea en lugar de un rect.

Defina un objeto de pintura de línea como este:

  mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(20); // thickness of your bar 

entonces en onDraw, en lugar drawRect :

  // draw the "progress" canvas.drawLine(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.left, mProgressRect.bottom, mPaint); 

Asegúrese de ajustar su mProgressRect consecuencia.

He creado algo así para un proyecto Termómetro Widget

  package com.janslab.thermometer.widgets; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.Scroller; import com.janslab.thermometer.R; public class DummyThermometer extends View { private Paint mInnerCirclePaint; private Paint mOuterCirclePaint; private Paint mFirstOuterCirclePaint; //thermometer arc paint private Paint mFirstOuterArcPaint; //thermometer lines paints private Paint mInnerLinePaint; private Paint mOuterLinePaint; private Paint mFirstOuterLinePaint; //thermometer radii private int mOuterRadius; private int mInnerRadius; private int mFirstOuterRadius; //thermometer colors private int mThermometerColor = Color.rgb(200, 115, 205); //circles and lines variables private float mLastCellWidth; private int mStageHeight; private float mCellWidth; private float mStartCenterY; //center of first cell private float mEndCenterY; //center of last cell private float mStageCenterX; private float mXOffset; private float mYOffset; // I 1st Cell I 2nd Cell I 3rd Cell I private static final int NUMBER_OF_CELLS = 3; //three cells in all ie.stageHeight divided into 3 equal cells //animation variables private float mIncrementalTempValue; private boolean mIsAnimating; private Animator mAnimator; public DummyThermometer(Context context) { this(context, null); } public DummyThermometer(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DummyThermometer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); if (attrs != null) { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Thermometer, defStyle, 0); mThermometerColor = a.getColor(R.styleable.Thermometer_therm_color, mThermometerColor); a.recycle(); } init(); } private void init() { mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInnerCirclePaint.setColor(mThermometerColor); mInnerCirclePaint.setStyle(Paint.Style.FILL); mInnerCirclePaint.setStrokeWidth(17f); mOuterCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mOuterCirclePaint.setColor(Color.WHITE); mOuterCirclePaint.setStyle(Paint.Style.FILL); mOuterCirclePaint.setStrokeWidth(32f); mFirstOuterCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFirstOuterCirclePaint.setColor(mThermometerColor); mFirstOuterCirclePaint.setStyle(Paint.Style.FILL); mFirstOuterCirclePaint.setStrokeWidth(60f); mFirstOuterArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFirstOuterArcPaint.setColor(mThermometerColor); mFirstOuterArcPaint.setStyle(Paint.Style.STROKE); mFirstOuterArcPaint.setStrokeWidth(30f); mInnerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInnerLinePaint.setColor(mThermometerColor); mInnerLinePaint.setStyle(Paint.Style.FILL); mInnerLinePaint.setStrokeWidth(17f); mOuterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mOuterLinePaint.setColor(Color.WHITE); mOuterLinePaint.setStyle(Paint.Style.FILL); mFirstOuterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFirstOuterLinePaint.setColor(mThermometerColor); mFirstOuterLinePaint.setStyle(Paint.Style.FILL); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mStageCenterX = getWidth() / 2; mStageHeight = getHeight(); mCellWidth = mStageHeight / NUMBER_OF_CELLS; //center of first cell mStartCenterY = mCellWidth / 2; //move to 3rd cell mLastCellWidth = (NUMBER_OF_CELLS * mCellWidth); //center of last(3rd) cell mEndCenterY = mLastCellWidth - (mCellWidth / 2); // mOuterRadius is 1/4 of mCellWidth mOuterRadius = (int) (0.25 * mCellWidth); mInnerRadius = (int) (0.656 * mOuterRadius); mFirstOuterRadius = (int) (1.344 * mOuterRadius); mFirstOuterLinePaint.setStrokeWidth(mFirstOuterRadius); mOuterLinePaint.setStrokeWidth(mFirstOuterRadius / 2); mFirstOuterArcPaint.setStrokeWidth(mFirstOuterRadius / 4); mXOffset = mFirstOuterRadius / 4; mXOffset = mXOffset / 2; //get the d/f btn firstOuterLine and innerAnimatedline mYOffset = (mStartCenterY + (float) 0.875 * mOuterRadius) - (mStartCenterY + mInnerRadius); mYOffset = mYOffset / 2; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawFirstOuterCircle(canvas); drawOuterCircle(canvas); drawInnerCircle(canvas); drawFirstOuterLine(canvas); drawOuterLine(canvas); animateInnerLine(canvas); drawFirstOuterCornerArc(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //take care of paddingTop and paddingBottom int paddingY = getPaddingBottom() + getPaddingTop(); //get height and width int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); height += paddingY; setMeasuredDimension(width, height); } private void drawInnerCircle(Canvas canvas) { drawCircle(canvas, mInnerRadius, mInnerCirclePaint); } private void drawOuterCircle(Canvas canvas) { drawCircle(canvas, mOuterRadius, mOuterCirclePaint); } private void drawFirstOuterCircle(Canvas canvas) { drawCircle(canvas, mFirstOuterRadius, mFirstOuterCirclePaint); } private void drawCircle(Canvas canvas, float radius, Paint paint) { canvas.drawCircle(mStageCenterX, mEndCenterY, radius, paint); } private void drawOuterLine(Canvas canvas) { float startY = mEndCenterY - (float) (0.875 * mOuterRadius); float stopY = mStartCenterY + (float) (0.875 * mOuterRadius); drawLine(canvas, startY, stopY, mOuterLinePaint); } private void drawFirstOuterLine(Canvas canvas) { float startY = mEndCenterY - (float) (0.875 * mFirstOuterRadius); float stopY = mStartCenterY + (float) (0.875 * mOuterRadius); drawLine(canvas, startY, stopY, mFirstOuterLinePaint); } private void drawLine(Canvas canvas, float startY, float stopY, Paint paint) { canvas.drawLine(mStageCenterX, startY, mStageCenterX, stopY, paint); } //simulate temperature measurement for now private void animateInnerLine(Canvas canvas) { if (mAnimator == null) measureTemperature(); if (!mIsAnimating) { mIncrementalTempValue = mEndCenterY + (float) (0.875 * mInnerRadius); mIsAnimating = true; } else { mIncrementalTempValue = mEndCenterY + (float) (0.875 * mInnerRadius) - mIncrementalTempValue; } if (mIncrementalTempValue > mStartCenterY + mInnerRadius) { float startY = mEndCenterY + (float) (0.875 * mInnerRadius); drawLine(canvas, startY, mIncrementalTempValue, mInnerCirclePaint); } else { float startY = mEndCenterY + (float) (0.875 * mInnerRadius); float stopY = mStartCenterY + mInnerRadius; drawLine(canvas, startY, stopY, mInnerCirclePaint); mIsAnimating = false; stopMeasurement(); } } private void drawFirstOuterCornerArc(Canvas canvas) { float y = mStartCenterY - (float) (0.875 * mFirstOuterRadius); RectF rectF = new RectF(mStageCenterX - mFirstOuterRadius / 2 + mXOffset, y + mFirstOuterRadius, mStageCenterX + mFirstOuterRadius / 2 - mXOffset, y + (2 * mFirstOuterRadius) + mYOffset); canvas.drawArc(rectF, -180, 180, false, mFirstOuterArcPaint); } public void setThermometerColor(int thermometerColor) { this.mThermometerColor = thermometerColor; mInnerCirclePaint.setColor(mThermometerColor); mFirstOuterCirclePaint.setColor(mThermometerColor); mFirstOuterArcPaint.setColor(mThermometerColor); mInnerLinePaint.setColor(mThermometerColor); mFirstOuterLinePaint.setColor(mThermometerColor); invalidate(); } //simulate temperature measurement for now private void measureTemperature() { mAnimator = new Animator(); mAnimator.start(); } private class Animator implements Runnable { private Scroller mScroller; private final static int ANIM_START_DELAY = 1000; private final static int ANIM_DURATION = 4000; private boolean mRestartAnimation = false; public Animator() { mScroller = new Scroller(getContext(), new AccelerateDecelerateInterpolator()); } public void run() { if (mAnimator != this) return; if (mRestartAnimation) { int startY = (int) (mStartCenterY - (float) (0.875 * mInnerRadius)); int dy = (int) (mEndCenterY + mInnerRadius); mScroller.startScroll(0, startY, 0, dy, ANIM_DURATION); mRestartAnimation = false; } boolean isScrolling = mScroller.computeScrollOffset(); mIncrementalTempValue = mScroller.getCurrY(); if (isScrolling) { invalidate(); post(this); } else { stop(); } } public void start() { mRestartAnimation = true; postDelayed(this, ANIM_START_DELAY); } public void stop() { removeCallbacks(this); mAnimator = null; } } private void stopMeasurement() { if (mAnimator != null) mAnimator.stop(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); measureTemperature(); } @Override protected void onDetachedFromWindow() { stopMeasurement(); super.onDetachedFromWindow(); } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); switch (visibility) { case View.VISIBLE: measureTemperature(); break; default: stopMeasurement(); break; } } } 

archivo attrs.xml

  <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Thermometer"> <attr name="therm_color" format="color" /> </declare-styleable> </resources> 
  • Canvas.drawLines mostrando segmentos disjuntos
  • Dibujo de Android en superficie y lienzo
  • Los datos del adaptador RecycleView aparecen erróneos al desplazarse demasiado rápido
  • Android - drawline con aceleración de hardware y antialiasing causa artefactos
  • Método OnDraw personalizado () no llamado
  • Cómo dibujar algo con el dedo en una aplicación de Android ... Y guardarlo en la web
  • Android TextureView / Dibujo / Rendimiento de la pintura
  • ¿Puedo dibujar rectángulo en XML?
  • GetChildDrawingOrder llamado / utilizado de forma errática?
  • Dibujo Texto sobre lienzo
  • El elemento ActionBar no se muestra cuando un ShapeDrawable está configurado como su icono
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.