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

Пример анимации загрузки в Android, имитирующей爱奇艺

Эта статья介绍了 пример анимации загрузки, имитирующей爱奇艺的android, конкретный код следующий:

Эскиз:

Используемые знания:

  1. Path
  2. ValueAnimator

Если вы еще не знакомы с Path и ValueAnimator, рекомендуется ознакомиться с блогами этих великих людей, статьи которых о создании собственных view на данный момент наиболее подходящие для меня, подробные инструкции и практика по созданию собственных view, также это и инструкция с практикой, благодарю их за их труды! (Надеюсь, что все смогут серьезно изучить это, и это даст много启发).

Разбивка анимации

  1. Одновременно с этим один круг медленно рисуется по часовой стрелке (круг не является замкнутым)
  2. Этот шаг представляет собой комбинированную анимацию, круг медленно исчезает, а треугольник вращается по часовой стрелке

Основная сложность здесь заключается в вычислении координат, и я постараюсь详细说一下:

  1. Мы здесь ставим центр круга в начало координат x, y, направлением вниз является положительным направлением оси x, направлением вправо является положительным направлением оси y. Если размер view равен квадратному, то в этом случае можно установить半径 круга в половину ширины или высоты, если не квадратный, то нужно взять минимальное значение ширины или высоты и разделить его на два, чтобы получить半径 круга.
  2. Далее идет треугольник, это难点在于 определении координат, этот треугольник является равносторонним треугольником, и мы хотим, чтобы при вращении треугольника он также вращался вокруг центра круга. Таким образом, расстояние от центра круга до каждого вершины треугольника одинаково, и я установил, что длина стороны треугольника равна半径у круга.

Верю, что это изображение уже вынесено, и с помощью тригонометрических функций, координаты p1, p2, p3 уже определены.

p1.x = -(int) ((radius / 2 * Math.tan(30 * Math.PI / 180)));
p1.y = -radius / 2;
p2.x = p1.x;
p2.y = radius / 2;
p3.x = (int) (radius / 2 / Math.sin(60 * Math.PI / 180));
p3.y = 0;

Определяем некоторые свойства

private static final String DEFAULT_COLOR = "#00ba9b";
private static final int DEFAULT_SIZE = 50;  // По умолчанию размер
private static final int DRAW_CIRCLE = 10001; // Статический флаг состояния: рисует круг и треугольник, выполняет анимацию рисования круга
private static final int ROTATE_TRIANGLE = 10002; // Статический флаг состояния: выполняет анимацию вращения треугольника и сворачивания круга
private Context mContext;
private Paint trianglePaint;  // Кисть для треугольника
private Paint circlePaint;  // Кисть для круга
private float paintStrokeWidth = 1; // Устанавливает ширину круга
private long duration = 800; //время выполнения
private int mWidth; //ширина и высота View
private int mHeight;
private Path trianglePath; //путь треугольника
private Path circlePath; //путь окружности
private Path dst; //путь, вычисленный после измерения pathMeasure
private Point p1, p2, p3; //три вершины треугольника
private ValueAnimator animator; //анимация свойств, главным образом для получения значения от 0 до 1 для выполнения анимации
private float mAnimatorValue = 0; //хранение полученного значения от 0 до 1
private int mCurrentState = 0; //текущее состояние 
private int radius = 0; //радиус окружности
private float startSegment; //длина начала окружности
private PathMeasure mMeasure; //измерение пути
private int triangleColor = -1;
private int circleColor = -1;

Настройка пути

1.Поскольку треугольник всегда существует, сначала нарисуйте треугольник, используя путь, мы уже знаем координаты трёх вершины треугольника, и рисование треугольника становится очень простым.

trianglePath = new Path();
p1 = new Point();
p2 = new Point();
p3 = new Point();
trianglePath.moveTo(p1.x, p1.y);
trianglePath.lineTo(p2.x, p2.y);
trianglePath.lineTo(p3.x, p3.y);
trianglePath.close();

Таким образом, путь треугольника настроен, и достаточно вызвать canvans.drawPath(), чтобы нарисовать треугольник на холсте.

2.Затем рисуется окружность, как уже говорилось, у окружности есть выемка,所以我们 также добавляем окружность в путь, и мы не рисуем её directamente на canvas, потому что позже мы ещё будем вычислять периметр окружности, и эти операции помогут нам с путём.

circlePath = new Path();
RectF circleRect = new RectF(-radius, -radius, radius, radius);
circlePath.addArc(circleRect, 268, 358); // Это начнется с 268° от круга, нарисовать 258° с двухградусным промежутком

