前言
在項目中遇到了這樣一個需求,一個Imageview圍繞另一個Imageview沿傾斜的橢圓路徑旋轉(zhuǎn)佩脊,具體效果如下:
思路
- 確定橢圓的坐標(biāo)
- 用PathMeasure計算移動點的坐標(biāo)
- 設(shè)置屬性動畫和差值器
- 添加屬性動畫監(jiān)聽
- 設(shè)置視圖坐標(biāo)
環(huán)境
- API 25
- JDK 1.8.0_101
涉及到的知識點
-
獲取控件在屏幕中的絕對坐標(biāo)
//獲取控件當(dāng)前位置 int[] startLoc = new int[2]; rotateIv.getLocationInWindow(startLoc); //獲取被圍繞控件的起始點 int[] parentStart = new int[2]; customIv.getLocationInWindow(parentStart); //獲取被圍繞坐標(biāo)的終點 int[] parentEnd = new int[2]; parentEnd[0] = parentStart[0] + customIv.getWidth(); parentEnd[1] = parentStart[1] + customIv.getHeight();
-
繪制橢圓并旋轉(zhuǎn)角度
//構(gòu)建橢圓 // KLog.i((parentStart[0]-deviation)+" " +(parentStart[1]-deviation)+" "+(parentEnd[0]+deviation)+" "+(parentEnd[1]+deviation)); Path path = new Path(); RectF rectF = new RectF(parentStart[0]-120,parentStart[1]-220,parentEnd[0]+100,parentEnd[1]);//橢圓大小需自己調(diào)整 path.addArc(rectF,0,360); //設(shè)置橢圓傾斜度數(shù) Matrix matrix = new Matrix(); matrix.setRotate(-14,(parentStart[0]+parentEnd[0])/2,(parentStart[1]+parentEnd[1])/2); path.transform(matrix);
-
視圖加載監(jiān)聽
//添加視圖加載完成監(jiān)聽,getLocationInWindow需等到視圖加載完成后才能返回正確值垫卤,否則為0 customIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // TODO Auto-generated method stub startRotate(); } });
-
屬性動畫監(jiān)聽
//添加監(jiān)聽 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //獲取當(dāng)前位置 float value = (float) animation.getAnimatedValue(); //傳入一個距離distance(0<=distance<=getLength())威彰,然后會計算當(dāng)前距 // 離的坐標(biāo)點和切線,pos會自動填充上坐標(biāo) pathMeasure.getPosTan(value,mCurrentPosition,null); //打印當(dāng)前坐標(biāo) // KLog.i(mCurrentPosition[0]+" "+mCurrentPosition[1]); //設(shè)置視圖坐標(biāo) rotateIv.setX(mCurrentPosition[0]); rotateIv.setY(mCurrentPosition[1]); } }); valueAnimator.start();
所有代碼
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);
//添加視圖加載完成監(jiān)聽穴肘,getLocationInWindow需等到視圖加載完成后才能返回正確值歇盼,否則為0
customIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
startRotate();
}
});
}
@Override
protected void onResume() {
super.onResume();
}
private void startRotate() {
//獲取控件當(dāng)前位置
int[] startLoc = new int[2];
rotateIv.getLocationInWindow(startLoc);
//獲取被圍繞控件的起始點
int[] parentStart = new int[2];
customIv.getLocationInWindow(parentStart);
//獲取被圍繞坐標(biāo)的終點
int[] parentEnd = new int[2];
parentEnd[0] = parentStart[0] + customIv.getWidth();
parentEnd[1] = parentStart[1] + customIv.getHeight();
//構(gòu)建橢圓
// KLog.i((parentStart[0]-deviation)+" " +(parentStart[1]-deviation)+" "+(parentEnd[0]+deviation)+" "+(parentEnd[1]+deviation));
Path path = new Path();
RectF rectF = new RectF(parentStart[0]-120,parentStart[1]-220,parentEnd[0]+100,parentEnd[1]);//橢圓大小需自己調(diào)整
path.addArc(rectF,0,360);
//設(shè)置橢圓傾斜度數(shù)
Matrix matrix = new Matrix();
matrix.setRotate(-14,(parentStart[0]+parentEnd[0])/2,(parentStart[1]+parentEnd[1])/2);
path.transform(matrix);
//pathMeasure用來計算顯示坐標(biāo)
pathMeasure = new PathMeasure(path,true);
//屬性動畫加載
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,pathMeasure.getLength());
//設(shè)置動畫時長
valueAnimator.setDuration(10000);
//加入差值器
valueAnimator.setInterpolator(new LinearInterpolator());
//設(shè)置無限次循環(huán)
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
//添加監(jiān)聽
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//獲取當(dāng)前位置
float value = (float) animation.getAnimatedValue();
//boolean getPosTan(float distance, float[] pos, float[] tan) :
//傳入一個距離distance(0<=distance<=getLength()),然后會計算當(dāng)前距
// 離的坐標(biāo)點和切線评抚,pos會自動填充上坐標(biāo)
pathMeasure.getPosTan(value,mCurrentPosition,null);
//打印當(dāng)前坐標(biāo)
// KLog.i(mCurrentPosition[0]+" "+mCurrentPosition[1]);
//設(shè)置視圖坐標(biāo)
rotateIv.setX(mCurrentPosition[0]);
rotateIv.setY(mCurrentPosition[1]);
}
});
valueAnimator.start();
}
}