一個酷炫的 android 粒子動畫庫

一、靈感

做這個粒子動畫庫的靈感來自于 MIUI 卸載應用時的動畫:


image

這個爆炸的粒子效果看起來很酷炫,而且粒子顏色是從 icon 中拿到的。

最開始我簡單實現(xiàn)了類似爆炸的效果,后來想到可以直接擴展一下,寫一個通用的粒子動畫庫。

二、使用

項目地址:https://github.com/ultimateHandsomeBoy666/Particle

Particle 是一個使用 kotlin 編寫的粒子動畫庫,可以用幾行代碼輕松搞定一個粒子動畫。同時也支持高度自定義的粒子動畫軌跡,可以打造出非常炫酷的自定義動畫。這個項目發(fā)布了 0.1 版本在 JitPack 上,按如下操作引入:

在根目錄的 build.gradle 中的 allprojects 中添加(注意不是 buildScript):

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

然后在你的項目中引入依賴即可。

implementation 'com.github.ultimateHandsomeBoy666:Particle:0.1'

在引入了 Particle 之后,只需要下面幾行簡單的代碼,就可以實現(xiàn)上面的粒子爆炸效果:

Particles.with(context, container) // container 是粒子動畫的宿主父 ViewGroup
        .colorFromView(button)// 從 button 中采樣顏色
        .particleNum(200)// 一共 200 個粒子
        .anchor(button)// 把 button 作為動畫的錨點
        .shape(Shape.CIRCLE)// 粒子形狀是圓形
        .radius(2, 6)// 粒子隨機半徑 2~6
        .anim(ParticleAnimation.EXPLOSION)// 使用爆炸動畫
        .start()
image

三、粒子形狀

粒子的形狀支持圓形、三角形、矩形、五角星以及矢量圖形及位圖,并且支持多種圖形粒子混合。

下面詳細說明。

Shape.CIRCLEShape.HOLLOWCIRCLE

  • 圓形和空心圓

  • 使用 radius 定義圓的大小??招膱A使用 strokeWidth 定義粗細。

Shape.TRIANGLEShape.HOLLOWTRIANGLE

  • 實心三角形和空心三角形

  • 使用 widthheight 定義三角形的大小。空心三角形使用 strokeWidth 定義粗細。

Shape.RECTANGLEShape.HOLLOWRECTANGLE

  • 實心矩形和空心矩形。

  • 使用 widthheight 定義矩形的大小??招木匦问褂?strokeWidth 定義粗細。

Shape.PENTACLEShape.HOLLOWPENTACLE

  • 實心五角星和空心五角星

  • 使用 radius 定義五角星外接圓的大小??招奈褰切鞘褂?strokeWidth 定義粗細。

Shape.BITMAP

  • 支持位圖。

  • 支持矢量圖,只需要把矢量圖 xml 的資源 id 傳入即可。

  • 圖片粒子不受 color 設置的影響。

除了上述單種圖形以外,還支持多種圖形的混合粒子,如下:

<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/85bcaf99629243aaa897d3069b698e25~tplv-k3u1fbpfcp-watermark.image"
width = "180" height = "400"/>

四、粒子動畫

動畫控制

粒子的動畫使用 ValueAnimator 來控制,可以自行定義 animator 來控制動畫的行為,包括動畫時長、Interpolater、重復、開始結(jié)束的監(jiān)聽等等。

粒子特效

目前僅支持粒子在運動過程中的旋轉(zhuǎn),如下。后續(xù)會增加更多效果

image

粒子軌跡

粒子軌跡的控制使用 IPathGenerator 接口的派生類來完成。庫中自帶四種軌跡動畫,分別是:

  • ParticleAnimation.EXPLOSION 爆炸??效果
  • ParticleAnimation.RISE 粒子上升
  • ParticleAnimation.FALL 粒子下降
  • ParticleAnimation.FIREWORK 煙花??效果

如果想要自定義粒子運動軌跡的話,可以繼承 IPathGenerator 接口,復寫生成粒子坐標的方法:

private fun createPathGenerator(): IPathGenerator {
  // LinearPathGenerator 庫中自帶
        return object : LinearPathGenerator() {
            val cos = Random.nextDouble(-1.0, 1.0)
            val sin = Random.nextDouble(-1.0, 1.0)

            override fun getCurrentCoord(progress: Float, duration: Long): Pair<Int, Int> {
              // 在這里寫你想要的粒子軌跡
                val originalX = distance * progress
                val originalY = 100 * sin(originalX / 50)
                val x = originalX * cos - originalY * sin
                val y = originalX * sin + originalY * cos
                return Pair((0.01 * x * originalY).toInt(), (0.008 * y * originalX).toInt())
            }
        }
    }

然后把這個返回 IPathGenerator 的方法通過高階函數(shù)的形式傳入即可:

particleManager!!.colorFromView(button)
                .particleNum(300)
                .anchor(it)
                .shape(Shape.CIRCLE, Shape.BITMAP)
                .radius(8, 12)
                .strokeWidth(10f)
                .size(20, 20)
                .rotation(Rotation(600))
                .bitmap(R.drawable.ic_thumbs_up)
                .anim(ParticleAnimation.with({
                  // 控制動畫的animator
                    createAnimator()
                }, {
                  // 粒子運動的軌跡
                    createPathGenerator()
                })).start()

上述代碼中的 ParticleAnimation.with 方法接受兩個高階函數(shù)分別生成動畫控制和粒子軌跡。

fun with(animator: () -> ValueAnimator = DEFAULT_ANIMATOR_LAMBDA,
        generator: () -> IPathGenerator): ParticleAnimation {
    return ParticleAnimation(generator, animator)
}

終于,經(jīng)過上面的折騰,可以得到下面的酷炫動畫:

image

當然,只要你想要,可以構(gòu)造出無限多的粒子動畫軌跡,不過這可能要求一點數(shù)學功底??。

https://github.com/ultimateHandsomeBoy666/Particle 目錄下有一份我之前試驗的比較酷炫的軌跡公式合集,可以參考。

五、注意事項

  • 粒子動畫比較消耗內(nèi)存和 CPU,所以粒子數(shù)目太多,比如超過 1000 的話,可能會有卡頓。
  • 默認在動畫結(jié)束的時候,粒子是不會消失的。如果要讓粒子在動畫結(jié)束時消失,可以自定義 ValueAnimator 監(jiān)聽動畫結(jié)束,在結(jié)束時調(diào)用 ParticleManager.hide() 方法來隱藏粒子。
  • 如果需要反復觸發(fā)粒子動畫,比如按一次按鈕觸發(fā)一次,可以使用一個全局的 particleManager 變量來啟動和取消粒子動畫,可以避免內(nèi)存消耗和內(nèi)存抖動。比如:
particleManager = Particles.with(this, container)
button.setOnClickListener {
        
    particleManager!!.colorFromView(button)
                      .particleNum(300)
                      .anchor(it)
                      .shape(Shape.CIRCLE, Shape.BITMAP)
                      .radius(8, 12)
                      .rotation(Rotation(600))
                      .anim(ParticleAnimation.EXPLOSION)

    particleManager!!.start()
}

六、最后

這個項目暫時除了第一個版本,也是我自己第一個開源發(fā)布的項目,會花一些時間精力去維護。

  • 后續(xù)會增加更多粒子特效,比如粒子運動過程中的尺寸、透明度、顏色等改變
  • 再后續(xù)可能會出一份 compose 版本??

最后,https://github.com/ultimateHandsomeBoy666/Particle 項目地址在這里,歡迎 fork、pr、issues、star,求求大家點個小星星吧???,感謝!

?著作權(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)容

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