一、靈感
做這個粒子動畫庫的靈感來自于 MIUI 卸載應用時的動畫:
這個爆炸的粒子效果看起來很酷炫,而且粒子顏色是從 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()
三、粒子形狀
粒子的形狀支持圓形、三角形、矩形、五角星以及矢量圖形及位圖,并且支持多種圖形粒子混合。
下面詳細說明。
Shape.CIRCLE 和 Shape.HOLLOWCIRCLE
圓形和空心圓
使用
radius定義圓的大小??招膱A使用strokeWidth定義粗細。
Shape.TRIANGLE 和 Shape.HOLLOWTRIANGLE
實心三角形和空心三角形
使用
width和height定義三角形的大小。空心三角形使用strokeWidth定義粗細。
Shape.RECTANGLE 和 Shape.HOLLOWRECTANGLE
實心矩形和空心矩形。
使用
width和height定義矩形的大小??招木匦问褂?strokeWidth定義粗細。
Shape.PENTACLE 和 Shape.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ù)會增加更多效果
粒子軌跡
粒子軌跡的控制使用 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)過上面的折騰,可以得到下面的酷炫動畫:
當然,只要你想要,可以構(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,求求大家點個小星星吧???,感謝!