【发布时间】:2014-03-29 00:52:25
【问题描述】:
我正在实现一种“指南针箭头”,它根据使用磁场传感器的设备的物理方向跟踪目的地。突然间我遇到了一个小问题。
获得方位角和方位角是可以的,但是执行逼真的动画变成了一项非常艰巨的任务。我尝试使用不同的插值器来使动画更加“物理”(即在真实的指南针中,箭头在发夹旋转后摆动,在运动过程中加速和减速等)。
现在我正在使用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;
}
}
【问题讨论】:
标签: android animation rotation android-sensors