簡(jiǎn)單實(shí)現(xiàn)滿屏表情下落的動(dòng)畫效果,你也可以

博文出處:簡(jiǎn)單實(shí)現(xiàn)滿屏表情下落的動(dòng)畫效果抵碟,你也可以桃漾,歡迎大家關(guān)注我的博客,謝謝拟逮!

首先我相信大家一定玩過(guò)微信吧撬统。之前在玩微信的時(shí)候,給好友發(fā)一句“圣誕快樂(lè)”就會(huì)有滿屏的圣誕樹往下掉敦迄,當(dāng)時(shí)覺(jué)得這個(gè)動(dòng)畫好酷恋追。正好在公司的項(xiàng)目中需要用到這樣的動(dòng)畫效果。于是寫了一個(gè)小Demo,就有了這篇文章罚屋。

下圖是做出的相關(guān)效果:

表情下落動(dòng)畫效果gif

看完上面的效果圖苦囱,大家一定都迫不及待地想要試一試了,那就讓我們來(lái)動(dòng)手吧脾猛。

首先我們定義一個(gè)實(shí)體類DropLook:

/**
 * 下落的表情
 */
public class DropLook {

    // x軸坐標(biāo)
    private float x;
    // y軸坐標(biāo)
    private float y;
    // 初始旋轉(zhuǎn)角度
    private float rotation;
    // 下落速度
    private float speed;
    // 旋轉(zhuǎn)速度
    private float rotationSpeed;
    // 寬度
    private int width;
    // 高度
    private int height;
    // 圖片
    private Bitmap bitmap;

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getRotationSpeed() {
        return rotationSpeed;
    }

    public void setRotationSpeed(float rotationSpeed) {
        this.rotationSpeed = rotationSpeed;
    }

    public float getRotation() {
        return rotation;
    }

    public void setRotation(float rotation) {
        this.rotation = rotation;
    }

    public float getSpeed() {
        return speed;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}

我們定義的實(shí)體類很簡(jiǎn)單撕彤,只是設(shè)置了如寬高、x猛拴,y坐標(biāo)羹铅、下落速度等。接下來(lái)我們?cè)賱?chuàng)建一個(gè)DropLookFactory類愉昆,用來(lái)創(chuàng)建DropLook對(duì)象职员。

public class DropLookFactory {

    private DropLookFactory() {

    }

    public static DropLook createDropLook(int width, int height,Bitmap originalBitmap) {
        DropLook look = new DropLook();
        if (originalBitmap == null) {
            throw new NullPointerException("originalBitmap cannot be null");
        }
        // 設(shè)置與圖片等寬
        look.setWidth(originalBitmap.getWidth());
        // 設(shè)置與圖片等高
        look.setHeight(originalBitmap.getHeight());
        // 設(shè)置起始位置的X坐標(biāo)
        look.setX((float) Math.random() * (width - look.getWidth()));
        // 設(shè)置起始位置的Y坐標(biāo)
        look.setY((float) Math.random() * (height - look.getHeight()));
        // 設(shè)置速度
        look.setSpeed(20 + (float) Math.random() * 40);
        // 設(shè)置初始旋轉(zhuǎn)角度
        look.setRotation((float) Math.random() * 180 - 90);
        // 設(shè)置旋轉(zhuǎn)速度
        look.setRotationSpeed((float) Math.random() * 90 - 60);
        // 設(shè)置圖片
        look.setBitmap(originalBitmap);
        return look;
    }

}

其中createDropLook(Context context, float xRange, Bitmap originalBitmap)的第一個(gè)參數(shù)代表著下落表情在x軸上的范圍,第二個(gè)參數(shù)代表在y軸上的范圍跛溉,第三個(gè)參數(shù)是表情的圖片焊切。在createDropLook方法中相信大家都看得懂,主要就是用隨機(jī)數(shù)初始化DropLook的坐標(biāo)及下落速度等倒谷。

好了蛛蒙,下面就是今天的重頭戲DropLookView糙箍,先來(lái)看看onMeasure():

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    if (widthMode == MeasureSpec.EXACTLY) {
        mWidth = widthSize;
    } else {
        mWidth = Tools.dip2px(getContext(),200);
    }
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    if (heightMode == MeasureSpec.EXACTLY) {
        mHeight = heightSize;
    } else {
        mHeight = Tools.dip2px(getContext(),200);
    }
    setMeasuredDimension(mWidth, mHeight);
    if (looks.size() == 0) {
        for (int i = 0; i < DEFAULT_DROP_LOOK_NUMS; ++i) {
            looks.add(DropLookFactory.createDropLook(mWidth, mHeight, mBitmap));
        }
        Log.i(TAG, "num = " + looks.size());
    }
}

onMeasure里主要是對(duì)View的測(cè)量渤愁,如果是wrap_content的話設(shè)置一個(gè)默認(rèn)的寬高度200dp。然后就是初始化DropLook深夯,looks是DropLook類的集合抖格,用于管理DropLook诺苹。而DEFAULT_LOOK_NUMS是默認(rèn)的looks集合的數(shù)量。

