English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
No desenvolvimento anterior do Contador de Passos Ultra Preciso do Android-Dylan Stepping Home Page usou um controle personalizado, semelhante à interface do QQ Movement, e efeitos de animação, vamos falar sobre como esse View é desenhado a seguir.
1.Primeiro olhemos para a imagem de efeito
2.Análise da imagem de efeito
Descrição da função: Amarelo representa o número total de passos planejados pelo usuário, vermelho representa o número de passos atuais do usuário.
Análise inicial: Personalizar completamente View, anular o método onDraw() para desenhar arcos.
3.Conhecimentos necessários para desenhar arcos
No Canvas há um método para desenhar arcos
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//desenhar arco
o primeiro parâmetro é o objeto RectF, uma área retangular elíptica que define os limites da forma, tamanho e arco.
o segundo parâmetro é o ângulo de início (em graus) no início do arco, o ângulo de início do arco, em graus.
o terceiro parâmetro é o ângulo do arco coberto, na direção horária, em graus, começando do meio direito como zero graus.
O quarto parâmetro é se for true (verdadeiro), ao desenhar o arco, incluirá o centro, geralmente usado para desenhar seções circulares; se for false (falso), isso será uma curva arredondada.
o quinto parâmetro é o objeto Paint;
Para este método, você pode ver o esboço que eu desenhei à mão, é muito ruim, expor o significado desses parâmetros e o processo de desenho, peço desculpas por minha má arte!
4.Preparativos de desenho
(1).Obter as coordenadas do ponto central
/**Coordenada x do ponto central*/ float centerX = (getWidth()) / 2;
(2).Criar um retângulo de referência externo ao arco
/**Especificar a área retangular contornada do arco circular*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);
5.Os principais passos de desenho
(1).[Primeiro Passo] Desenhar o arco amarelo geral
/** * 1.Desenhar o arco amarelo total * * @param canvas Caneta * @param rectF Rectângulo de referência */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** Cor padrão da caneta, amarelo */ paint.setColor(getResources().getColor(R.color.yellow)); /** O ponto de junção é arco circular*/ paint.setStrokeJoin(Paint.Join.ROUND); /** Definir o estilo da caneta Paint.Cap.Round, Cap.SQUARE, etc., como circular e quadrada*/ paint.setStrokeCap(Paint.Cap.ROUND); /** definir estilo de preenchimento do pincel Paint.Style.FILL : preencher interno; Paint.Style.FILL_AND_STROKE : preencher interno e contorno; Paint.Style.STROKE : apenas contorno*/ paint.setStyle(Paint.Style.STROKE); /**Função de anti-aliasamento*/ paint.setAntiAlias(true); /**definir largura do pincel*/ paint.setStrokeWidth(borderWidth); /**método para desenhar arco * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//desenhar arco o primeiro parâmetro é o objeto RectF, uma área retangular elíptica que define os limites da forma, tamanho e arco. o segundo parâmetro é o ângulo de início (em graus) no início do arco, o ângulo de início do arco, em graus. o terceiro parâmetro é o ângulo do arco coberto, na direção horária, em graus, começando do meio direito como zero graus. o quarto parâmetro, se for true (verdadeiro), inclui o centro ao desenhar o arco, geralmente usado para desenhar seções circulares; se for false (falso), será uma curva de arco; o quinto parâmetro é o objeto Paint; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); }
(2).[Segundo Passo] Desenhar o arco vermelho do progresso atual
/** * 2.desenhar arco vermelho atual */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//curvatura arredondada paintCurrent.setStyle(Paint.Style.STROKE);//definir estilo de preenchimento paintCurrent.setAntiAlias(true);//Função de anti-aliasamento paintCurrent.setStrokeWidth(borderWidth);//definir largura do pincel paintCurrent.setColor(getResources().getColor(R.color.red));//Definir cor do pincel canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); }
(3).[Terceiro Passo] Desenhar o número vermelho do progresso atual
/** * 3Número de passos no centro do anel */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Função de anti-aliasamento vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font);//Estilo de fonte 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).[Quarto Passo] Desenhar o número vermelho de 'passos'
/** * 4Texto no centro do anel [número de passos] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Função de anti-aliasamento 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.Como a animação é implementada->ValueAnimator
ValueAnimator é uma classe fundamental no mecanismo de animação de atributos, e o mecanismo de execução da animação de atributos é realizado através de operações contínuas sobre os valores, enquanto a transição de animação entre o valor inicial e o valor final é calculada por essa classe ValueAnimator. Seu interior usa um mecanismo de loop de tempo para calcular a transição entre os valores, e tudo o que precisamos fazer é fornecer o valor inicial e o valor final para o ValueAnimator, e informá-lo do tempo necessário para a animação, então o ValueAnimator automaticamente nos ajudará a completar o efeito de transição suave do valor inicial ao valor final.
/*definir animação de progresso * @param start O valor inicial * @param current O valor final * @param length A duração do animação */ 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) { /**Um valor de transição suave gerado entre o valor inicial e o valor final, atualizando gradualmente o progresso*/ currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); }
7.O código-fonte completo do 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; /** * Criado por DylanAndroid em 2016/5/26. * O arco que exibe o número de passos */ public class StepArcView extends View { /** * A largura do arco */ private float borderWidth = 38f; /** * O tamanho da fonte para desenhar o número de passos */ private float numberTextSize = 0; /** * O número de passos */ private String stepNumber = "0"; /** * O ângulo de início do desenho do arco */ private float startAngle = 135; /** * a diferença de ângulo entre o ângulo correspondente ao ponto final e o ângulo correspondente ao ponto de partida */ private float angleLength = 270; /** * O ângulo entre o ponto final do arco vermelho a ser desenhado e o ponto de partida */ private float currentAngleLength = 0; /** * Duração do animação */ 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 do ponto central*/ float centerX = (getWidth()) / 2; /**Especificar a área retangular contornada do arco circular*/ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth); /**【Passo 1】Desenhar o arco amarelo geral*/ drawArcYellow(canvas, rectF); /**【Passo 2】Desenhar o arco vermelho do progresso atual*/ drawArcRed(canvas, rectF); /**【Passo 3】Desenhar o número vermelho do progresso atual*/ drawTextNumber(canvas, centerX); /**【Passo 4】Desenhar o número vermelho de "passos"*/ drawTextStepString(canvas, centerX); } /** * 1.Desenhar o arco amarelo total * * @param canvas Caneta * @param rectF Rectângulo de referência */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** Cor padrão da caneta, amarelo */ paint.setColor(getResources().getColor(R.color.yellow)); /** O ponto de junção é arco circular*/ paint.setStrokeJoin(Paint.Join.ROUND); /** Definir o estilo da caneta Paint.Cap.Round, Cap.SQUARE, etc., como circular e quadrada*/ paint.setStrokeCap(Paint.Cap.ROUND); /** definir estilo de preenchimento do pincel Paint.Style.FILL : preencher interno; Paint.Style.FILL_AND_STROKE : preencher interno e contorno; Paint.Style.STROKE : apenas contorno*/ paint.setStyle(Paint.Style.STROKE); /**Função de anti-aliasamento*/ paint.setAntiAlias(true); /**definir largura do pincel*/ paint.setStrokeWidth(borderWidth); /**método para desenhar arco * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//desenhar arco o primeiro parâmetro é o objeto RectF, uma área retangular elíptica que define os limites da forma, tamanho e arco. o segundo parâmetro é o ângulo de início (em graus) no início do arco, o ângulo de início do arco, em graus. o terceiro parâmetro é o ângulo do arco coberto, na direção horária, em graus, começando do meio direito como zero graus. o quarto parâmetro, se for true (verdadeiro), inclui o centro ao desenhar o arco, geralmente usado para desenhar seções circulares; se for false (falso), será uma curva de arco; o quinto parâmetro é o objeto Paint; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); } /** * 2.desenhar arco vermelho atual */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//curvatura arredondada paintCurrent.setStyle(Paint.Style.STROKE);//definir estilo de preenchimento paintCurrent.setAntiAlias(true);//Função de anti-aliasamento paintCurrent.setStrokeWidth(borderWidth);//definir largura do pincel paintCurrent.setColor(getResources().getColor(R.color.red));//Definir cor do pincel canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); } /** * 3Número de passos no centro do anel */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Função de anti-aliasamento vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font);//Estilo de fonte 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 no centro do anel [número de passos] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true);//Função de anti-aliasamento 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 the current step * * @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 &63; 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 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 in the total number of steps*/ float scale = (float) currentCounts / totalStepNum; /**converter para o comprimento da angle final a ser alcançada em radianos--> comprimento da arco*/ float currentAngleLength = scale * angleLength; /**iniciar execução da animação*/ setAnimation(0, currentAngleLength, animationLength); } /** * definir animação de progresso * O ValueAnimator é a classe mais central da mecânica de animação de atributos, a execução da animação de atributos é implementada através da operação contínua de valores, * e a transição entre o valor inicial e final é calculada pelo ValueAnimator. * Internamente, ele usa um mecanismo de ciclo de tempo para calcular a transição entre os valores, * Precisamos fornecer o valor inicial e final ao ValueAnimator e informá-lo do tempo de execução do animação. * Então o ValueAnimator nos ajudará automaticamente a completar a transição suave do valor inicial para o 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(); } /** * Define o tamanho do texto, para evitar que o texto não caiba após um número de passos particularmente grande, ajustando dinamicamente o tamanho da fonte * * @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.Instruções de Uso
no 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" />
Dentro da Activity
StepArcView sv = (StepArcView) findViewById(R.id.sv); sv.setCurrentCount(7000, 1000);
O que foi mencionado acima é o que o editor apresentou aos amigos sobre o efeito circular e animação de contagem de passos do Android que imita o QQ, esperando que ajude a todos. Se você tiver alguma dúvida, por favor, deixe um comentário, o editor responderá a todos a tempo. Agradecemos também o apoio ao site Tutorial Yell.
Declaração: O conteúdo deste artigo é extraído da Internet, pertence ao autor original, foi uploaded por usuários da Internet de forma voluntária, o site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade legal relevante. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie um e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar, e forneça provas relevantes. Apenas após verificação, o site deletará o conteúdo suspeito de violação de direitos autorais.)