@@ -31,6 +31,7 @@ import androidx.compose.runtime.mutableStateListOf
31
31
import androidx.compose.runtime.mutableStateOf
32
32
import androidx.compose.runtime.remember
33
33
import androidx.compose.runtime.setValue
34
+ import androidx.compose.runtime.snapshots.SnapshotStateList
34
35
import androidx.compose.ui.Alignment
35
36
import androidx.compose.ui.Modifier
36
37
import androidx.compose.ui.composed
@@ -40,20 +41,20 @@ import androidx.compose.ui.geometry.Size
40
41
import androidx.compose.ui.graphics.Color
41
42
import androidx.compose.ui.graphics.ImageBitmap
42
43
import androidx.compose.ui.graphics.asAndroidBitmap
43
- import androidx.compose.ui.graphics.asImageBitmap
44
+ import androidx.compose.ui.graphics.drawscope.DrawScope
44
45
import androidx.compose.ui.graphics.drawscope.Stroke
45
46
import androidx.compose.ui.graphics.rememberGraphicsLayer
46
47
import androidx.compose.ui.platform.LocalContext
47
48
import androidx.compose.ui.platform.LocalDensity
48
49
import androidx.compose.ui.res.painterResource
49
50
import androidx.compose.ui.tooling.preview.Preview
51
+ import androidx.compose.ui.unit.Dp
50
52
import androidx.compose.ui.unit.Velocity
51
53
import androidx.compose.ui.unit.dp
52
54
import androidx.compose.ui.unit.sp
53
55
import com.smarttoolfactory.tutorial1_1basics.R
54
56
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
55
57
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
56
- import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
57
58
import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
58
59
import kotlinx.coroutines.CancellationException
59
60
import kotlin.random.Random
@@ -85,6 +86,10 @@ fun SingleParticleTrajectorySample() {
85
86
86
87
val particleState = rememberParticleState()
87
88
89
+ val particleSize = with (density) {
90
+ 5 .dp.toPx()
91
+ }
92
+
88
93
LaunchedEffect (trajectoryProgressStart, trajectoryProgressEnd) {
89
94
particleState.particleList.clear()
90
95
particleState.addParticle(
@@ -94,7 +99,7 @@ fun SingleParticleTrajectorySample() {
94
99
x = sizePxHalf,
95
100
y = sizePxHalf,
96
101
),
97
- initialSize = Size (5 .dp.toPx(), 5 .dp.toPx() ),
102
+ initialSize = Size (particleSize, particleSize ),
98
103
endSize = Size (sizePx, sizePx),
99
104
velocity = Velocity (
100
105
x = sizePxHalf,
@@ -293,18 +298,20 @@ fun Modifier.disintegrate(
293
298
LaunchedEffect (animationStatus != AnimationStatus .Idle ) {
294
299
if (animationStatus != AnimationStatus .Idle ) {
295
300
296
- if (particleState.imageBitmap == null ) {
297
- val imageBitmap = graphicsLayer
301
+ if (particleState.bitmap == null || particleState.bitmap?.isRecycled == true ) {
302
+ val bitmap = graphicsLayer
298
303
.toImageBitmap()
299
304
.asAndroidBitmap()
300
305
.copy(Bitmap .Config .ARGB_8888 , false )
301
- .asImageBitmap()
302
306
303
- particleState.imageBitmap = imageBitmap
307
+ bitmap.prepareToDraw()
308
+
309
+ particleState.bitmap = bitmap
304
310
305
311
particleState.createParticles(
312
+ particleList = particleState.particleList,
306
313
particleSize = particleSizePx,
307
- imageBitmap = imageBitmap
314
+ bitmap = bitmap
308
315
)
309
316
}
310
317
@@ -317,21 +324,62 @@ fun Modifier.disintegrate(
317
324
}
318
325
319
326
Modifier .drawWithCache {
320
-
321
327
onDrawWithContent {
322
-
323
328
if (animationStatus != AnimationStatus .Playing ) {
324
329
drawContent()
325
330
graphicsLayer.record {
326
331
this @onDrawWithContent.drawContent()
327
332
}
328
333
}
329
334
335
+ particleState.updateAndDrawParticles(
336
+ drawScope = this ,
337
+ particleList = particleState.particleList,
338
+ progress = progress
339
+ )
340
+ }
341
+ }
342
+ }
343
+
344
+ @Composable
345
+ fun rememberParticleState (particleSize : Dp = 2.dp): ParticleState {
346
+ return remember {
347
+ ParticleState (particleSize)
348
+ }
349
+ }
350
+
351
+ @Stable
352
+ class ParticleState internal constructor(particleSize : Dp ) {
353
+
354
+ var particleSize by mutableStateOf(particleSize)
355
+
356
+ val animatable = Animatable (0f )
357
+ val particleList = mutableStateListOf<Particle >()
358
+
359
+ var animationStatus by mutableStateOf(AnimationStatus .Idle )
360
+ internal set
361
+
362
+ val progress: Float
363
+ get() = animatable.value
364
+
365
+ var bitmap: Bitmap ? = null
366
+ internal set
367
+
368
+ fun addParticle (particle : Particle ) {
369
+ particleList.add(particle)
370
+ }
371
+
372
+ fun updateAndDrawParticles (
373
+ drawScope : DrawScope ,
374
+ particleList : SnapshotStateList <Particle >,
375
+ progress : Float
376
+ ) {
377
+ with (drawScope) {
330
378
if (animationStatus != AnimationStatus .Idle ) {
331
379
332
- particleState. particleList.forEach { particle ->
380
+ particleList.forEach { particle ->
333
381
334
- particleState. updateParticle(progress, particle)
382
+ updateParticle(progress, particle)
335
383
336
384
val color = particle.color
337
385
val radius = particle.currentSize.width * .65f
@@ -363,43 +411,17 @@ fun Modifier.disintegrate(
363
411
}
364
412
}
365
413
}
366
- }
367
-
368
- @Composable
369
- fun rememberParticleState (): ParticleState {
370
- return remember {
371
- ParticleState ()
372
- }
373
- }
374
-
375
- @Stable
376
- class ParticleState internal constructor() {
377
-
378
- var particleSize by mutableStateOf(2 .dp)
379
-
380
- val animatable = Animatable (0f )
381
- val particleList = mutableStateListOf<Particle >()
382
-
383
- var animationStatus by mutableStateOf(AnimationStatus .Idle )
384
- internal set
385
-
386
- val progress: Float
387
- get() = animatable.value
388
-
389
- var imageBitmap: ImageBitmap ? = null
390
- internal set
391
-
392
- fun addParticle (particle : Particle ) {
393
- particleList.add(particle)
394
- }
395
414
396
- fun createParticles (particleSize : Int , imageBitmap : ImageBitmap ) {
415
+ fun createParticles (
416
+ particleList : SnapshotStateList <Particle >,
417
+ particleSize : Int ,
418
+ bitmap : Bitmap
419
+ ) {
397
420
particleList.clear()
398
421
399
- val width = imageBitmap .width
400
- val height = imageBitmap .height
422
+ val width = bitmap .width
423
+ val height = bitmap .height
401
424
402
- val bitmap: Bitmap = imageBitmap.asAndroidBitmap()
403
425
404
426
val particleRadius = particleSize / 2
405
427
@@ -552,6 +574,18 @@ class ParticleState internal constructor() {
552
574
animationStatus = AnimationStatus .Idle
553
575
}
554
576
}
577
+
578
+ fun dispose () {
579
+ bitmap?.recycle()
580
+ }
581
+ }
582
+
583
+ interface DisintegrationStrategy {
584
+ fun updateParticle (progress : Float , particle : Particle )
585
+
586
+ fun createParticles (particleSize : Int , imageBitmap : ImageBitmap )
587
+
588
+ fun updateAndDrawParticles (drawScope : DrawScope )
555
589
}
556
590
557
591
/* *
0 commit comments