接下來(lái)就是最關(guān)鍵的onDraw():

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.save();
    long nowTime = System.currentTimeMillis();
    if (nowTime - startTime < 100) {
        try {
            Thread.sleep(100 + startTime - nowTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    for (int i = 0; i < DEFAULT_DROP_LOOK_NUMS; i++) {

        DropLook look = looks.get(i);
        mMatrix.setTranslate(-look.getWidth() / 2, -look.getHeight() / 2);
        mMatrix.postRotate(look.getRotation());
        mMatrix.postTranslate(look.getWidth() / 2 + look.getX(), look.getHeight() / 2 + look.getY());
        canvas.drawBitmap(look.getBitmap(), mMatrix, mPaint);

        look.setY(look.getY() + look.getSpeed());
        if (look.getY() > getHeight()) {
            look.setY((float) (0 - Math.random() * look.getHeight()));
        }

        look.setRotation(look.getRotation() + look.getRotationSpeed());
    }

    canvas.restore();
    startTime = System.currentTimeMillis();
    invalidate();
}

一開始判斷時(shí)間間隔如果沒(méi)有超過(guò)100ms雹拄,就讓線程睡眠一會(huì)收奔。然后就是用drawBitmap的方法把looks里面逐個(gè)繪制出來(lái)。并且再把look的y軸坐標(biāo)加上下落速度等滓玖,旋轉(zhuǎn)的角度也是如此坪哄。最后就是調(diào)用invalidate()不斷地重繪∈拼郏總體上并沒(méi)有什么難點(diǎn)翩肌。

以下是DropLookView的完整代碼:

/**
 * 表情下落view
 */
public class DropLookView extends View {

    // 表情
    private Bitmap mBitmap;
    // 所有表情集合
    List<DropLook> looks = new ArrayList();
    // view開始時(shí)間
    private long startTime;
    // view寬度
    private int mWidth;
    // view高度
    private int mHeight;
    // 畫筆
    private Paint mPaint;
    // 默認(rèn)表情下落數(shù)
    private static final int DEFAULT_DROP_LOOK_NUMS = 35;

    private static final String TAG = "DropLookView";

    private Matrix mMatrix = new Matrix();

    public DropLookView(Context context) {
        this(context, null);
    }

    public DropLookView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DropLookView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 圖片
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.d_5_xiaoku);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            mWidth = widthSize;
        } else {
            mWidth = Tools.dip2px(getContext(),200);
        }
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode == MeasureSpec.EXACTLY) {
            mHeight = heightSize;
        } else {
            mHeight = Tools.dip2px(getContext(),200);
        }
        setMeasuredDimension(mWidth, mHeight);
        if (looks.size() == 0) {
            for (int i = 0; i < DEFAULT_DROP_LOOK_NUMS; ++i) {
                looks.add(DropLookFactory.createDropLook(mWidth, mHeight, mBitmap));
            }
            Log.i(TAG, "num = " + looks.size());
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        long nowTime = System.currentTimeMillis();
        if (nowTime - startTime < 100) {
            try {
                Thread.sleep(100 + startTime - nowTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < DEFAULT_DROP_LOOK_NUMS; i++) {

            DropLook look = looks.get(i);
            mMatrix.setTranslate(-look.getWidth() / 2, -look.getHeight() / 2);
            mMatrix.postRotate(look.getRotation());
            mMatrix.postTranslate(look.getWidth() / 2 + look.getX(), look.getHeight() / 2 + look.getY());
            canvas.drawBitmap(look.getBitmap(), mMatrix, mPaint);

            look.setY(look.getY() + look.getSpeed());
            if (look.getY() > getHeight()) {
                look.setY((float) (0 - Math.random() * look.getHeight()));
            }

            look.setRotation(look.getRotation() + look.getRotationSpeed());
        }

        canvas.restore();
        startTime = System.currentTimeMillis();
        invalidate();
    }

}

該講的也差不多講完了,其實(shí)并沒(méi)有想象中的那么有難度禁悠,實(shí)現(xiàn)起來(lái)也比較容易念祭。當(dāng)然DropLookView也有需要改進(jìn)的地方。比如說(shuō)可以在布局文件中自定義表情下落的數(shù)量等碍侦。這些就需要自己根據(jù)需求來(lái)更改了粱坤,那今天就先這樣吧。

下面是本Demo的完整代碼:
DropLookView.rar

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓷产,一起剝皮案震驚了整個(gè)濱河市站玄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌濒旦,老刑警劉巖蜒什,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異疤估,居然都是意外死亡灾常,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門铃拇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钞瀑,“玉大人,你說(shuō)我怎么就攤上這事慷荔〉袷玻” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵显晶,是天一觀的道長(zhǎng)贷岸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)磷雇,這世上最難降的妖魔是什么偿警? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮唯笙,結(jié)果婚禮上螟蒸,老公的妹妹穿的比我還像新娘盒使。我一直安慰自己,他們只是感情好七嫌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布少办。 她就那樣靜靜地躺著,像睡著了一般诵原。 火紅的嫁衣襯著肌膚如雪英妓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天绍赛,我揣著相機(jī)與錄音鞋拟,去河邊找鬼。 笑死惹资,一個(gè)胖子當(dāng)著我的面吹牛贺纲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播褪测,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼猴誊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了侮措?” 一聲冷哼從身側(cè)響起懈叹,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎分扎,沒(méi)想到半個(gè)月后澄成,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畏吓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年墨状,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菲饼。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肾砂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宏悦,到底是詐尸還是另有隱情镐确,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布饼煞,位于F島的核電站源葫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砖瞧。R本人自食惡果不足惜息堂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芭届。 院中可真熱鬧储矩,春花似錦感耙、人聲如沸褂乍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逃片。三九已至屡拨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間褥实,已是汗流浹背呀狼。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留损离,地道東北人哥艇。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像僻澎,于是被迫代替她去往敵國(guó)和親貌踏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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