path 動(dòng)畫

Paint

Paint類包含關(guān)于如何繪制幾何圖形枣宫,文本和位圖的樣式和顏色信息。

//設(shè)置抗鋸齒存炮,如果不設(shè)置隶校,加載位圖的時(shí)候可能會(huì)出現(xiàn)鋸齒狀的邊界仔涩,如果設(shè)置忍坷,邊界就會(huì)變的稍微有點(diǎn)模糊,鋸齒就看不到了
mPaint.setAntiAlias(boolean aa);
設(shè)置繪畫的風(fēng)格,用于控制原始圖形的幾何解釋(除了drawBitmap佩研,它總是假定為Fill)柑肴。
//設(shè)置繪制的風(fēng)格,用于控制原語(yǔ)的幾何體是如何解釋的(除了drawBitmap旬薯,它總是假定為Fill)晰骑。
mPaint.setStyle(Style style);
//設(shè)置描邊的寬度。 在發(fā)線模式下將0傳遞給筆劃绊序。 細(xì)線總是繪制一個(gè)獨(dú)立于Canva矩陣的像素硕舆。設(shè)置繪畫的筆畫寬度,每當(dāng)繪畫時(shí)使用風(fēng)格是Stroke或StrokeAndFill
mPaint.setStrokeWidth(3);

//用這種風(fēng)格繪制的幾何和文本將被填充骤公,忽略所有
中風(fēng)相關(guān)的設(shè)置在油漆抚官。
Paint.Style.FILL
//用這種風(fēng)格繪制的幾何和文本將描邊,尊重油漆上的筆畫相關(guān)的領(lǐng)域阶捆。
Paint.Style.STROKE
//用這種風(fēng)格繪制的幾何和文字將同時(shí)填充和描邊耗式,尊重油漆上的筆觸相關(guān)的領(lǐng)域。 如果幾何形狀逆時(shí)針?lè)较虺煤铮四J娇赡軙?huì)產(chǎn)生意想不到的結(jié)果。 此限制不適用于FILL或STROKE彪见。
Paint.Style.FILL_AND_STROKE

mPaint.setColor(mColorBg);

path

Path類封裝了由直線段儡司,二次曲線和三次曲線組成的復(fù)合(多個(gè)輪廓)幾何路徑∮嘀福可以使用canvas.drawPath(path捕犬,paint)繪制,可以是填充或描邊(基于繪制的樣式) 酵镜,或者它可以用于剪輯或在路徑上繪制文本碉碉。

//清除路徑中的任何線條和曲線,使其為空淮韭。這不會(huì)改變填充類型的設(shè)置垢粮。
animPath.reset();
//從最后一個(gè)點(diǎn)到指定點(diǎn)(x,y)添加一條線靠粪。 如果此輪廓未進(jìn)行moveTo()調(diào)用蜡吧,則第一個(gè)點(diǎn)將自動(dòng)設(shè)置為(0,0)。
x一行結(jié)尾的x坐標(biāo)--y一行結(jié)尾的y坐標(biāo)
animPath.lineTo(0, 0);

將下一個(gè)輪廓的起點(diǎn)設(shè)置為點(diǎn)(x占键,y)昔善。
@參數(shù)x新輪廓起點(diǎn)的x坐標(biāo)
@參數(shù)y新輪廓起點(diǎn)的y坐標(biāo)
sPath.moveTo
向路徑添加一個(gè)封閉的圓形輪廓
參數(shù)x要添加到路徑的圓的中心的x坐標(biāo)
參數(shù)y要添加到路徑中的圓的中心的y坐標(biāo)
radius要添加到路徑的圓的半徑
dir旋轉(zhuǎn)圓的輪廓的方向
sPath.addCircle(50, 50, 60, Path.Direction.CW);
順時(shí)針
Path.Direction.CW
逆時(shí)針
Path.Direction.CCW
創(chuàng)建一個(gè)空的PathMeasure對(duì)象。 要使用它來(lái)測(cè)量路徑的長(zhǎng)度畔乙,和/或沿著它找到位置和切線君仆,請(qǐng)調(diào)用setPath。
請(qǐng)注意,一旦一個(gè)路徑與度量對(duì)象相關(guān)聯(lián)返咱,如果路徑隨后被修改并且使用度量對(duì)象钥庇,那么它是未定義的。 如果修改路徑洛姑,則必須使用路徑調(diào)用setPath上沐。
PathMeasure pathMeasure = new PathMeasure();
指定一個(gè)新的路徑,或者為null楞艾,否則為空参咙。
pathMeasure.setPath(sourcePath, false);
//返回當(dāng)前輪廓的總長(zhǎng)度,如果沒(méi)有路徑與此度量對(duì)象關(guān)聯(lián)硫眯,則返回0蕴侧。
pathMeasure.getLength()
移動(dòng)到路徑中的下一個(gè)輪廓。 如果存在則返回true两入,否則返回false净宵。
pathMeasure.nextContour();

