ANDROID-漂浮背景效果

效果圖:

GIF動圖效果不是很好,實際效果非常平滑very smooth,而且添加不同的圖形可以組成各種效果,目前已經(jīng)用在我們項目的注冊界面~

這里寫圖片描述

原理:

實現(xiàn)原理很簡單,每一個懸浮的“小物體”就是一個自定義View,這些小的自定義View都盛放在一個自定義的ViewGroup中。然后所有的視圖都放在這個ViewGroup之上,這樣就相當(dāng)于做一個可動的背景。

詳解:

FloatObject

懸浮的物體,繼承自View,需要重寫onDraw方法,主要作用就是來畫出自己,并進行隨機曲線運動。

任何需要畫出的對象都需要繼承FloatObject,并重寫提供的drawFloatObject方法,在此方法中可以通過設(shè)置畫筆和畫布畫出任意圖形。比如下面是畫出一行文字:

public class FloatText extends FloatObject {
    String text;

    public FloatText(float posX, float posY, String text) {
        super(posX, posY);
        this.text = text;
        setAlpha(88);
        setColor(Color.WHITE);
    }

    @Override
    public void drawFloatObject(Canvas canvas, float x, float y, Paint paint) {
        paint.setTextSize(65);
        canvas.drawText(text, x, y, paint);
    }
}

隨機曲線:

其實最復(fù)雜的部分就是讓漂浮的物體做隨機無規(guī)則的曲線運動,并且每個漂浮物的速度不同,這樣整個漂浮動畫才更加自然。

我之前想過使用布朗運動,但是在網(wǎng)上找了好久也沒找到一個好用的算法。

最后只能還是使用3點賽貝爾曲線,使漂浮物沿著一條賽貝爾曲線運動,達到終點時,再隨機產(chǎn)生一條新的曲線,這樣就可以實現(xiàn)隨機曲線運動了。

控制運動的代碼如下:

public void drawFloatItem(Canvas canvas) {

        switch (status) {
            case START:
                // fade in
                if (isFade() && alpha <= ALPHA_LIMIT) {
                    paint.setAlpha(alpha);
                    alpha += ALPHA_PER_FRAME;
                } else {
                    setStatus(MOVE);
                }
                break;
            case MOVE:
                // 更新賽貝爾曲線點
                if (mCurDistance == 0) {
                    start = new PointF(x, y);
                    end = getRandomPoint((int)start.x, (int)start.y, (int) distance);// 取值范圍distance
                    c1 = getRandomPoint((int)start.x, (int)start.y, random.nextInt(width / 2)); // 取值范圍width/2
                    c2 = getRandomPoint(end.x, end.y, random.nextInt(width / 2));// 取值范圍width/2
                }

                // 計算塞貝兒曲線的當(dāng)前點
                PointF bezierPoint = CalculateBezierPoint(mCurDistance / distance, start, c1, c2, end);
                x = bezierPoint.x;
                y = bezierPoint.y;

                // 更新當(dāng)前路徑
                mCurDistance += MOVE_PER_FRAME;

                // 一段畫完后重置
                if (mCurDistance >= distance) {
                    mCurDistance = 0;
                }
                break;
            case END:
                // fade out
                if (isFade() && alpha > 0) {
                    paint.setAlpha(alpha);
                    alpha -= ALPHA_PER_FRAME;
                } else {
                    setStatus(FINISH);
                }
                break;
        }

        if (status != FINISH) {
            Log.e("drawFloatObject", x+", "+y);
            drawFloatObject(canvas, x ,y, paint);
        }
    }

關(guān)于賽貝爾曲線運動的算法都是復(fù)用之前寫的一篇文章ANDROID模擬火花粒子的滑動噴射效果,如果大家有興趣可以看看。

FloatBackground

FloatBackground繼承自FrameLayout,里面有一個用于存放FloatObject的集合。
FloatBackground的主要作用就是繪制所有的“漂浮物”,以及維護其生命周期:

初始化:

  private void initFloatObject(int width, int height) {
        for (FloatObject floatObject : floats) {
            int x = (int) (floatObject.posX * width);
            int y = (int) (floatObject.posY * height);
            floatObject.init(x, y, width, height);
        }
    }

繪制:

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (FloatObject floatObject : floats) {
            floatObject.drawFloatItem(canvas);
        }
        // 隔一段時間重繪一次, 動畫效果
        getHandler().postDelayed(runnable, DELAY);

    }
    
    // 重繪線程
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            invalidate();
            // 控制幀數(shù)
        }
    };

開始和結(jié)束:

    public void startFloat() {
        for (FloatObject floatObject : floats) {
            floatObject.setStatus(FloatObject.START);
        }
    }

    public void endFloat() {
        for (FloatObject floatObject : floats) {
            floatObject.setStatus(FloatObject.END);
        }
    }

使用

使用時非常簡單,在layout文件中將FloatBackground設(shè)置為最底層的視圖(其實就是當(dāng)作一個背景):

 <com.dean.library.FloatBackground
        android:id="@+id/float_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_gravity="center"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <Button
                android:id="@+id/start"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Start" />

            <Button
                android:id="@+id/end"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="End" />
        </LinearLayout>
    </com.dean.library.FloatBackground>

在代碼中進行如下調(diào)用:


        final FloatBackground floatBackground = (FloatBackground) this.findViewById(R.id.float_view);

        Button start = (Button) this.findViewById(R.id.start);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                floatBackground.startFloat();
            }
        });

        Button end = (Button) this.findViewById(R.id.end);
        end.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                floatBackground.endFloat();
            }
        });

        floatBackground.addFloatView(new FloatRect(0.2f, 0.3f, 30, 40));
        floatBackground.addFloatView(new FloatBitmap( this, 0.2f, 0.3f, R.drawable.gr_ptn_03));
        floatBackground.addFloatView(new FloatCircle( 0.8f, 0.8f));
        floatBackground.addFloatView(new FloatText( 0.3f, 0.6f, "E"));
        floatBackground.addFloatView(new FloatRing( 0.6f, 0.2f, 15 ,20));

比如在添加文字“漂浮物”時:floatBackground.addFloatView(new FloatText( 0.3f, 0.6f, "E"))
接收的三個參數(shù)分別為出生位置在屏幕寬的百分比,長的百分比,和顯示的文字。

Github

https://github.com/a396901990/FloatBackground

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

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,045評論 25 709
  • 2017,痛并快樂著。 2018我要永久的快樂著。 今天是2018年1月1日。我再也不要頹廢的活著,我會努力過好每...
    傾一生白了頭閱讀 156評論 8 2
  • (第一次在簡書上寫文章,打開寫作頁面之后體驗并沒有很好,改天寫個建議好了。) 序 在各種暑期實習(xí)生招聘全軍覆沒之后...
    李家城Jason閱讀 6,134評論 0 8
  • 下班了,吃完飯,坐在陽臺。 外面,好像都安靜了吧? 風(fēng),徐徐吹著。 很久沒有寫字了,已經(jīng)快要忘了文字曾帶來的快樂與...
    大蛟的來信閱讀 344評論 4 0
  • 臺風(fēng)
    燕云軒閱讀 311評論 0 0

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