English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementación de View personalizada en Android para imitar el efecto de la curva y la animación de los pasos del ejercicio de QQ

En el desarrollo anterior del pedometer ultra preciso de Android-En la página principal de Dylan Pedometer se utiliza un control personalizado, similar a la interfaz de QQ Movement, y también hay efectos de animación. A continuación, explicaré cómo se dibuja esta View.

1.Primero veamos la imagen del efecto

2.Análisis de la imagen del efecto

Descripción de la función: el amarillo representa el número total de pasos de ejercicio planificados por el usuario, y el rojo representa el número de pasos actuales del usuario.

Análisis inicial: personalizar completamente View, sobrescribir el método onDraw() para dibujar arcos.

3.Conocimientos necesarios para dibujar un arco

En Canvas hay un método para dibujar arcos

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//dibujar arco

el primer parámetro es el objeto RectF, un área rectangular que define los límites elípticos para definir la forma, el tamaño y el arco.

el segundo parámetro es el ángulo de inicio (en grados) en el comienzo del arco, el ángulo de inicio del arco, en unidades de grados.

el tercer parámetro es el ángulo que recorre el arco, en sentido horario, en unidades de grados, desde el centro derecho como cero grados.

El cuarto parámetro es que si es true (verdadero), al dibujar el arco, incluye el centro, generalmente se usa para dibujar secciones circulares; si es false (falso), será una curva.

el quinto parámetro es el objeto Paint;

Para este método, pueden ver el bosquejo que hice a mano, es bastante malo, solo para explicar el significado de estos parámetros y el proceso de dibujo, lo hice mal, espero que me disculpen!

4.绘图的准备工作

(1).获取中心点坐标

/**Coordenada x del punto central*/
float centerX = (getWidth()) / 2;

(2).建立一个圆弧外的参考矩形

/**Especificar el área del contorno del arco circular*/
RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);

5.绘图的主要步骤

(1).【第一步】绘制整体的黄色圆弧

/**
* 1.Dibujar el arco amarillo de la cantidad total de pasos
*
* @param canvas Pincel
* @param rectF Rectangulo de referencia
*/
private void drawArcYellow(Canvas canvas, RectF rectF) {
Paint paint = new Paint();
/** Color del pincel predeterminado, amarillo */
paint.setColor(getResources().getColor(R.color.yellow));
/** El lugar de combinación es una arco circular*/
paint.setStrokeJoin(Paint.Join.ROUND);
/** Establecer el estilo del pincel Paint.Cap.Round, Cap.SQUARE, etc., como circular y cuadrado*/
paint.setStrokeCap(Paint.Cap.ROUND);
/** establecer estilo de relleno del pincel Paint.Style.FILL : rellenar el interior; Paint.Style.FILL_AND_STROKE : rellenar el interior y el contorno; Paint.Style.STROKE : solo contorno*/
paint.setStyle(Paint.Style.STROKE);
/**función de anti-aliasing*/
paint.setAntiAlias(true);
/**establecer anchura del pincel*/
paint.setStrokeWidth(borderWidth);
/**método para dibujar arcos
* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//dibujar arco
el primer parámetro es el objeto RectF, un área rectangular que define los límites elípticos para definir la forma, el tamaño y el arco.
el segundo parámetro es el ángulo de inicio (en grados) en el comienzo del arco, el ángulo de inicio del arco, en unidades de grados.
el tercer parámetro es el ángulo que recorre el arco, en sentido horario, en unidades de grados, desde el centro derecho como cero grados.
el cuarto parámetro es si es true (verdadero), se incluirá el centro al dibujar el arco, generalmente se usa para dibujar segmentos circulares; si es false (falso), será una curva de arco;
el quinto parámetro es el objeto Paint;
*/
canvas.drawArc(rectF, startAngle, angleLength, false, paint);
}

(2).【第二步】绘制当前进度的红色圆弧