//經(jīng)過(guò)上面這段計(jì)算duration代碼的折騰 需要重新初始pathMeasure
pathMeasure.setPath(sourcePath, false);
  //每段path走完后,要補(bǔ)一下 某些情況會(huì)出現(xiàn) animPath不滿的情況(當(dāng)然也可以設(shè)置一段裹纳,就可以達(dá)到進(jìn)度條的效果)
*給定起止距離择葡,返回到中間段。 如果段是零長(zhǎng)度剃氧,則返回false敏储,否則返回true。 startD和stopD被固定為合法值(0..getLength())朋鞍。 如果startD> = stopD已添,則返回false(并保持dst不變)。如果startWithMoveTo為true滥酥,則使用moveTo開(kāi)始該段更舞。
      * <p>在{@link android.os.Build.VERSION_CODES#KITKAT}和更早的發(fā)行版上,得到的路徑可能不會(huì)顯示在硬件加速的畫布上坎吻。 一個(gè)簡(jiǎn)單的解決方法是向這個(gè)路徑添加一個(gè)單獨(dú)的操作缆蝉,比如<code> dst.rLineTo(0,0)</ code>禾怠。</ p>
 pathMeasure.getSegment(0, pathMeasure.getLength(), animPath, true);
給定一個(gè)起點(diǎn)和終點(diǎn)距離返奉,返回中間段。 如果段是零長(zhǎng)度吗氏,則返回false芽偏,否則返回true。 startD和stopD被固定為合法值(0..getLength())弦讽。
如果startD> = stopD污尉,則返回false(并保持dst不變)膀哲。
如果startWithMoveTo為true,則使用moveTo開(kāi)始片段被碗。

在{@link android.os.Build.VERSION_CODES#KITKAT}和更早版本上某宪,結(jié)果路徑可能不會(huì)顯示在硬件加速畫布上。 一個(gè)簡(jiǎn)單的解決方法是向這個(gè)路徑添加一個(gè)單獨(dú)的操作锐朴,比如<code> dst.rLineTo(0兴喂,0)</ code>。</ p>
//animPath替換成mStonePath
animPath.set(mStonePath);

view

當(dāng)這個(gè)視圖的大小改變時(shí)焚志,這在layout期間被調(diào)用衣迷。 如果剛剛添加到視圖層次結(jié)構(gòu)中,則使用舊值0調(diào)用酱酬。
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
       mPaddingLeft = getPaddingLeft();
        mPaddingTop = getPaddingTop();
    }

返回這個(gè)視圖的左邊填充壶谒。 如果有插入和啟用滾動(dòng)條,則此值可能還包括顯示滾動(dòng)條所需的空間膳沽。
        mPaddingLeft = getPaddingLeft();
        mPaddingTop = getPaddingTop();

invalidate

invalidate汗菜,請(qǐng)求重新draw,只會(huì)繪制調(diào)用者本身挑社。
      * <p>這必須從UI線程調(diào)用陨界。 要從非UI線程調(diào)用,請(qǐng)調(diào)用{@link #postInvalidate()}痛阻。
   public void invalidate() {
        invalidate(true);
    }
這是invalidate()工作實(shí)際發(fā)生的地方普碎。 一個(gè)完整的invalidate()將導(dǎo)致繪圖緩存失效,但是可以使用invalidateCache設(shè)置為false來(lái)調(diào)用此函數(shù)录平,以跳過(guò)不需要它的情況下的失效步驟(例如,保持與 相同的內(nèi)容)缀皱。
     *
      * @param invalidateCache此視圖的繪圖緩存是否也應(yīng)該失效斗这。 對(duì)于完全無(wú)效,這通常是正確的啤斗,但是如果視圖的內(nèi)容或維度沒(méi)有改變表箭,則可以將其設(shè)置為假。
    void invalidate(boolean invalidateCache) {
        invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
    }

Canvas

Canvas類保存“draw”調(diào)用钮莲。 要繪制東西免钻,你需要4個(gè)基本組件:一個(gè)位圖來(lái)保存像素,一個(gè)Canvas來(lái)承載繪制調(diào)用(寫入到位圖)崔拥,一個(gè)繪制基元(例如Rect极舔,Path,文本链瓦,位圖)和一個(gè)繪制 描述繪圖的顏色和樣式)拆魏。

//用指定的轉(zhuǎn)換對(duì)當(dāng)前矩陣進(jìn)行預(yù)處理
canvas.translate(mPaddingLeft, mPaddingTop);
*使用指定的繪圖繪制指定的路徑盯桦。 該路徑將根據(jù)畫筆中的樣式進(jìn)行填充或框定。
     *
      * @param path要繪制的路徑
      * @param paint用于繪制路徑的油漆
canvas.drawPath(mSourcePath, mPaint);
canvas.drawPath(mAnimPath, mPaint);
繪制前景渤刃,mAnimPath不斷變化拥峦,不斷重繪View的話,就會(huì)有動(dòng)畫效果卖子。

PathAnimView

一個(gè)路徑動(dòng)畫的View,利用源Path繪制“底”,利用動(dòng)畫Path 繪制 填充動(dòng)畫
一個(gè)SourcePath 內(nèi)含多段Path略号,循環(huán)取出每段Path,并做一個(gè)動(dòng)畫
需要做動(dòng)畫的源Path
用于繪制動(dòng)畫的Path
背景色
前景色

PathAnimHelper

介紹:一個(gè)自定義View Path動(dòng)畫的工具類
一個(gè)SourcePath 內(nèi)含多段(一段)Path洋闽,循環(huán)取出每段Path玄柠,并做一個(gè)動(dòng)畫,

  /**
     * 一個(gè)SourcePath 內(nèi)含多段Path,循環(huán)取出每段Path喊递,并做一個(gè)動(dòng)畫
     * 自定義動(dòng)畫的總時(shí)間
     * 和是否循環(huán)
     *
     * @param view           需要做動(dòng)畫的自定義View
     * @param sourcePath     源Path
     * @param animPath       自定義View用這個(gè)Path做動(dòng)畫
     * @param totalDuaration 動(dòng)畫一共的時(shí)間
     * @param isInfinite     是否無(wú)限循環(huán)
     */
    protected void startAnim(View view, Path sourcePath, Path animPath, long totalDuaration, boolean isInfinite) {
        if (view == null || sourcePath == null || animPath == null) {
            return;
        }
        PathMeasure pathMeasure = new PathMeasure();
        //pathMeasure.setPath(sourcePath, false);
        //先重置一下需要顯示動(dòng)畫的path
        animPath.reset();
        animPath.lineTo(0, 0);
        pathMeasure.setPath(sourcePath, false);
        //這里僅僅是為了 計(jì)算一下每一段的duration
        int count = 0;
        while (pathMeasure.getLength() != 0) {
            pathMeasure.nextContour();
            count++;
        }
        //經(jīng)過(guò)上面這段計(jì)算duration代碼的折騰 需要重新初始化pathMeasure
        pathMeasure.setPath(sourcePath, false);
        loopAnim(view, sourcePath, animPath, totalDuaration, pathMeasure, totalDuaration / count, isInfinite);
    }

    /**
     * 循環(huán)取出每一段path 随闪,并執(zhí)行動(dòng)畫
     *
     * @param animPath    自定義View用這個(gè)Path做動(dòng)畫
     * @param pathMeasure 用于測(cè)量的PathMeasure
     */
    protected void loopAnim(final View view, final Path sourcePath, final Path animPath, final long totalDuaration, final PathMeasure pathMeasure, final long duration, final boolean isInfinite) {
        //動(dòng)畫正在運(yùn)行的話,先stop吧骚勘。萬(wàn)一有人要使用新動(dòng)畫呢铐伴,(正經(jīng)用戶不會(huì)這么用。)
        stopAnim();

        mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.setDuration(duration);
        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //Log.i("TAG", "onAnimationUpdate");
                //增加一個(gè)callback 便于子類重寫搞事情
                onPathAnimCallback(view, sourcePath, animPath, pathMeasure, animation);
                //通知View刷新自己
                view.invalidate();
            }
        });

        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationRepeat(Animator animation) {
                //Log.w("TAG", "onAnimationRepeat: ");
                //每段path走完后俏讹,要補(bǔ)一下 某些情況會(huì)出現(xiàn) animPath不滿的情況
                pathMeasure.getSegment(0, pathMeasure.getLength(), animPath, true);

                //繪制完一條Path之后当宴,再繪制下一條
                pathMeasure.nextContour();
                //長(zhǎng)度為0 說(shuō)明一次循環(huán)結(jié)束
                if (pathMeasure.getLength() == 0) {
                    if (isInfinite) {//如果需要循環(huán)動(dòng)畫
                        animPath.reset();
                        animPath.lineTo(0, 0);
                        pathMeasure.setPath(sourcePath, false);
                    } else {//不需要就停止(因?yàn)閞epeat是無(wú)限 需要手動(dòng)停止)
                        animation.end();
                    }
                }
            }

        });
        mAnimator.start();
    }