Настройка анимации свойств

Поскольку анимации требуются данные в диапазоне от 0 до 1
Здесь мы используем числовые значения, предоставляемые анимацией свойств, для создания анимации.

private void initAnimation() {
    TimeInterpolator timeInterpolator = new AccelerateDecelerateInterpolator();
    animator = ValueAnimator.ofFloat(0, 1).setDuration(duration);
    animator.setInterpolator(timeInterpolator);
    animator.setRepeatMode(ValueAnimator.RESTART);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        mAnimatorValue = (float) animation.getAnimatedValue(); // Здесь мы получим значение от 0 до 1
        invalidate(); // Здесь выполняется перерисовка
      {}
    });
    animator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {
      {}
      @Override
      public void onAnimationEnd(Animator animation) {
      {}
      @Override
      public void onAnimationCancel(Animator animation) {
      {}
      @Override
      public void onAnimationRepeat(Animator animation) { 
       // здесь выполняется переход между состояниями, выполняются различные анимации
        switch (mCurrentState) {
          case DRAW_CIRCLE:
            mCurrentState = ROTATE_TRIANGLE;
            break;
          case ROTATE_TRIANGLE:
            mCurrentState = DRAW_CIRCLE;
            break;
          default:
            break;
        {}
      {}
    });
  {}

onDraw

анализ метода onDraw

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // переместить origen в центральное положение
    canvas.translate(mWidth / 2, mHeight / 2);
    // сбросить path dst
    dst.reset();
    // определяем текущее состояние
    switch (mCurrentState) {
     // здесь мы говорим о первом состоянии
      case DRAW_CIRCLE:
      // это строка используется для получения начальной позиции для вырезанного path (dst), если внимательно наблюдать за анимацией, можно увидеть, что начало окружности
      // рисуется с обоих концов, это положение大约 равно 1/5 окружности, когда достигается начальная точка окружности, начну рисовать с начальной точки окружности, я выполняю этот анимационный
      // время大致 установлено на положение около 0.3 от 0 до 1.
        startSegment = (float) (mMeasure.getLength() / 5 * ((0.3 - mAnimatorValue) > 0 ? (0.3 - mAnimatorValue) : 0));
        // здесь нет ничего, просто рисуется треугольник
        trianglePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(trianglePath, trianglePaint);
        // этот метод используется для получения требуемого фрагмента, первый параметр - это начальная позиция, второй параметр - это конечная позиция, третий параметр - это
        // это число - это вырезанный path, добавляется к path (dst), обратите внимание, что это добавление, а не замена, поэтому перед этим нужно выполнить reset, четвертый параметр - это
        // нужно ли перемещать начальную точку к началу текущего пути, чтобы сохранить путь в dst без изменений (например, если в dst уже есть path, здесь
        // установлено false, в этом случае гарантируется непрерывность dst, а после перемещения dst добавляется начальная точка нового пути к концу предыдущего пути, чтобы поддерживать непрерывность)
        mMeasure.getSegment(startSegment, mMeasure.getLength() * mAnimatorValue, dst, true);
        canvas.drawPath(dst, circlePaint);
        break;
         //Второй вид анимации
      case ROTATE_TRIANGLE:
      //Сохранить холст, так как нужно выполнить два анимации, сохранить состояние холста в начальном состоянии
        canvas.save();
        //Затем выполнить вращение треугольника
        trianglePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.rotate(360 * mAnimatorValue);
        canvas.drawPath(trianglePath, trianglePaint);
        //Восстановить холст
        canvas.restore();
        //Затем исчезновение внешнего круга, исчезновение действительно похоже на рисование круга, у нас есть набор значений от 0 до 1, нам нужно только
        //Когда мы截取片段时,пусть точка старта постоянно приближается к общей длине, и появится эффект исчезновения
        mMeasure.getSegment(mMeasure.getLength() * mAnimatorValue, mMeasure.getLength(), dst, true);
        canvas.drawPath(dst, circlePaint);
        break;
      default:
        break;
    {}
  {}

Вот и все, что было в этой статье, надеюсь, это поможет вам в изучении, также希望大家多多支持呐喊教程。

Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору, материалы предоставлены пользователями Интернета в порядке добровольного участия и самостоятельной загрузки, сайт не обладает правами собственности, не был обработан редакторами, не несет ответственности за связанные с этим法律责任. Если вы обнаружите материалы,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма замените # на @) для сообщения о нарушении и предоставьте соответствующие доказательства. В случае подтверждения факта нарушения, сайт незамедлительно удалят涉嫌侵权的内容。

Основной учебник
Тебе понравится