/**
* 2.dibujar arco rojo actual
*/
private void drawArcRed(Canvas canvas, RectF rectF) {
Paint paintCurrent = new Paint();
paintCurrent.setStrokeJoin(Paint.Join.ROUND);
paintCurrent.setStrokeCap(Paint.Cap.ROUND);//radio de arco redondeado
paintCurrent.setStyle(Paint.Style.STROKE);//establecer estilo de relleno
paintCurrent.setAntiAlias(true);//función de anti-aliasing
paintCurrent.setStrokeWidth(borderWidth);//establecer anchura del pincel
paintCurrent.setColor(getResources().getColor(R.color.red));//establecer el color del pincel
canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent);
}

(3).【第三步】绘制当前进度的红色数字

/**
* 3número en el centro del anillo
*/
private void drawTextNumber(Canvas canvas, float centerX) {
Paint vTextPaint = new Paint();
vTextPaint.setTextAlign(Paint.Align.CENTER);
vTextPaint.setAntiAlias(true);//función de anti-aliasing
vTextPaint.setTextSize(numberTextSize);
Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
vTextPaint.setTypeface(font);//estilo de fuente
vTextPaint.setColor(getResources().getColor(R.color.red));
Rect bounds_Number = new Rect();
vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);
canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint);
}

(4).【第四步】绘制”步数”的红色数字

/**
* 4texto en el centro del anillo [步数]
*/
private void drawTextStepString(Canvas canvas, float centerX) {
Paint vTextPaint = new Paint();
vTextPaint.setTextSize(dipToPx(16));
vTextPaint.setTextAlign(Paint.Align.CENTER);
vTextPaint.setAntiAlias(true);//función de anti-aliasing
vTextPaint.setColor(getResources().getColor(R.color.grey));
String stepString = "步数";
Rect bounds = new Rect();
vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds);
canvas.drawText(stepString, centerX, getHeight()) / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint);
}

6. ¿Cómo se realiza la animación?->ValueAnimator

ValueAnimator es una de las clases más nucleares en el mecanismo de animación de atributos, y el mecanismo de ejecución de la animación de atributos se realiza a través de la operación continua de valores, mientras que la transición de animación entre el valor inicial y el valor final es calculada por la clase ValueAnimator. Su interior utiliza un mecanismo de bucle de tiempo para calcular la transición entre valores, y solo necesitamos proporcionar el valor inicial y el valor final a ValueAnimator, y decirle cuánto tiempo debe durar la animación, ValueAnimator se encargará automáticamente de completar el efecto de transición suave desde el valor inicial al valor final.

/*establecer animación de progreso
* @param start Valor inicial
* @param current Valor final
* @param length Duración del animación
*/
private void setAnimation(float start, float current, int length) {
ValueAnimator progressAnimator = ValueAnimator.ofFloat(start, current);
progressAnimator.setDuration(length);
progressAnimator.setTarget(currentAngleLength);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/**Un valor de transición suave producido entre el valor inicial y el valor final, que se actualiza gradualmente para actualizar el progreso*/
currentAngleLength = (float) animation.getAnimatedValue();
invalidate();
}
});
progressAnimator.start();
}