根據(jù)ArrayList<float[]> path 解析

    /**
     * 根據(jù)ArrayList<float[]> path 解析
     *
     * @param path
     * @return
     */
    public static Path getPathFromArrayFloatList(ArrayList<float[]> path) {
        Path sPath = new Path();
        for (int i = 0; i < path.size(); i++) {
            float[] floats = path.get(i);
            sPath.moveTo(floats[0], floats[1]);
            sPath.lineTo(floats[2], floats[3]);
        }
        return sPath;
    }
    /**
     * 從R.array.xxx里取出點(diǎn)陣,
     *
     * @param context
     * @param arrayId
     * @param zoomSize
     * @return
     */
    public static Path getPathFromStringArray(Context context, int arrayId, float zoomSize) {
        Path path = new Path();
        String[] points = context.getResources().getStringArray(arrayId);
        for (int i = 0; i < points.length; i++) {
            String[] x = points[i].split(",");
            for (int j = 0; j < x.length; j = j + 2) {
                if (j == 0) {
                    path.moveTo(Float.parseFloat(x[j]) * zoomSize, Float.parseFloat(x[j + 1]) * zoomSize);
                } else {
                    path.lineTo(Float.parseFloat(x[j]) * zoomSize, Float.parseFloat(x[j + 1]) * zoomSize);
                }
            }
        }
        return path;
    }
        float[][] LETTERS = new float[][]{
                new float[]{
                        // A
                        24, 0, 1, 22,
                        1, 22, 1, 72,
                        24, 0, 47, 22,
                        47, 22, 47, 72,
                        1, 48, 47, 48
                },

                new float[]{
                        // B
                        0, 0, 0, 72,
                        0, 0, 37, 0,
                        37, 0, 47, 11,
                        47, 11, 47, 26,
                        47, 26, 38, 36,
                        38, 36, 0, 36,
                        38, 36, 47, 46,
                        47, 46, 47, 61,
                        47, 61, 38, 71,
                        37, 72, 0, 72,
                },....
};

