@@ -308,16 +308,13 @@ fun Modifier.disintegrate(
308
308
withContext(Dispatchers .Default ) {
309
309
val bitmap =
310
310
if (particleState.bitmap == null || particleState.bitmap?.isRecycled == true ) {
311
-
312
- val bitmap = graphicsLayer
311
+ graphicsLayer
313
312
.toImageBitmap()
314
313
.asAndroidBitmap()
315
314
.copy(Bitmap .Config .ARGB_8888 , false )
316
315
.apply {
317
316
this .prepareToDraw()
318
317
}
319
- bitmap
320
-
321
318
} else particleState.bitmap
322
319
323
320
bitmap?.let {
@@ -352,6 +349,7 @@ fun Modifier.disintegrate(
352
349
particleState.updateAndDrawParticles(
353
350
drawScope = this ,
354
351
particleList = particleState.particleList,
352
+ bitmap = particleState.bitmap,
355
353
progress = progress
356
354
)
357
355
}
@@ -401,61 +399,67 @@ class ParticleState internal constructor(particleSize: Dp) {
401
399
easing = FastOutSlowInEasing
402
400
)
403
401
402
+ private val strategy = DisintegrateStrategy ()
403
+
404
404
fun addParticle (particle : Particle ) {
405
405
particleList.add(particle)
406
406
}
407
407
408
408
fun updateAndDrawParticles (
409
409
drawScope : DrawScope ,
410
410
particleList : SnapshotStateList <Particle >,
411
+ bitmap : Bitmap ? ,
411
412
progress : Float
412
413
) {
413
- with (drawScope ) {
414
- if (animationStatus != AnimationStatus . Idle ) {
415
-
416
- drawWithLayer {
417
- particleList.forEach { particle ->
418
- updateParticle(progress, particle)
414
+ if (animationStatus != AnimationStatus . Idle ) {
415
+ bitmap?. let {
416
+ strategy.updateAndDrawParticles(drawScope, particleList, bitmap, progress)
417
+ }
418
+ }
419
+ }
419
420
420
- val color = particle.color
421
- val radius = particle.currentSize.width * .5f
422
- val position = particle.currentPosition
423
- val alpha = particle.alpha
421
+ fun createParticles (
422
+ particleList : SnapshotStateList <Particle >,
423
+ particleSize : Int ,
424
+ bitmap : Bitmap
425
+ ) {
426
+ strategy.createParticles(particleList, particleSize, bitmap)
427
+ }
424
428
425
- // Destination
426
- drawCircle(
427
- color = color,
428
- radius = radius,
429
- center = position,
430
- alpha = alpha
431
- )
432
- }
429
+ fun updateParticle (progress : Float , particle : Particle ) {
430
+ strategy.updateParticle(progress, particle)
431
+ }
433
432
434
- clipRect(
435
- left = progress * size.width * 2f
436
- ) {
437
- bitmap?.asImageBitmap()?.let {
438
- // Source
439
- drawImage(
440
- image = it,
441
- blendMode = BlendMode .SrcOut
442
- )
443
- }
444
- }
433
+ fun startAnimation () {
434
+ animationStatus = AnimationStatus .Initializing
435
+ }
445
436
446
- // For debugging
447
- drawRect(
448
- color = Color .Black ,
449
- topLeft = Offset (progress * size.width, 0f ),
450
- size = Size (size.width - progress * size.width, size.height),
451
- style = Stroke (4 .dp.toPx())
452
- )
453
- }
454
- }
437
+ suspend fun animate (
438
+ onStart : () -> Unit ,
439
+ onEnd : () -> Unit
440
+ ) {
441
+ try {
442
+ onStart()
443
+ animatable.snapTo(0f )
444
+ animatable.animateTo(
445
+ targetValue = 1f ,
446
+ animationSpec = animationSpec
447
+ )
448
+ } catch (e: CancellationException ) {
449
+ println (" FAILED: ${e.message} " )
450
+ } finally {
451
+ onEnd()
455
452
}
456
453
}
457
454
458
- fun createParticles (
455
+ fun dispose () {
456
+ bitmap?.recycle()
457
+ }
458
+ }
459
+
460
+ open class DisintegrateStrategy : ParticleStrategy {
461
+
462
+ override fun createParticles (
459
463
particleList : SnapshotStateList <Particle >,
460
464
particleSize : Int ,
461
465
bitmap : Bitmap
@@ -494,15 +498,14 @@ class ParticleState internal constructor(particleSize: Dp) {
494
498
495
499
// Get trajectory for each 5 percent of the image in x direction
496
500
// This creates wave effect where particles at the start animation earlier
497
- val sectionFraction = 0.05f
498
- val particleTimeEnd = 0.5f
501
+ val sectionFraction = ParticleCreationFraction / 10f
499
502
500
503
// This range is between 0-0.5f to display all of the particles
501
504
// until half of the progress is reached
502
505
var trajectoryProgressRange = getTrajectoryRange(
503
506
fraction = fractionToImageWidth,
504
507
sectionFraction = sectionFraction,
505
- until = particleTimeEnd
508
+ until = ParticleCreationFraction
506
509
)
507
510
508
511
// Add randomization for trajectory so particles don't start
@@ -555,7 +558,56 @@ class ParticleState internal constructor(particleSize: Dp) {
555
558
}
556
559
}
557
560
558
- fun updateParticle (progress : Float , particle : Particle ) {
561
+ override fun updateAndDrawParticles (
562
+ drawScope : DrawScope ,
563
+ particleList : SnapshotStateList <Particle >,
564
+ bitmap : Bitmap ,
565
+ progress : Float ,
566
+ ) {
567
+ with (drawScope) {
568
+
569
+ drawWithLayer {
570
+ particleList.forEach { particle ->
571
+ updateParticle(progress, particle)
572
+
573
+ val color = particle.color
574
+ val radius = particle.currentSize.width * .5f
575
+ val position = particle.currentPosition
576
+ val alpha = particle.alpha
577
+
578
+ // Destination
579
+ drawCircle(
580
+ color = color,
581
+ radius = radius,
582
+ center = position,
583
+ alpha = alpha
584
+ )
585
+ }
586
+
587
+ clipRect(
588
+ left = progress * size.width * 2f
589
+ ) {
590
+ bitmap?.asImageBitmap()?.let {
591
+ // Source
592
+ drawImage(
593
+ image = it,
594
+ blendMode = BlendMode .SrcOut
595
+ )
596
+ }
597
+ }
598
+
599
+ // For debugging
600
+ drawRect(
601
+ color = Color .Black ,
602
+ topLeft = Offset (progress * size.width, 0f ),
603
+ size = Size (size.width - progress * size.width, size.height),
604
+ style = Stroke (4 .dp.toPx())
605
+ )
606
+ }
607
+ }
608
+ }
609
+
610
+ override fun updateParticle (progress : Float , particle : Particle ) {
559
611
particle.run {
560
612
// Trajectory progress translates progress from 0f-1f to
561
613
// trajectoryStart-trajectoryEnd
@@ -573,7 +625,6 @@ class ParticleState internal constructor(particleSize: Dp) {
573
625
initialSize.width + (endSize.width - initialSize.width) * currentTime * .5f
574
626
val height =
575
627
initialSize.height + (endSize.height - initialSize.height) * currentTime * .5f
576
-
577
628
currentSize = Size (width, height)
578
629
579
630
// Set alpha
@@ -587,46 +638,30 @@ class ParticleState internal constructor(particleSize: Dp) {
587
638
val horizontalDisplacement = velocity.x * currentTime
588
639
val verticalDisplacement =
589
640
velocity.y * currentTime + 0.5f * acceleration * currentTime * currentTime
641
+
590
642
currentPosition = Offset (
591
643
x = initialCenter.x + horizontalDisplacement,
592
644
y = initialCenter.y + verticalDisplacement
593
645
)
594
646
}
595
647
}
596
-
597
- fun startAnimation () {
598
- animationStatus = AnimationStatus .Initializing
599
- }
600
-
601
- suspend fun animate (
602
- onStart : () -> Unit ,
603
- onEnd : () -> Unit
604
- ) {
605
- try {
606
- onStart()
607
- animatable.snapTo(0f )
608
- animatable.animateTo(
609
- targetValue = 1f ,
610
- animationSpec = animationSpec
611
- )
612
- } catch (e: CancellationException ) {
613
- println (" FAILED: ${e.message} " )
614
- } finally {
615
- onEnd()
616
- }
617
- }
618
-
619
- fun dispose () {
620
- bitmap?.recycle()
621
- }
622
648
}
623
649
624
- interface DisintegrationStrategy {
625
- fun updateParticle (progress : Float , particle : Particle )
650
+ interface ParticleStrategy {
651
+ fun createParticles (
652
+ particleList : SnapshotStateList <Particle >,
653
+ particleSize : Int ,
654
+ bitmap : Bitmap
655
+ )
626
656
627
- fun createParticles (particleSize : Int , imageBitmap : ImageBitmap )
657
+ fun updateAndDrawParticles (
658
+ drawScope : DrawScope ,
659
+ particleList : SnapshotStateList <Particle >,
660
+ bitmap : Bitmap ,
661
+ progress : Float
662
+ )
628
663
629
- fun updateAndDrawParticles ( drawScope : DrawScope )
664
+ fun updateParticle ( progress : Float , particle : Particle )
630
665
}
631
666
632
667
/* *
@@ -704,3 +739,5 @@ private fun DrawScope.drawWithLayer(block: DrawScope.() -> Unit) {
704
739
restoreToCount(checkPoint)
705
740
}
706
741
}
742
+
743
+ private const val ParticleCreationFraction = 0.5f
0 commit comments