頭像隨波浪漂浮效果—仿Android百度外賣

前幾天看到有iOS仿百度外賣的個人頁,所以就隨手擼了個Android。效果圖如下:


demo.gif

源碼

代碼在github:HeaderWaveView

改造輪子

輪子就不重復造了,github上已經(jīng)有實現(xiàn)波浪的效果WaveView,WaveView作者的水波浪實現(xiàn)方法是比較優(yōu)雅的,簡單粗暴的,繪制一個波形圖,填充到View里,移動波形圖。
實現(xiàn)思路,畫兩條sin函數(shù)曲線相疊的波形圖,通過Matrix平移,將sin函數(shù)的height傳給頭像view,進行Translation。

  • 1、將輪子的水波浪方向上下顛倒
baiduwaimai.png

因為百度外賣的水波浪下面還有一個scrollview,而當scrollview往上滑動時,內(nèi)容會被水波浪整個view覆蓋,看著不舒服,所以將水波浪方向調(diào)整。

        wavePaint.setColor(mBehindWaveColor);
        for (int beginX = 0; beginX < endX; beginX++) {
            double wx = beginX * mDefaultAngularFrequency;
            float beginY = (float) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx));
            canvas.drawLine(beginX, beginY, beginX, -1, wavePaint);
            waveY[beginX] = beginY;
        }

        wavePaint.setColor(mFrontWaveColor);
        final int wave2Shift = (int) (mDefaultWaveLength / 4);
        for (int beginX = 0; beginX < endX; beginX++) {
            canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, -1, wavePaint);
        }
  • 2、在HeaderWaveView中提供get方法返回sin函數(shù)的height
public float getSinHeight() {
        //sin函數(shù)的height
        return (float) (getHeight() * mWaterLevelRatio
                + mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO * mDefaultAmplitude * Math.sin(mWaveShiftRatio * getWidth() * mDefaultAngularFrequency));
    }

動畫實現(xiàn)

創(chuàng)建HeaderWaveHelper類進行動畫管理,動畫采用AnimatorSet進行組合。通過設置waterLevelRatio波浪水位、amplitudeRatio波浪振幅、mDefaultFloatViewRotation頭像旋轉(zhuǎn)調(diào)整角,調(diào)整整個效果。

當動畫cancel時,不能很鬼畜的直接將振幅調(diào)零,start時也同理,應該緩慢過渡。

public void cancel() {
        if (mAnimatorSet != null && !mHasCancel) {
            mHasCancel = true;
            mHasStart = false;
            mAmplitudeAnim.cancel();
            amplitudeChangeAnim = ObjectAnimator.ofFloat(
                    mHeaderWaveView, "amplitudeRatio", mDefaultAmplitudeRatioT, 0.00001f);
            amplitudeChangeAnim.setDuration(1000);
            amplitudeChangeAnim.start();
            amplitudeChangeAnim.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animator) {
                
                }
                @Override
                public void onAnimationEnd(Animator animator) {
                    if (mFloatView.getAnimation() != null) {
                        mFloatView.getAnimation().cancel();
                    }
                }

                @Override
                public void onAnimationCancel(Animator animator) {

                }

                @Override
                public void onAnimationRepeat(Animator animator) {

                }
            });
        }
    }
public void start() {
        mHeaderWaveView.setShowWave(true);
        if (mAnimatorSet != null && !mHasStart) {
            mHasStart = true;
            mHasCancel = false;
            if (amplitudeChangeAnim != null) {
                amplitudeChangeAnim = ObjectAnimator.ofFloat(
                        mHeaderWaveView, "amplitudeRatio", 0.00001f, mDefaultAmplitudeRatioF);
                amplitudeChangeAnim.setDuration(1000);
                amplitudeChangeAnim.start();
            }

            if (!mIsFirst) {
                mAnimatorSet.start();
                mIsFirst = true;
            }


        }
    }

三個動畫A、B、C組合成一個AnimatorSet,playTogether,其中A、B是循環(huán)的,而C需要實現(xiàn)三個階段,從0到0.5的過渡(單次),0.5-0.8的來回(循環(huán)),停止時再由當前循環(huán)數(shù)值到0(單次)。我的實現(xiàn)思路是,由A、B、C的循環(huán)構(gòu)成AnimatorSet,在停止事件觸發(fā)后cancel C的動畫,然后new一個動畫實現(xiàn)C的當前數(shù)值到0,開始同理。而整個結(jié)束開始過程中AnimatorSet一直運行。老是感覺這種動畫實現(xiàn)方法不優(yōu)雅,不知道有沒有其他更好的實現(xiàn)方式。

還有一個小細節(jié),view如果是在onCreat中獲取,是無法獲得view.getHeight(),采用view.getMeasuredHeight()代替,不理解可以去看看View的繪制機制。

waveShiftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //獲取sin函數(shù)的height,更新mFloatView
                float value = mHeaderWaveView.getSinHeight() - mFloatView.getMeasuredHeight();
                mFloatView.setRotation(value + mDefaultFloatViewRotation);
                mFloatView.setTranslationY(value);
                mFloatView.invalidate();
            }
        });

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,147評論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,419評論 4 61
  • 我正在聚精會神地陪著姥姥打麻將,一直在火炕上待著的大寶玩了倆把手機游戲就把手機給我了. 我打開手機,早上在得到的留...
    燦寶辣媽閱讀 414評論 3 4
  • 感悟: 1.我們判斷一件事情是否能做不能以其他人有沒有在做為標準,而應該去探求這件事底層的事實和邏輯。 2.討論問...
    葉超群閱讀 163評論 0 0
  • 那些讓你成長的人,往往都不會和你長久。如果以后你很成功,一定要記得感謝他(她)。感謝他(她)的絕情和成全。
    云痕閱讀 293評論 0 0

友情鏈接更多精彩內(nèi)容