@@ -41,8 +41,10 @@ import androidx.compose.ui.geometry.Size
4141import  androidx.compose.ui.graphics.Color 
4242import  androidx.compose.ui.graphics.ImageBitmap 
4343import  androidx.compose.ui.graphics.asAndroidBitmap 
44+ import  androidx.compose.ui.graphics.asImageBitmap 
4445import  androidx.compose.ui.graphics.drawscope.DrawScope 
4546import  androidx.compose.ui.graphics.drawscope.Stroke 
47+ import  androidx.compose.ui.graphics.drawscope.clipRect 
4648import  androidx.compose.ui.graphics.rememberGraphicsLayer 
4749import  androidx.compose.ui.platform.LocalContext 
4850import  androidx.compose.ui.platform.LocalDensity 
@@ -59,7 +61,6 @@ import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
5961import  kotlinx.coroutines.CancellationException 
6062import  kotlin.random.Random 
6163
62- 6364@Preview
6465@Composable
6566fun  SingleParticleTrajectorySample () {
@@ -219,12 +220,13 @@ fun ParticleAnimationSample() {
219220 .border(2 .dp, Color .Red )
220221 .size(widthDp)
221222 .disintegrate(
222- //  progress = progress,
223+  progress =  progress,
223224 particleState =  particleState,
224225 onStart =  {
225226 Toast .makeText(context, " Animation started..." Toast .LENGTH_SHORT ).show()
226227 },
227228 onEnd =  {
229+ //  particleState.animationStatus = AnimationStatus.Idle
228230 Toast .makeText(context, " Animation ended..." Toast .LENGTH_SHORT ).show()
229231 }
230232 ),
@@ -323,22 +325,23 @@ fun Modifier.disintegrate(
323325 }
324326 }
325327
326-  Modifier .drawWithCache {
327-  onDrawWithContent {
328-  if  (animationStatus !=  AnimationStatus .Playing ) {
329-  drawContent()
330-  graphicsLayer.record {
331-  this @onDrawWithContent.drawContent()
328+  Modifier 
329+  .drawWithCache {
330+  onDrawWithContent {
331+  if  (animationStatus !=  AnimationStatus .Playing ) {
332+  drawContent()
333+  graphicsLayer.record {
334+  this @onDrawWithContent.drawContent()
335+  }
332336 }
333-  }
334337
335-  particleState.updateAndDrawParticles(
336-  drawScope =  this ,
337-  particleList =  particleState.particleList,
338-  progress =  progress
339-  )
338+  particleState.updateAndDrawParticles(
339+  drawScope =  this ,
340+  particleList =  particleState.particleList,
341+  progress =  progress
342+  )
343+  }
340344 }
341-  }
342345}
343346
344347@Composable
@@ -365,6 +368,11 @@ class ParticleState internal constructor(particleSize: Dp) {
365368 var  bitmap:  Bitmap ?  =  null 
366369 internal  set
367370
371+  var  animationSpec =  tween<Float >(
372+  durationMillis =  2000 ,
373+  easing =  FastOutSlowInEasing 
374+  )
375+ 368376 fun  addParticle (particle :  Particle ) {
369377 particleList.add(particle)
370378 }
@@ -377,6 +385,15 @@ class ParticleState internal constructor(particleSize: Dp) {
377385 with (drawScope) {
378386 if  (animationStatus !=  AnimationStatus .Idle ) {
379387
388+  //  TODO disintegrate image non-uniformly, with blend mode of particles
389+ //  clipRect(
390+ //  left = progress * size.width
391+ //  ) {
392+ //  bitmap?.asImageBitmap()?.let {
393+ //  drawImage(it)
394+ //  }
395+ //  }
396+ 380397 particleList.forEach { particle -> 
381398
382399 updateParticle(progress, particle)
@@ -394,13 +411,6 @@ class ParticleState internal constructor(particleSize: Dp) {
394411 )
395412 }
396413
397-  //  TODO disintegrate image non-uniformly, with blend mode of particles
398- //  clipRect(
399- //  left = progress * size.width
400- //  ) {
401- //  this@onDrawWithContent.drawContent()
402- //  }
403- 404414 //  For debugging
405415 drawRect(
406416 color =  Color .Black ,
@@ -422,7 +432,6 @@ class ParticleState internal constructor(particleSize: Dp) {
422432 val  width =  bitmap.width
423433 val  height =  bitmap.height
424434
425- 426435 val  particleRadius =  particleSize /  2 
427436
428437 //  divide image into squares based on particle size
@@ -467,9 +476,11 @@ class ParticleState internal constructor(particleSize: Dp) {
467476 //  Add some vertical randomization for trajectory so particles don't start
468477 //  animating vertically as well. Particles with smaller y value in same x
469478 //  coordinate tend to start earlier
479+  val  startYOffset = 
480+  (fractionToImageHeight *  Random .nextFloat()).coerceAtMost(.2f )
481+ 470482 trajectoryProgressRange = 
471-  trajectoryProgressRange.start +  fractionToImageHeight *  Random .nextFloat()
472-  .coerceAtMost(.2f ).. trajectoryProgressRange.endInclusive
483+  trajectoryProgressRange.start +  startYOffset.. trajectoryProgressRange.endInclusive
473484
474485 val  endSize =  randomInRange(0f , particleSize.toFloat() *  .5f )
475486
@@ -565,13 +576,14 @@ class ParticleState internal constructor(particleSize: Dp) {
565576 try  {
566577 onStart()
567578 animatable.snapTo(0f )
568-  animatable.animateTo(1f , tween(durationMillis =  2400 , easing =  FastOutSlowInEasing ))
569-  animationStatus =  AnimationStatus .Idle 
579+  animatable.animateTo(
580+  targetValue =  1f ,
581+  animationSpec =  animationSpec
582+  )
570583 } catch  (e:  CancellationException ) {
571584 println (" FAILED: ${e.message} " 
572585 } finally  {
573586 onEnd()
574-  animationStatus =  AnimationStatus .Idle 
575587 }
576588 }
577589
0 commit comments