@@ -31,6 +31,7 @@ import androidx.compose.runtime.mutableStateListOf
3131import androidx.compose.runtime.mutableStateOf
3232import androidx.compose.runtime.remember
3333import androidx.compose.runtime.setValue
34+ import androidx.compose.runtime.snapshots.SnapshotStateList
3435import androidx.compose.ui.Alignment
3536import androidx.compose.ui.Modifier
3637import androidx.compose.ui.composed
@@ -40,20 +41,20 @@ import androidx.compose.ui.geometry.Size
4041import androidx.compose.ui.graphics.Color
4142import androidx.compose.ui.graphics.ImageBitmap
4243import androidx.compose.ui.graphics.asAndroidBitmap
43- import androidx.compose.ui.graphics.asImageBitmap
44+ import androidx.compose.ui.graphics.drawscope.DrawScope
4445import androidx.compose.ui.graphics.drawscope.Stroke
4546import androidx.compose.ui.graphics.rememberGraphicsLayer
4647import androidx.compose.ui.platform.LocalContext
4748import androidx.compose.ui.platform.LocalDensity
4849import androidx.compose.ui.res.painterResource
4950import androidx.compose.ui.tooling.preview.Preview
51+ import androidx.compose.ui.unit.Dp
5052import androidx.compose.ui.unit.Velocity
5153import androidx.compose.ui.unit.dp
5254import androidx.compose.ui.unit.sp
5355import com.smarttoolfactory.tutorial1_1basics.R
5456import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
5557import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
56- import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
5758import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
5859import kotlinx.coroutines.CancellationException
5960import kotlin.random.Random
@@ -85,6 +86,10 @@ fun SingleParticleTrajectorySample() {
8586
8687 val particleState = rememberParticleState()
8788
89+ val particleSize = with (density) {
90+ 5 .dp.toPx()
91+ }
92+
8893 LaunchedEffect (trajectoryProgressStart, trajectoryProgressEnd) {
8994 particleState.particleList.clear()
9095 particleState.addParticle(
@@ -94,7 +99,7 @@ fun SingleParticleTrajectorySample() {
9499 x = sizePxHalf,
95100 y = sizePxHalf,
96101 ),
97- initialSize = Size (5 .dp.toPx(), 5 .dp.toPx() ),
102+ initialSize = Size (particleSize, particleSize ),
98103 endSize = Size (sizePx, sizePx),
99104 velocity = Velocity (
100105 x = sizePxHalf,
@@ -293,18 +298,20 @@ fun Modifier.disintegrate(
293298 LaunchedEffect (animationStatus != AnimationStatus .Idle ) {
294299 if (animationStatus != AnimationStatus .Idle ) {
295300
296- if (particleState.imageBitmap == null ) {
297- val imageBitmap = graphicsLayer
301+ if (particleState.bitmap == null || particleState.bitmap?.isRecycled == true ) {
302+ val bitmap = graphicsLayer
298303 .toImageBitmap()
299304 .asAndroidBitmap()
300305 .copy(Bitmap .Config .ARGB_8888 , false )
301- .asImageBitmap()
302306
303- particleState.imageBitmap = imageBitmap
307+ bitmap.prepareToDraw()
308+
309+ particleState.bitmap = bitmap
304310
305311 particleState.createParticles(
312+ particleList = particleState.particleList,
306313 particleSize = particleSizePx,
307- imageBitmap = imageBitmap
314+ bitmap = bitmap
308315 )
309316 }
310317
@@ -317,21 +324,62 @@ fun Modifier.disintegrate(
317324 }
318325
319326 Modifier .drawWithCache {
320-
321327 onDrawWithContent {
322-
323328 if (animationStatus != AnimationStatus .Playing ) {
324329 drawContent()
325330 graphicsLayer.record {
326331 this @onDrawWithContent.drawContent()
327332 }
328333 }
329334
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) {
330378 if (animationStatus != AnimationStatus .Idle ) {
331379
332- particleState. particleList.forEach { particle ->
380+ particleList.forEach { particle ->
333381
334- particleState. updateParticle(progress, particle)
382+ updateParticle(progress, particle)
335383
336384 val color = particle.color
337385 val radius = particle.currentSize.width * .65f
@@ -363,43 +411,17 @@ fun Modifier.disintegrate(
363411 }
364412 }
365413 }
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- }
395414
396- fun createParticles (particleSize : Int , imageBitmap : ImageBitmap ) {
415+ fun createParticles (
416+ particleList : SnapshotStateList <Particle >,
417+ particleSize : Int ,
418+ bitmap : Bitmap
419+ ) {
397420 particleList.clear()
398421
399- val width = imageBitmap .width
400- val height = imageBitmap .height
422+ val width = bitmap .width
423+ val height = bitmap .height
401424
402- val bitmap: Bitmap = imageBitmap.asAndroidBitmap()
403425
404426 val particleRadius = particleSize / 2
405427
@@ -552,6 +574,18 @@ class ParticleState internal constructor() {
552574 animationStatus = AnimationStatus .Idle
553575 }
554576 }
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 )
555589}
556590
557591/* *
0 commit comments