Android - как сделать RotateAnimation более плавной и «физической»?
Я использую своего рода «стрелку компаса», которая следует за пунктом назначения в зависимости от физической ориентации устройства с помощью датчика магнитного поля. Внезапно я столкнулся с небольшой проблемой.
С азимутом и азимутом все в порядке, но реалистичная анимация превратилась в действительно сложную задачу. Я пытался использовать разные интерполяторы, чтобы сделать анимацию более «физической» (т.е. как в реальном компасе, стрелка которого колеблется после вращения шпильки, ускоряется и замедляется во время движения и т. Д.).
Сейчас я пользуюсьinterpolator.accelerate_decelerate
и все довольно хорошо, пока обновления не начинают приходить быстро. Это заставляет анимации перекрывать друг друга, и стрела становится нервной и нервной. Я хочу избежать этого. Я попытался создать очередь, чтобы каждая следующая анимация ожидала до конца или отбрасывала обновления, которые приходят очень быстро. Это делало анимацию гладкой, но поведение стрелы превратилось в абсолютно нелогичное.
Итак, у меня есть 2 вопроса:
1) есть ли способсделать анимированные переходы более плавными в тех случаях, когда анимации перекрывают друг друга?
2) есть ли способостановить анимацию, которая в данный момент обрабатывается и получить промежуточную позицию объекта?
Мой код ниже.UpdateRotation()
метод обрабатывает обновления ориентации и направления и выполняет анимацию внешнегоviewArrow
Посмотреть.
public class DirectionArrow {
// View that represents the arrow
final View viewArrow;
// speed of rotation of the arrow, degrees/sec
final double rotationSpeed;
// current values of bearing and azimuth
float bearingCurrent = 0;
float azimuthCurrent = 0;
/*******************************************************************************/
/**
* Basic constructor
*
* @param view View representing an arrow that should be rotated
* @param rotationSpeed Speed of rotation in deg/sec. Recommended from 50 (slow) to 500 (fast)
*/
public DirectionArrow(View view, double rotationSpeed) {
this.viewArrow = view;
this.rotationSpeed = rotationSpeed;
}
/**
* Extended constructor
*
* @param viewArrow View representing an arrow that should be rotated
* @param rotationSpeed Speed of rotation in deg/sec. Recommended from 50 (slow) to 500 (fast)
* @param bearing Initial bearing
* @param azimuth Initial azimuth
*/
public DirectionArrow(View viewArrow, double rotationSpeed, float bearing, float azimuth){
this.viewArrow = viewArrow;
this.rotationSpeed = rotationSpeed;
UpdateRotation(bearing, azimuth);
}
/**
* Invoke this to update orientation and animate the arrow
*
* @param bearingNew New bearing value, set >180 or <-180 if you don't need to update it
* @param azimuthNew New azimuth value, set >360 or <0 if you don't need to update it
*/
public void UpdateRotation(float bearingNew, float azimuthNew){
// look if any parameter shouldn't be updated
if (bearingNew < -180 || bearingNew > 180){
bearingNew = bearingCurrent;
}
if (azimuthNew < 0 || azimuthNew > 360){
azimuthNew = azimuthCurrent;
}
// log
Log.println(Log.DEBUG, "compass", "Setting rotation: B=" + bearingNew + " A=" + azimuthNew);
// calculate rotation value
float rotationFrom = bearingCurrent - azimuthCurrent;
float rotationTo = bearingNew - azimuthNew;
// correct rotation angles
if (rotationFrom < -180) {
rotationFrom += 360;
}
while (rotationTo - rotationFrom < -180) {
rotationTo += 360;
}
while (rotationTo - rotationFrom > 180) {
rotationTo -= 360;
}
// log again
Log.println(Log.DEBUG, "compass", "Start Rotation to " + rotationTo);
// create an animation object
RotateAnimation rotateAnimation = new RotateAnimation(rotationFrom, rotationTo,
Animation.RELATIVE_TO_SELF, (float) 0.5, Animation.RELATIVE_TO_SELF, (float) 0.5);
// set up an interpolator
rotateAnimation.setInterpolator(viewArrow.getContext(), interpolator.accelerate_decelerate);
// force view to remember its position after animation
rotateAnimation.setFillAfter(true);
// set duration depending on speed
rotateAnimation.setDuration((long) (Math.abs(rotationFrom - rotationTo) / rotationSpeed * 1000));
// start animation
viewArrow.startAnimation(rotateAnimation);
// update cureent rotation
bearingCurrent = bearingNew;
azimuthCurrent = azimuthNew;
}
}