1
1
package com.smarttoolfactory.tutorial1_1basics.chapter9_animation
2
2
3
3
import android.graphics.Bitmap
4
+ import android.util.Log
4
5
import android.widget.Toast
5
6
import androidx.compose.animation.core.Animatable
6
7
import androidx.compose.animation.core.FastOutSlowInEasing
@@ -234,13 +235,12 @@ fun ParticleAnimationSample() {
234
235
particleState.startAnimation()
235
236
}
236
237
.disintegrate(
237
- progress = progress,
238
+ // progress = progress,
238
239
particleState = particleState,
239
240
onStart = {
240
241
Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
241
242
},
242
243
onEnd = {
243
- // particleState.animationStatus = AnimationStatus.Idle
244
244
Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
245
245
}
246
246
),
@@ -258,6 +258,7 @@ fun ParticleAnimationSample() {
258
258
.border(2 .dp, Color .Red )
259
259
.size(widthDp)
260
260
.clickable {
261
+ particleState2.changeProgressManually = true
261
262
particleState2.startAnimation()
262
263
}
263
264
.disintegrate(
@@ -267,7 +268,6 @@ fun ParticleAnimationSample() {
267
268
Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
268
269
},
269
270
onEnd = {
270
- // particleState2.animationStatus = AnimationStatus.Idle
271
271
Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
272
272
}
273
273
),
@@ -306,19 +306,23 @@ fun Modifier.disintegrate(
306
306
if (animationStatus != AnimationStatus .Idle ) {
307
307
308
308
withContext(Dispatchers .Default ) {
309
+
310
+ val currentBitmap = particleState.bitmap?.asAndroidBitmap()
311
+
309
312
val bitmap =
310
- if (particleState.bitmap == null || particleState.bitmap?. isRecycled== true ) {
313
+ if (currentBitmap == null || currentBitmap. isRecycled) {
311
314
graphicsLayer
312
315
.toImageBitmap()
313
316
.asAndroidBitmap()
314
317
.copy(Bitmap .Config .ARGB_8888 , false )
315
318
.apply {
316
319
this .prepareToDraw()
317
320
}
318
- } else particleState.bitmap
321
+
322
+ } else particleState.bitmap?.asAndroidBitmap()
319
323
320
324
bitmap?.let {
321
- particleState.bitmap = bitmap
325
+ particleState.bitmap = bitmap.asImageBitmap()
322
326
particleState.createParticles(
323
327
particleList = particleState.particleList,
324
328
particleSize = particleSizePx,
@@ -371,7 +375,9 @@ fun Modifier.disintegrate(
371
375
)
372
376
373
377
@Composable
374
- fun rememberParticleState (particleSize : Dp = 2.dp): ParticleState {
378
+ fun rememberParticleState (
379
+ particleSize : Dp = 2.dp,
380
+ ): ParticleState {
375
381
return remember {
376
382
ParticleState (particleSize)
377
383
}
@@ -391,15 +397,17 @@ class ParticleState internal constructor(particleSize: Dp) {
391
397
val progress: Float
392
398
get() = animatable.value
393
399
394
- var bitmap: Bitmap ? = null
400
+ var bitmap: ImageBitmap ? = null
395
401
internal set
396
402
397
403
var animationSpec = tween<Float >(
398
404
durationMillis = 2000 ,
399
405
easing = FastOutSlowInEasing
400
406
)
401
407
402
- private val strategy = DisintegrateStrategy ()
408
+ var changeProgressManually: Boolean = false
409
+
410
+ private val strategy: ParticleStrategy = DisintegrateStrategy ()
403
411
404
412
fun addParticle (particle : Particle ) {
405
413
particleList.add(particle)
@@ -408,7 +416,7 @@ class ParticleState internal constructor(particleSize: Dp) {
408
416
fun updateAndDrawParticles (
409
417
drawScope : DrawScope ,
410
418
particleList : SnapshotStateList <Particle >,
411
- bitmap : Bitmap ? ,
419
+ bitmap : ImageBitmap ? ,
412
420
progress : Float
413
421
) {
414
422
if (animationStatus != AnimationStatus .Idle ) {
@@ -441,19 +449,24 @@ class ParticleState internal constructor(particleSize: Dp) {
441
449
try {
442
450
onStart()
443
451
animatable.snapTo(0f )
444
- animatable.animateTo(
445
- targetValue = 1f ,
446
- animationSpec = animationSpec
447
- )
452
+ if (changeProgressManually.not ()) {
453
+ animatable.animateTo(
454
+ targetValue = 1f ,
455
+ animationSpec = animationSpec
456
+ )
457
+ }
448
458
} catch (e: CancellationException ) {
449
- println ( " FAILED: ${e.message} " )
459
+ Log .e( " Particle " , " ${e.message} " )
450
460
} finally {
451
- onEnd()
461
+ if (changeProgressManually.not ()) {
462
+ animationStatus = AnimationStatus .Idle
463
+ onEnd()
464
+ }
452
465
}
453
466
}
454
467
455
468
fun dispose () {
456
- bitmap?.recycle()
469
+ bitmap?.asAndroidBitmap()?. recycle()
457
470
}
458
471
}
459
472
@@ -561,7 +574,7 @@ open class DisintegrateStrategy : ParticleStrategy {
561
574
override fun updateAndDrawParticles (
562
575
drawScope : DrawScope ,
563
576
particleList : SnapshotStateList <Particle >,
564
- bitmap : Bitmap ,
577
+ imageBitmap : ImageBitmap ,
565
578
progress : Float ,
566
579
) {
567
580
with (drawScope) {
@@ -587,13 +600,10 @@ open class DisintegrateStrategy : ParticleStrategy {
587
600
clipRect(
588
601
left = progress * size.width * 2f
589
602
) {
590
- bitmap?.asImageBitmap()?.let {
591
- // Source
592
- drawImage(
593
- image = it,
594
- blendMode = BlendMode .SrcOut
595
- )
596
- }
603
+ drawImage(
604
+ image = imageBitmap,
605
+ blendMode = BlendMode .SrcOut
606
+ )
597
607
}
598
608
599
609
// For debugging
@@ -622,9 +632,9 @@ open class DisintegrateStrategy : ParticleStrategy {
622
632
623
633
// Set size
624
634
val width =
625
- initialSize.width + (endSize.width - initialSize.width) * currentTime* . 5f
635
+ initialSize.width + (endSize.width - initialSize.width) * currentTime
626
636
val height =
627
- initialSize.height + (endSize.height - initialSize.height) * currentTime* . 5f
637
+ initialSize.height + (endSize.height - initialSize.height) * currentTime
628
638
currentSize = Size (width, height)
629
639
630
640
// Set alpha
@@ -647,7 +657,23 @@ open class DisintegrateStrategy : ParticleStrategy {
647
657
}
648
658
}
649
659
660
+ data class ParticleBoundaries (
661
+ val velocityHorizontalLowerBound : ClosedRange <Float >? = null ,
662
+ val velocityHorizontalUpperBound : ClosedRange <Float >? = null ,
663
+ val velocityVerticalLowerBound : ClosedRange <Float >? = null ,
664
+ val velocityVerticalUpperBound : ClosedRange <Float >? = null ,
665
+ val accelerationLowerBound : ClosedRange <Float >? = null ,
666
+ val accelerationLowerUpperBound : ClosedRange <Float >? = null ,
667
+ val startSizeLowerBound : Size ? = null ,
668
+ val startSizeUpperBound : Size ? = null ,
669
+ val endSizeLowerBound : Size ? = null ,
670
+ val endSizeUpperBound : Size ? = null ,
671
+ val alphaLowerBound : ClosedRange <Float >? = null ,
672
+ val alphaUpperbound : ClosedRange <Float >? = null
673
+ )
674
+
650
675
interface ParticleStrategy {
676
+
651
677
fun createParticles (
652
678
particleList : SnapshotStateList <Particle >,
653
679
particleSize : Int ,
@@ -657,7 +683,7 @@ interface ParticleStrategy {
657
683
fun updateAndDrawParticles (
658
684
drawScope : DrawScope ,
659
685
particleList : SnapshotStateList <Particle >,
660
- bitmap : Bitmap ,
686
+ imageBitmap : ImageBitmap ,
661
687
progress : Float
662
688
)
663
689
@@ -729,7 +755,7 @@ data class Particle(
729
755
}
730
756
731
757
enum class AnimationStatus {
732
- Idle , Initializing , Playing
758
+ Idle , Initializing , Playing , Finished
733
759
}
734
760
735
761
private fun DrawScope.drawWithLayer (block : DrawScope .() -> Unit ) {
0 commit comments