7.El código fuente completo del StepArcView personalizado

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import cn.bluemobi.dylan.step.R;
/**
* Creado por DylanAndroid el 2016/5/26.
* El arco que muestra el número de pasos
*/
public class StepArcView extends View {
/**
* El ancho del arco
*/
private float borderWidth = 38f;
/**
* El tamaño de la fuente para dibujar el número de pasos
*/
private float numberTextSize = 0;
/**
* Número de pasos
*/
private String stepNumber = "0";
/**
* El ángulo de inicio para dibujar el arco
*/
private float startAngle = 135;
/**
* El ángulo correspondiente al punto final y el ángulo correspondiente al punto de partida
*/
private float angleLength = 270;
/**
* El ángulo de la arco rojo del paso actual desde el punto final al punto de partida
*/
private float currentAngleLength = 0;
/**
* Duración de la animación
*/
private int animationLength = 3000;
public StepArcView(Context context) {
super(context);
}
public StepArcView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StepArcView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**Coordenada x del punto central*/
float centerX = (getWidth()) / 2;
/**Especificar el área del contorno del arco circular*/
RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);
/**【Paso Primero】Dibujar el arco amarillo completo*/
drawArcYellow(canvas, rectF);
/**【Paso Segundo】Dibujar el arco rojo de progreso actual*/
drawArcRed(canvas, rectF);
/**【Paso Tercero】Dibujar el número rojo de progreso actual*/
drawTextNumber(canvas, centerX);
/**【Paso Cuarto】Dibujar el número rojo de "pasos"*/
drawTextStepString(canvas, centerX);
}
/**
* 1.Dibujar el arco amarillo de la cantidad total de pasos
*
* @param canvas Pincel
* @param rectF Rectangulo de referencia
*/
private void drawArcYellow(Canvas canvas, RectF rectF) {
Paint paint = new Paint();
/** Color del pincel predeterminado, amarillo */
paint.setColor(getResources().getColor(R.color.yellow));
/** El lugar de combinación es una arco circular*/
paint.setStrokeJoin(Paint.Join.ROUND);
/** Establecer el estilo del pincel Paint.Cap.Round, Cap.SQUARE, etc., como circular y cuadrado*/
paint.setStrokeCap(Paint.Cap.ROUND);
/** establecer estilo de relleno del pincel Paint.Style.FILL : rellenar el interior; Paint.Style.FILL_AND_STROKE : rellenar el interior y el contorno; Paint.Style.STROKE : solo contorno*/
paint.setStyle(Paint.Style.STROKE);
/**función de anti-aliasing*/
paint.setAntiAlias(true);
/**establecer anchura del pincel*/
paint.setStrokeWidth(borderWidth);
/**método para dibujar arcos
* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//dibujar arco
el primer parámetro es el objeto RectF, un área rectangular que define los límites elípticos para definir la forma, el tamaño y el arco.
el segundo parámetro es el ángulo de inicio (en grados) en el comienzo del arco, el ángulo de inicio del arco, en unidades de grados.
el tercer parámetro es el ángulo que recorre el arco, en sentido horario, en unidades de grados, desde el centro derecho como cero grados.
el cuarto parámetro es si es true (verdadero), se incluirá el centro al dibujar el arco, generalmente se usa para dibujar segmentos circulares; si es false (falso), será una curva de arco;
el quinto parámetro es el objeto Paint;
*/
canvas.drawArc(rectF, startAngle, angleLength, false, paint);
}
/**
* 2.dibujar arco rojo actual
*/
private void drawArcRed(Canvas canvas, RectF rectF) {
Paint paintCurrent = new Paint();
paintCurrent.setStrokeJoin(Paint.Join.ROUND);
paintCurrent.setStrokeCap(Paint.Cap.ROUND);//radio de arco redondeado
paintCurrent.setStyle(Paint.Style.STROKE);//establecer estilo de relleno
paintCurrent.setAntiAlias(true);//función de anti-aliasing
paintCurrent.setStrokeWidth(borderWidth);//establecer anchura del pincel
paintCurrent.setColor(getResources().getColor(R.color.red));//establecer el color del pincel
canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent);
}
/**
* 3número en el centro del anillo
*/
private void drawTextNumber(Canvas canvas, float centerX) {
Paint vTextPaint = new Paint();
vTextPaint.setTextAlign(Paint.Align.CENTER);
vTextPaint.setAntiAlias(true);//función de anti-aliasing
vTextPaint.setTextSize(numberTextSize);
Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
vTextPaint.setTypeface(font);//estilo de fuente
vTextPaint.setColor(getResources().getColor(R.color.red));
Rect bounds_Number = new Rect();
vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);
canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint);
}
/**
* 4texto en el centro del anillo [步数]
*/
private void drawTextStepString(Canvas canvas, float centerX) {
Paint vTextPaint = new Paint();
vTextPaint.setTextSize(dipToPx(16));
vTextPaint.setTextAlign(Paint.Align.CENTER);
vTextPaint.setAntiAlias(true);//función de anti-aliasing
vTextPaint.setColor(getResources().getColor(R.color.grey));
String stepString = "步数";
Rect bounds = new Rect();
vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds);
canvas.drawText(stepString, centerX, getHeight()) / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint);
}
/**
* Get the height of the number of current steps
*
* @param fontSize Font size
* @return Font height
*/
public int getFontHeight(float fontSize) {
Paint paint = new Paint();
paint.setTextSize(fontSize);
Rect bounds_Number = new Rect();
paint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);
return bounds_Number.height();
}
/**
* dip converted to px
*
* @param dip
* @return
*/
private int dipToPx(float dip) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));
}
/**
* The progress of steps taken
*
* @param totalStepNum The set number of steps
* @param currentCounts The number of steps taken
*/
public void setCurrentCount(int totalStepNum, int currentCounts) {
stepNumber = currentCounts + "";
setTextSize(currentCounts);
/**If the number of steps taken currently exceeds the total number of steps, the arc is still270 degrees, cannot be a garden*/
if (currentCounts > totalStepNum) {
currentCounts = totalStepNum;
}
/**The percentage of steps taken to the total number of steps*/
float scale = (float) currentCounts / totalStepNum;
/**convertir en longitud del ángulo final que debe alcanzar después de la conversión a radianes-->longitud del arco*/
float currentAngleLength = scale * angleLength;
/**iniciar la ejecución de la animación*/
setAnimation(0, currentAngleLength, animationLength);
}
/**
* establecer animación de progreso
* ValueAnimator es la clase más nuclear en el mecanismo de animación de atributos, el mecanismo de ejecución de la animación de atributos se realiza mediante la operación continua de valores,
* y la transición entre el valor inicial y final es responsabilidad de la clase ValueAnimator.
* usando un mecanismo de bucle de tiempo interno para calcular la transición entre valores,
* Solo necesitamos proporcionar el valor inicial y final a ValueAnimator y decirle cuánto tiempo debe durar la animación,
* entonces ValueAnimator nos ayudará automáticamente a completar la transición suave desde el valor inicial al valor final.
*
* @param last
* @param current
*/
private void setAnimation(float last, float current, int length) {
ValueAnimator progressAnimator = ValueAnimator.ofFloat(last, current);
progressAnimator.setDuration(length);
progressAnimator.setTarget(currentAngleLength);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAngleLength = (float) animation.getAnimatedValue();
invalidate();
}
});
progressAnimator.start();
}
/**
* establecer el tamaño del texto para evitar que no quepa después de que el número de pasos sea especialmente grande, configurando dinámicamente el tamaño de la fuente
*
* @param num
*/
public void setTextSize(int num) {
String s = String.valueOf(num);
int length = s.length();
if (length <= 4) {
numberTextSize = dipToPx(50);
} else if (length > 4 && length <= 6) {
numberTextSize = dipToPx(40);
} else if (length > 6 && length <= 8) {
numberTextSize = dipToPx(30);
} else if (length > 8) {
numberTextSize = dipToPx(25);
}
}
}

8.Descripción de uso

en xml

<cn.bluemobi.dylan.step.view.StepArcView
android:id="@"+id/sv "
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp" />

En Activity

StepArcView sv = (StepArcView) findViewById(R.id.sv);
sv.setCurrentCount(7000, 1000);

Lo que se ha mencionado anteriormente es lo que el editor le ha presentado a todos sobre el efecto de curva y animación de pasos de Android similar a QQ, espero que pueda ayudar a todos. Si tiene alguna pregunta, déjeme un mensaje y el editor responderá a tiempo. También muy agradecido por el apoyo de todos a la página web de tutorial de grito!

Declaración: El contenido de este artículo se obtiene de la red, pertenece al propietario original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio no posee los derechos de propiedad, no se ha realizado un procesamiento editorial humano y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar, y proporcione evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustará