前言
在项目中遇到了这样一个需求,一个Imageview围绕另一个Imageview沿倾斜的椭圆路径旋转,具体效果如下:

思路
- 确定椭圆的坐标
- 用PathMeasure计算移动点的坐标
- 设置属性动画和差值器
- 添加属性动画监听
- 设置视图坐标
环境
- API 25
- JDK 1.8.0_101
涉及到的知识点
获取控件在屏幕中的绝对坐标
1 2 3 4 5 6 7 8 9 10 11 12
| int[] startLoc = new int[2]; rotateIv.getLocationInWindow(startLoc);
int[] parentStart = new int[2]; customIv.getLocationInWindow(parentStart);
int[] parentEnd = new int[2]; parentEnd[0] = parentStart[0] + customIv.getWidth(); parentEnd[1] = parentStart[1] + customIv.getHeight();
|
绘制椭圆并旋转角度
1 2 3 4 5 6 7 8 9 10
|
Path path = new Path(); RectF rectF = new RectF(parentStart[0]-120,parentStart[1]-220,parentEnd[0]+100,parentEnd[1]); path.addArc(rectF,0,360);
Matrix matrix = new Matrix(); matrix.setRotate(-14,(parentStart[0]+parentEnd[0])/2,(parentStart[1]+parentEnd[1])/2); path.transform(matrix);
|
视图加载监听
1 2 3 4 5 6 7 8
| customIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { startRotate(); } });
|
属性动画监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); pathMeasure.getPosTan(value,mCurrentPosition,null);
rotateIv.setX(mCurrentPosition[0]); rotateIv.setY(mCurrentPosition[1]); } }); valueAnimator.start();
|
所有代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| package cn.edu.neu.providence.activity;
import android.animation.ValueAnimator; import android.app.Activity; import android.graphics.Matrix; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.RectF; import android.os.Bundle; import android.view.View; import android.view.ViewTreeObserver; import android.view.Window; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.widget.ImageView;
import com.socks.library.KLog;
import butterknife.BindView; import butterknife.ButterKnife; import cn.edu.neu.providence.R;
public class MainActivity extends Activity {
@BindView(R.id.rotate_iv) ImageView rotateIv; @BindView(R.id.custom_iv) ImageView customIv; private float[] mCurrentPosition = new float[2]; private PathMeasure pathMeasure;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); ButterKnife.bind(this); customIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { startRotate(); } }); }
@Override protected void onResume() { super.onResume(); }
private void startRotate() {
int[] startLoc = new int[2]; rotateIv.getLocationInWindow(startLoc);
int[] parentStart = new int[2]; customIv.getLocationInWindow(parentStart);
int[] parentEnd = new int[2]; parentEnd[0] = parentStart[0] + customIv.getWidth(); parentEnd[1] = parentStart[1] + customIv.getHeight();
Path path = new Path(); RectF rectF = new RectF(parentStart[0]-120,parentStart[1]-220,parentEnd[0]+100,parentEnd[1]); path.addArc(rectF,0,360);
Matrix matrix = new Matrix(); matrix.setRotate(-14,(parentStart[0]+parentEnd[0])/2,(parentStart[1]+parentEnd[1])/2); path.transform(matrix);
pathMeasure = new PathMeasure(path,true);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,pathMeasure.getLength());
valueAnimator.setDuration(10000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); pathMeasure.getPosTan(value,mCurrentPosition,null);
rotateIv.setX(mCurrentPosition[0]); rotateIv.setY(mCurrentPosition[1]); } });
valueAnimator.start(); } }
|