English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
В предыдущем проекте Android Ultra Precise Pedometer - Dylan Pedometer на главной странице использовался пользовательский виджет, который somewhat напоминает интерфейс QQ Sports, и имеет анимационный эффект. Вот как этот View был нарисован.
1. Начнем с изображения
2. Анализ изображений
Описание функции: Желтый цвет represents the total number of steps planned by the user, while red represents the number of steps the user has taken at the moment.
Начальный анализ: полная自定义 View, перезапись метода onDraw(), рисование дуги.
3. Необходимые знания для рисования дуги
В Canvas есть метод для рисования дуги
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)// рисовать дугу,
Параметр один - это объект RectF, это граница эллипса в прямоугольной области, которая используется для определения формы, размера, дуги,
Параметр два - это начальный угол (градусы) в начале дуги, начальный угол дуги, единица измерения - градусы.
Параметр три - это угол дуги, проходящий по часовой стрелке, единица измерения - градусы, от середины справа к нулю.
Параметр四是, если true (истина), включает в себя центр при рисовании дуги, обычно используется для рисования секторов; если false (ложь), это будет дуга.
Параметр пять - это объект Paint;
Для этого метода вы можете посмотреть на мой ручной эскиз, он не очень хорош, объясните смысл этих параметров и процесс рисования, извините за плохую работу!
4. Подготовка к рисованию
(1). Получение координат центра
/**中心点的x坐标 */ float centerX = (getWidth()) / 2;
(2). Создание отложенного прямоугольника для дуги
/**指定圆弧的外轮廓矩形区域 */ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);
5. Основные шаги рисования
(1).【第一步】Нанесение целого желтого дуги
/** * 1.绘制总步数的黄色圆弧 * * @param canvas 画笔 * @param rectF 参考的矩形 */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** 默认画笔颜色,黄色 */ paint.setColor(getResources().getColor(R.color.yellow)); /** 结合处为圆弧 */ paint.setStrokeJoin(Paint.Join.ROUND); /** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形 */ paint.setStrokeCap(Paint.Cap.ROUND); /** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边 */ paint.setStyle(Paint.Style.STROKE); /** 抗锯齿功能 */ paint.setAntiAlias(true); /** 设置画笔宽度 */ paint.setStrokeWidth(borderWidth); /**Метод рисования дуги * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//рисовать дугу, Параметр один - это объект RectF, это граница эллипса в прямоугольной области, которая используется для определения формы, размера, дуги, Параметр два - это начальный угол (градусы) в начале дуги, начальный угол дуги, единица измерения - градусы. Параметр три - это угол дуги, проходящий по часовой стрелке, единица измерения - градусы, от середины справа к нулю. Параметр четыре: если это true (истина), то при рисовании дуги центр включается, обычно используется для рисования секторов; если это false (ложь), то это будет дуга, Параметр пять - это объект Paint; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); }
(2).【第二步】Нанесение красного дуги текущего прогресса
/** * 2. Рисование красного дуги текущего шага */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//Круглый край paintCurrent.setStyle(Paint.Style.STROKE);//Установить стиль заливки paintCurrent.setAntiAlias(true);//Функция的抗锯齿 paintCurrent.setStrokeWidth(borderWidth);//Установить ширину кисти paintCurrent.setColor(getResources().getColor(R.color.red));//Установить цвет кисти canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); }
(3).【第三步】Нанесение красного числа текущего прогресса
/** * 3. Круглый центр шагов */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // Anti-aliasing function vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font); // Font style 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).【第四步】Нанесение красного числа «шагов»
/** * 4. Text at the center of the ring [number of steps] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // Anti-aliasing function vTextPaint.setColor(getResources().getColor(R.color.grey)); String stepString = "Number of steps"; Rect bounds = new Rect(); vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds); canvas.drawText(stepString, centerX, getHeight() / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint); }
6. Как реализуется анимация -> ValueAnimator
ValueAnimator — это один из самых основных классов в механизме анимации свойств, который реализует анимацию свойств, постоянно манипулируя значениями. Анимационный переход между начальным и конечным значениями реализуется классом ValueAnimator. Внутри класса используется механизм времени для вычисления перехода между значениями, и нам нужно только предоставить начальное и конечное значения, а также сообщить продолжительность анимации, и ValueAnimator автоматически поможет нам выполнить эффект平滑 перехода от начального значения к конечному.
/* Настройка анимации для прогресса */ * @param start Начальное значение * @param current Конечное значение * @param length Продолжительность анимации */ 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) { /** Каждая гладкая переходная величина между начальным и конечным значениями, постепенно обновляющая прогресс */ currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); }
7. Полный код的自定义 StepArcView
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; /** * Создано DylanAndroid 26 мая 2016 года. * Дуга для отображения шагов */ public class StepArcView extends View { /** * Ширина дуги */ private float borderWidth = 38f; /** * Размер шрифта для рисования шага */ private float numberTextSize = 0; /** * Шаг */ private String stepNumber = "0"; /** * Угол начала рисования дуги */ private float startAngle = 135; /** * Угол между концом и началом угла */ private float angleLength = 270; /** * Угол между концом красной дуги текущего шага и началом */ private float currentAngleLength = 0; /** * Время анимации */ 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); /**中心点的x坐标 */ float centerX = (getWidth()) / 2; /**指定圆弧的外轮廓矩形区域 */ RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth); /**【第一步】绘制整体的黄色圆弧 */ drawArcYellow(canvas, rectF); /**【第二步】绘制当前进度的红色圆弧 */ drawArcRed(canvas, rectF); /**【第三步】绘制当前进度的红色数字 */ drawTextNumber(canvas, centerX); /**【第四步】绘制"步数"的红色数字 */ drawTextStepString(canvas, centerX); } /** * 1.绘制总步数的黄色圆弧 * * @param canvas 画笔 * @param rectF 参考的矩形 */ private void drawArcYellow(Canvas canvas, RectF rectF) { Paint paint = new Paint(); /** 默认画笔颜色,黄色 */ paint.setColor(getResources().getColor(R.color.yellow)); /** 结合处为圆弧 */ paint.setStrokeJoin(Paint.Join.ROUND); /** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形 */ paint.setStrokeCap(Paint.Cap.ROUND); /** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边 */ paint.setStyle(Paint.Style.STROKE); /** 抗锯齿功能 */ paint.setAntiAlias(true); /** 设置画笔宽度 */ paint.setStrokeWidth(borderWidth); /**Метод рисования дуги * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//рисовать дугу, Параметр один - это объект RectF, это граница эллипса в прямоугольной области, которая используется для определения формы, размера, дуги, Параметр два - это начальный угол (градусы) в начале дуги, начальный угол дуги, единица измерения - градусы. Параметр три - это угол дуги, проходящий по часовой стрелке, единица измерения - градусы, от середины справа к нулю. Параметр четыре: если это true (истина), то при рисовании дуги центр включается, обычно используется для рисования секторов; если это false (ложь), то это будет дуга, Параметр пять - это объект Paint; */ canvas.drawArc(rectF, startAngle, angleLength, false, paint); } /** * 2. Рисование красного дуги текущего шага */ private void drawArcRed(Canvas canvas, RectF rectF) { Paint paintCurrent = new Paint(); paintCurrent.setStrokeJoin(Paint.Join.ROUND); paintCurrent.setStrokeCap(Paint.Cap.ROUND);//Круглый край paintCurrent.setStyle(Paint.Style.STROKE);//Установить стиль заливки paintCurrent.setAntiAlias(true);//Функция的抗锯齿 paintCurrent.setStrokeWidth(borderWidth);//Установить ширину кисти paintCurrent.setColor(getResources().getColor(R.color.red));//Установить цвет кисти canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent); } /** * 3. Круглый центр шагов */ private void drawTextNumber(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // Anti-aliasing function vTextPaint.setTextSize(numberTextSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); vTextPaint.setTypeface(font); // Font style 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. Text at the center of the ring [number of steps] */ private void drawTextStepString(Canvas canvas, float centerX) { Paint vTextPaint = new Paint(); vTextPaint.setTextSize(dipToPx(16)); vTextPaint.setTextAlign(Paint.Align.CENTER); vTextPaint.setAntiAlias(true); // Anti-aliasing function vTextPaint.setColor(getResources().getColor(R.color.grey)); String stepString = "Number of steps"; 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 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 преобразуется в 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)); } /** * Прогресс выполненных шагов * * @param totalStepNum Установленное количество шагов * @param currentCounts Количество выполненных шагов */ public void setCurrentCount(int totalStepNum, int currentCounts) { stepNumber = currentCounts + ""; setTextSize(currentCounts); /** Если текущее количество шагов превышает общее количество шагов, дуга все еще составляет 270 градусов, она не может быть кругом */ if (currentCounts > totalStepNum) { currentCounts = totalStepNum; } /** Процент шагов, занимаемых из общего числа шагов */ float scale = (float) currentCounts / totalStepNum; /** Преобразование в длину дуги, которую нужно достичь в конце, в радианы --> длина дуги */ float currentAngleLength = scale * angleLength; /** Начать выполнение анимации */ setAnimation(0, currentAngleLength, animationLength); } /** * Анимация прогресса * ValueAnimator является одним из самых ключевых классов в механизме анимации свойств, механизм работы анимации свойств реализуется через постоянное манипулирование значениями. * А анимационный переход между начальным и конечным значениями отвечает за ValueAnimator этот класс. * Внутри он использует механизм времени для вычисления анимационного перехода между значениями, * Нам нужно предоставить начальное и конечное значения ValueAnimator и сообщить ему продолжительность анимации, * Тогда ValueAnimator автоматически поможет нам создать эффект平滑过渡 от начального значения к конечному значению. * * @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(); } /** * Устанавливает размер текста, чтобы предотвратить ситуации, когда текст становится слишком велик и не помещается, и динамически устанавливает размер шрифта * * @param num */ public void setTextSize(int num) { String s = String.valueOf(num); int length = s.length(); if (length <= 4) { numberTextSize = dipToPx(50); } иными словами, если length > 4 и length <= 6 { numberTextSize = dipToPx(40); } else if (length > 6 && length <= 8) { numberTextSize = dipToPx(30); } else if (length > 8) { numberTextSize = dipToPx(25); } } }
8. Объяснение использования
в 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" />
В Activity
StepArcView sv = (StepArcView) findViewById(R.id.sv); sv.setCurrentCount(7000, 1000);
Названные выше являются аналогичными QQ运动步数圆弧及动画效果,介绍的Android,希望大家有所帮助,如果大家有任何疑问请给我留言,我会及时回复大家的。在此也非常感谢大家对呐喊教程网站的支持!
Заявление: содержимое этой статьи было взято из Интернета, авторские права принадлежат соответствующему автору. Контент был предоставлен пользователями Интернета, сайт не имеет права собственности, не был отредактирован вручную и не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите содержимое,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма, пожалуйста, замените # на @) для жалоб, и предоставьте соответствующие доказательства. Если факт будет установлен, сайт немедленно удалил涉嫌侵权的内容。