@@ -38,13 +38,14 @@ import androidx.compose.ui.composed
3838import  androidx.compose.ui.draw.drawWithCache 
3939import  androidx.compose.ui.geometry.Offset 
4040import  androidx.compose.ui.geometry.Size 
41+ import  androidx.compose.ui.graphics.BlendMode 
4142import  androidx.compose.ui.graphics.Color 
4243import  androidx.compose.ui.graphics.ImageBitmap 
4344import  androidx.compose.ui.graphics.asAndroidBitmap 
4445import  androidx.compose.ui.graphics.asImageBitmap 
4546import  androidx.compose.ui.graphics.drawscope.DrawScope 
46- import  androidx.compose.ui.graphics.drawscope.Stroke 
4747import  androidx.compose.ui.graphics.drawscope.clipRect 
48+ import  androidx.compose.ui.graphics.nativeCanvas 
4849import  androidx.compose.ui.graphics.rememberGraphicsLayer 
4950import  androidx.compose.ui.platform.LocalContext 
5051import  androidx.compose.ui.platform.LocalDensity 
@@ -57,8 +58,10 @@ import androidx.compose.ui.unit.sp
5758import  com.smarttoolfactory.tutorial1_1basics.R 
5859import  com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange 
5960import  com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale 
61+ import  com.smarttoolfactory.tutorial1_1basics.ui.BlueGrey400 
6062import  com.smarttoolfactory.tutorial1_1basics.ui.Pink400 
6163import  kotlinx.coroutines.CancellationException 
64+ import  kotlin.math.roundToInt 
6265import  kotlin.random.Random 
6366
6467@Preview
@@ -158,6 +161,8 @@ fun SingleParticleTrajectorySample() {
158161 fontSize =  18 .sp
159162 )
160163 }
164+ 165+  Text (" Progress: ${(progress *  100 ).roundToInt() /  100f } " 
161166 Slider (
162167 modifier =  Modifier .fillMaxWidth(),
163168 value =  progress,
@@ -233,6 +238,8 @@ fun ParticleAnimationSample() {
233238 contentDescription =  null 
234239 )
235240
241+  Text (" Progress: ${(progress *  100 ).roundToInt() /  100f } " 
242+ 236243 Slider (
237244 value =  progress,
238245 onValueChange =  {
@@ -254,15 +261,15 @@ data class Particle(
254261 val  initialCenter :  Offset ,
255262 val  initialSize :  Size ,
256263 val  endSize :  Size ,
257-  val  color :  Color ,
258264 val  trajectoryProgressRange :  ClosedRange <Float > = 0f ..1f ,
265+  var  color :  Color ,
259266 var  velocity :  Velocity  = Velocity (0f, 0f),
260267 var  acceleration :  Float  = -2  * velocity.y
261268) {
262269 var  currentPosition:  Offset  =  initialCenter
263270 internal  set
264271 var  currentSize:  Size  =  initialSize
265- 272+ internal  set 
266273 var  alpha =  1f 
267274 internal  set
268275 var  currentTime:  Float  =  0f 
@@ -385,39 +392,44 @@ class ParticleState internal constructor(particleSize: Dp) {
385392 with (drawScope) {
386393 if  (animationStatus !=  AnimationStatus .Idle ) {
387394
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- 397-  particleList.forEach { particle -> 
398- 399-  updateParticle(progress, particle)
400- 401-  val  color =  particle.color
402-  val  radius =  particle.currentSize.width *  .65f 
403-  val  position =  particle.currentPosition
404-  val  alpha =  particle.alpha
405- 406-  drawCircle(
407-  color =  color,
408-  radius =  radius,
409-  center =  position,
410-  alpha =  alpha
411-  )
412-  }
395+  drawWithLayer {
413396
414-  //  For debugging
415-  drawRect(
416-  color =  Color .Black ,
417-  topLeft =  Offset (progress *  size.width, 0f ),
418-  size =  Size (size.width -  progress *  size.width, size.height),
419-  style =  Stroke (4 .dp.toPx())
420-  )
397+  particleList.forEach { particle -> 
398+ 399+  updateParticle(progress, particle)
400+ 401+  val  color =  particle.color
402+  val  radius =  particle.currentSize.width *  .65f 
403+  val  position =  particle.currentPosition
404+  val  alpha =  particle.alpha
405+ 406+  drawCircle(
407+  color =  color,
408+  radius =  radius,
409+  center =  position,
410+  alpha =  alpha
411+  )
412+  }
413+ 414+  clipRect(
415+  left =  progress *  size.width
416+  ) {
417+  bitmap?.asImageBitmap()?.let  {
418+  drawImage(
419+  image =  it,
420+  blendMode =  BlendMode .SrcIn 
421+  )
422+  }
423+  }
424+ 425+  //  For debugging
426+ //  drawRect(
427+ //  color = Color.Black,
428+ //  topLeft = Offset(progress * size.width, 0f),
429+ //  size = Size(size.width - progress * size.width, size.height),
430+ //  style = Stroke(4.dp.toPx())
431+ //  )
432+  }
421433 }
422434 }
423435 }
@@ -627,3 +639,11 @@ fun getTrajectoryRange(
627639enum  class  AnimationStatus  {
628640 Idle , Initializing , Playing 
629641}
642+ 643+ private  fun  DrawScope.drawWithLayer (block :  DrawScope .() ->  Unit ) {
644+  with (drawContext.canvas.nativeCanvas) {
645+  val  checkPoint =  saveLayer(null , null )
646+  block()
647+  restoreToCount(checkPoint)
648+  }
649+ }
0 commit comments