Пользовательская анимация Android для ArcShape

Сначала позвольте мне объяснить свою цель. Я пытаюсь сделать Animation, который изменяет свойства ArcShape. Конструктор ArcShape's принимает два поля: startAngle и sweepAngle. Я хочу анимировать sweepAngle, чтобы он отображался на экране как непрерывно сокращающийся круг.

Вы можете представить эту анимацию, представив PacMan. Представьте, что его рот закрыт. Эта анимация была бы сродни тому, что он все больше открывал свою верхнюю челюсть, пока не было больше PacMan.

Теперь... У меня есть пара проблем с реализацией этого. Во-первых, после создания ArcShape нет встроенных методов его изменения sweepAngle. Это подводит меня к моему первому вопросу: есть ли способ переопределить ArcShape и реализовать некоторый метод setSweepAngle? Или мне нужно создать new ArcShape для каждого sweepAngle, который я хочу отобразить?

Теперь о втором вопросе... Предполагая, что я нашел решение первой проблемы, как мне создать этот Animation? Это суть того, что у меня есть сейчас:

public class OpenPacman extends Animation {
  public OpenPacman(float startAngle, float sweepAngle) {
    mStartAngle = startAngle;
    mSweepAngle = sweepAngle;
  }

  @Override
  protected void applyTransformation(float interpolatedTime, Transformation t) {
    /* This represents the current sweepAngle */
    float currAngle = mStartAngle + ((mSweepAngle - mStartAngle) * interpolatedTime);

    //Now I need to update the ArcShape sweepAngle to currAngle. But HOW?
  }
}

Ответ 1

Я нашел решение. У меня есть класс, который расширяет View Мы будем называть это Pacman Я вложил свой пользовательский Animation в этот класс Pacman. Это позволило мне получить доступ к member variables класса Pacman.

public class Pacman extends View {
  float mSweepAngle;
  ...
  //include constructors
  //override onMeasure
  ...

  /* Here we override onDraw */
  @Override
  protected void onDraw(final Canvas canvas) {
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    RectF oval = new RectF(canvas.getClipBounds());
    canvas.drawArc(oval, 0, mCurrAngle, true, p);
  }

  /* Here we define our nested custom animation */
  public class OpenPacman extends Animation {
    float mStartAngle;
    float mSweepAngle;

    public OpenPacman (int startAngle, int sweepAngle, long duration) {
      mStartAngle = startAngle;
      mSweepAngle = sweepAngle;
      setDuration(duration);
      setInterpolator(new LinearInterpolator());
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
      float currAngle = mStartAngle + ((mSweepAngle - mStartAngle) * interpolatedTime);
      Pacman.this.mCurrAngle = -currAngle; //negative for counterclockwise animation.
    }
  }
}

Теперь, когда пользовательская анимация обновляет классы контейнера mCurrAngle, автоматически вызывается onDraw, которая рисует соответствующий ArcShape.

Ответ 2

Я думаю, что вам может быть лучше не использовать Drawable и переопределить функцию draw(), чтобы изменить угол развертки при каждом вызове и нарисовать соответствующую дугу. Draw обычно вызывается каждый раз, когда объект обновляется, что будет означать, что вам придется создавать новый ArcShape каждый раз, когда он нарисован Анимация больше предназначена для выполнения преобразований в представлениях и других компонентах пользовательского интерфейса.

Что-то вроде:

public class OpenPacman  
{

public OpenPacman(float startAngle, float sweepAngle) {  
    this.mStartAngle = startAngle;  
    this.mSweepAngle = sweepAngle;  
    this.wakaWaka = new ArcShape(this.startAngle, this.mSweepAngle);  
} 

public void draw(Canvas c){  
  //Do drawing stuff here with the canvas
}

//Your other functions for calculating angle, etc and making the ArcShape changes
//Can call these from inside draw function so that when the view that contains your
//object calls draw, it updates correctly.

public float mStartAngle;  
public float msweepAngle;  
private ArcShape wakaWaka;  
}

Надеюсь, это поможет вам на правильном пути.