自定義日出日落動畫

背景

最近在使用某一款天氣軟件的時候發現了它的一個日出日落的動畫,感覺還不錯,后面就自己動手擼了一個源碼地址

分析

我們先對這個動畫元素進行分析:

  1. 需要一條曲線。
  2. 需要一個沿著曲線運動的小太陽。
  3. 需要一個跟著太陽一起運動的陰影面。

好了我們直接開始

首先我們定義一個自定義View,然后初始化一些我們上面分析到的元素

 //曲線初始化
        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPathPaint.setStyle(Paint.Style.STROKE);
        mPathPaint.setStrokeWidth(2);
        mPathPaint.setColor(Color.parseColor("#ffffff"));
        PathEffect effects = new DashPathEffect(new float[]{10, 10, 10, 10}, 0);
        mPathPaint.setPathEffect(effects);

        //日出動畫陰影部分初始化
        mAnmationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mAnmationPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mAnmationPaint.setColor(Color.parseColor("#32ffffff"));

        //開始坐標的XY
        mStartPointX = dp2px(9);
        mStartPointY = dp2px(80);

        //結束坐標的XY
        mEndPointX = dp2px(139);
        mEndPointY = mStartPointY;

        //太陽的移動坐標的XY
        mMovePointX = mStartPointX;
        mMovePointY = mStartPointY;

        //圓的半徑
        mRadius = dp2px(74);

        //圓心坐標
        mCirclePointX = dp2px(74);
        mCirclePointY = dp2px(115);

        //圓的初始化
        mRectF = new RectF(mCirclePointX - mRadius, mCirclePointY - mRadius, mCirclePointX + mRadius, mCirclePointY + mRadius);

接下來就是我們繪制的代碼

if (isNeedSun) {
            //畫曲線
            canvas.save();
            canvas.clipRect(mStartPointX, 0, mEndPointX, mStartPointY, Region.Op.INTERSECT);
            canvas.clipRect(mMovePointX - mBitmapW / 2, mMovePointY - mBitmapH / 2, mMovePointX + mBitmapW / 2, mMovePointY + mBitmapH / 2, Region.Op.DIFFERENCE);
            canvas.drawArc(mRectF, 200, 140, true, mPathPaint);
            //畫透明背景用圓的角度來控制
            canvas.clipRect(mStartPointX, 0, mMovePointX, mStartPointY, Region.Op.INTERSECT);
            canvas.drawArc(mRectF, 200, 140, true, mAnmationPaint);
            canvas.restore();

            //畫小太陽
            canvas.drawBitmap(mSunBitmap, mMovePointX - mBitmapW, mMovePointY - mBitmapH, null);

        } else if (mNotUp || mHasDown) {
            //畫曲線
            canvas.save();
            canvas.clipRect(mMovePointX - mBitmapW / 2, mMovePointY - mBitmapH / 2, mMovePointX + mBitmapW / 2, mMovePointY + mBitmapH / 2, Region.Op.DIFFERENCE);
            canvas.clipRect(0, 0, getWidth(), mStartPointY, Region.Op.INTERSECT);
            canvas.drawCircle(mCirclePointX, mCirclePointY, mRadius, mPathPaint);
            canvas.restore();

            if (mNotUp) {
                //畫小太陽
                canvas.drawBitmap(mSunBitmap, mStartPointX - mBitmapW, mStartPointY - mBitmapH, null);
            } else {
                canvas.drawBitmap(mSunBitmap, mEndPointX - mBitmapW, mEndPointY - mBitmapH, null);
            }
        } else {
            //這里不繪制小太陽,只有曲線
            canvas.save();
            canvas.clipRect(0, 0, getWidth(), mStartPointY, Region.Op.INTERSECT);
            canvas.drawCircle(mCirclePointX, mCirclePointY, mRadius, mPathPaint);
            canvas.restore();
        }

最后就是通過我們外部的控制來實現小太陽的動畫

mSunBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.daily_deatil_sun);
            mBitmapW = mSunBitmap.getWidth() / 2;
            mBitmapH = mSunBitmap.getHeight() / 2;
            mNotUp = false;
            isNeedSun = true;
            mHasDown = false;
            ValueAnimator progressAnimator = ValueAnimator.ofFloat(210, 330);
            progressAnimator.setDuration(3000);
            progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    /**每次在初始值和結束值之間產生的一個平滑過渡的值,逐步去更新進度*/
                    float x = (float) animation.getAnimatedValue();
                    if ((x - 210) <= (120 * a)) {
                        mMovePointX = mCirclePointX + (int) (mRadius * (Math.cos(x * 3.14 / 180)));
                        mMovePointY = mCirclePointY + (int) (mRadius * (Math.sin(x * 3.14 / 180)));
                        invalidate();
                    } else {
                        return;
                    }
                }
            });
            progressAnimator.setInterpolator(new LinearInterpolator());
            progressAnimator.start();

最后附上源碼地址和簡單看一下效果圖:

曲線效果圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,357評論 25 708
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,245評論 4 61
  • 有些人就是這樣,轟轟烈烈的出現在你的生命中,說著不離不棄真愛永存的誓言。結果話說的有多真,現實就有多殘忍。當然了,...
    丑態丑閱讀 223評論 0 0
  • 夜寒衾薄 孤燈不許愁人眠 影斜獨窗 亦為蹉跎負流年 烈酒殘殤 酒罷歌賦恨長夜 它日誰能把酒同醉 那堪風雨 舉杯痛飲花間醉
    赫曦丶閱讀 460評論 4 6
  • 歸納法是一種從特殊,推出一般的方法。歸納法從現象提煉出猜想,演繹法把猜想證明為定律。我們幾乎所有的知識,都始于歸納...
    王炳煒閱讀 948評論 0 0