進(jìn)度條效果

    @Override
    public void onPathAnimCallback(View view, Path sourcePath, Path animPath, PathMeasure pathMeasure, ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        //獲取一個(gè)段落
        float end = pathMeasure.getLength() * value;
        float begin = (float) (end - ((0.5 - Math.abs(value - 0.5)) * pathMeasure.getLength()));
        animPath.reset();
        animPath.lineTo(0, 0);
        pathMeasure.getSegment(begin, end, animPath, true);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泽疆,一起剝皮案震驚了整個(gè)濱河市户矢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殉疼,老刑警劉巖梯浪,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瓢娜,居然都是意外死亡挂洛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門眠砾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)虏劲,“玉大人,你說(shuō)我怎么就攤上這事褒颈∑馕祝” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵谷丸,是天一觀的道長(zhǎng)堡掏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)刨疼,這世上最難降的妖魔是什么布疼? 我笑而不...
    開(kāi)封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任摊趾,我火速辦了婚禮,結(jié)果婚禮上游两,老公的妹妹穿的比我還像新娘砾层。我一直安慰自己,他們只是感情好贱案,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布肛炮。 她就那樣靜靜地躺著,像睡著了一般宝踪。 火紅的嫁衣襯著肌膚如雪侨糟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天瘩燥,我揣著相機(jī)與錄音秕重,去河邊找鬼。 笑死厉膀,一個(gè)胖子當(dāng)著我的面吹牛溶耘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播服鹅,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼凳兵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了企软?” 一聲冷哼從身側(cè)響起庐扫,我...
    開(kāi)封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎仗哨,沒(méi)想到半個(gè)月后形庭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厌漂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年碘勉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桩卵。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倍宾,靈堂內(nèi)的尸體忽然破棺而出雏节,到底是詐尸還是另有隱情,我是刑警寧澤高职,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布钩乍,位于F島的核電站,受9級(jí)特大地震影響怔锌,放射性物質(zhì)發(fā)生泄漏寥粹。R本人自食惡果不足惜变过,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涝涤。 院中可真熱鬧媚狰,春花似錦、人聲如沸阔拳。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)糊肠。三九已至辨宠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間货裹,已是汗流浹背嗤形。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弧圆,地道東北人赋兵。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像墓阀,于是被迫代替她去往敵國(guó)和親毡惜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

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