Android-小球沿路徑移動(Path+PathMeasure+ValueAnimator)實現(xiàn)

前言

在項目中遇到了這樣一個需求,一個Imageview圍繞另一個Imageview沿傾斜的橢圓路徑旋轉(zhuǎn)佩脊,具體效果如下:

aa.gif

思路

  • 確定橢圓的坐標(biāo)
  • 用PathMeasure計算移動點的坐標(biāo)
  • 設(shè)置屬性動畫和差值器
  • 添加屬性動畫監(jiān)聽
  • 設(shè)置視圖坐標(biāo)

環(huán)境

  1. API 25
  2. JDK 1.8.0_101

涉及到的知識點

  1. 獲取控件在屏幕中的絕對坐標(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();
    
  2. 繪制橢圓并旋轉(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);
    
  3. 視圖加載監(jiān)聽

    //添加視圖加載完成監(jiān)聽,getLocationInWindow需等到視圖加載完成后才能返回正確值垫卤,否則為0
    customIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // TODO Auto-generated method stub
            startRotate();
        }
    });
    
  4. 屬性動畫監(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();
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豹缀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子慨代,更是在濱河造成了極大的恐慌邢笙,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侍匙,死亡現(xiàn)場離奇詭異氮惯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門筐骇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來债鸡,“玉大人,你說我怎么就攤上這事铛纬⊙峋” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵告唆,是天一觀的道長棺弊。 經(jīng)常有香客問我,道長擒悬,這世上最難降的妖魔是什么模她? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮懂牧,結(jié)果婚禮上侈净,老公的妹妹穿的比我還像新娘。我一直安慰自己僧凤,他們只是感情好畜侦,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著躯保,像睡著了一般旋膳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上途事,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天验懊,我揣著相機(jī)與錄音,去河邊找鬼尸变。 笑死义图,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的召烂。 我是一名探鬼主播碱工,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骑晶!你這毒婦竟也來了痛垛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤桶蛔,失蹤者是張志新(化名)和其女友劉穎匙头,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仔雷,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蹂析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年舔示,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片电抚。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡惕稻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝙叛,到底是詐尸還是另有隱情俺祠,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布借帘,位于F島的核電站蜘渣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肺然。R本人自食惡果不足惜蔫缸,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望际起。 院中可真熱鬧拾碌,春花似錦、人聲如沸街望。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽它匕。三九已至展融,卻和暖如春窖认,著一層夾襖步出監(jiān)牢的瞬間豫柬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工扑浸, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留烧给,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓喝噪,卻偏偏與公主長得像础嫡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酝惧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程榴鼎,因...
    小菜c閱讀 6,397評論 0 17
  • 手勢圖片控件 PinchImageView 點擊圖片框架 photoView packagecom.example...
    Ztufu閱讀 721評論 0 1
  • UIBezierPath Class Reference 譯:UIBezierPath類封裝了Core Graph...
    鋼鉄俠閱讀 1,723評論 0 3
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載 前言 Canvas 本意是畫布的意思,然而將它理解為繪制工具一...
    cc榮宣閱讀 41,556評論 1 47
  • 夜幕降高樓晚唇,月落山丘巫财,廣場歌舞伴閑休。天上人間同快樂哩陕,放下煩憂平项。 星數(shù)漫天流赫舒,多像金牛,地平線上莫回頭闽瓢。田野風(fēng)光誰...
    木貞ma閱讀 354評論 1 1