@@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.ImageBitmap
44
44
import androidx.compose.ui.graphics.asAndroidBitmap
45
45
import androidx.compose.ui.graphics.asImageBitmap
46
46
import androidx.compose.ui.graphics.drawscope.DrawScope
47
+ import androidx.compose.ui.graphics.drawscope.Stroke
47
48
import androidx.compose.ui.graphics.drawscope.clipRect
48
49
import androidx.compose.ui.graphics.nativeCanvas
49
50
import androidx.compose.ui.graphics.rememberGraphicsLayer
@@ -56,9 +57,10 @@ import androidx.compose.ui.unit.Velocity
56
57
import androidx.compose.ui.unit.dp
57
58
import androidx.compose.ui.unit.sp
58
59
import com.smarttoolfactory.tutorial1_1basics.R
60
+ import com.smarttoolfactory.tutorial1_1basics.chapter3_layout.chat.MessageStatus
61
+ import com.smarttoolfactory.tutorial1_1basics.chapter3_layout.chat.SentMessageRowAlt
59
62
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
60
63
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
61
- import com.smarttoolfactory.tutorial1_1basics.ui.BlueGrey400
62
64
import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
63
65
import kotlinx.coroutines.CancellationException
64
66
import kotlin.math.roundToInt
@@ -96,6 +98,12 @@ fun SingleParticleTrajectorySample() {
96
98
97
99
LaunchedEffect (trajectoryProgressStart, trajectoryProgressEnd) {
98
100
particleState.particleList.clear()
101
+
102
+ val velocity = Velocity (
103
+ x = sizePxHalf,
104
+ y = sizePxHalf * 4
105
+ )
106
+
99
107
particleState.addParticle(
100
108
Particle (
101
109
color = Pink400 ,
@@ -105,10 +113,8 @@ fun SingleParticleTrajectorySample() {
105
113
),
106
114
initialSize = Size (particleSize, particleSize),
107
115
endSize = Size (sizePx, sizePx),
108
- velocity = Velocity (
109
- x = sizePxHalf,
110
- y = sizePxHalf * 4
111
- ),
116
+ velocity = velocity,
117
+ acceleration = - 2 * velocity.y,
112
118
trajectoryProgressRange = trajectoryProgressStart.. trajectoryProgressEnd
113
119
)
114
120
)
@@ -213,25 +219,48 @@ fun ParticleAnimationSample() {
213
219
}
214
220
215
221
val particleState = rememberParticleState()
222
+ val particleState2 = rememberParticleState()
216
223
217
224
val context = LocalContext .current
218
225
219
226
var progress by remember {
220
227
mutableFloatStateOf(0f )
221
228
}
229
+
230
+
231
+ SentMessageRowAlt (
232
+ modifier = Modifier .disintegrate(
233
+ // progress = progress,
234
+ particleState = particleState,
235
+ onStart = {
236
+ Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
237
+ },
238
+ onEnd = {
239
+ particleState.animationStatus = AnimationStatus .Idle
240
+ Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
241
+ }
242
+ ),
243
+ quotedImage = R .drawable.avatar_4_raster,
244
+ text = " Some long message" ,
245
+ messageTime = " 11.02.2024" ,
246
+ messageStatus = MessageStatus .READ
247
+ )
248
+
249
+ Spacer (Modifier .height(16 .dp))
250
+
222
251
Image (
223
252
painter = painterResource(R .drawable.avatar_2_raster),
224
253
modifier = Modifier
225
254
.border(2 .dp, Color .Red )
226
255
.size(widthDp)
227
256
.disintegrate(
228
- progress = progress,
229
- particleState = particleState ,
257
+ // progress = progress,
258
+ particleState = particleState2 ,
230
259
onStart = {
231
260
Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
232
261
},
233
262
onEnd = {
234
- // particleState .animationStatus = AnimationStatus.Idle
263
+ particleState2 .animationStatus = AnimationStatus .Idle
235
264
Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
236
265
}
237
266
),
@@ -250,6 +279,7 @@ fun ParticleAnimationSample() {
250
279
modifier = Modifier .fillMaxWidth(),
251
280
onClick = {
252
281
particleState.startAnimation()
282
+ particleState2.startAnimation()
253
283
}
254
284
) {
255
285
Text (" Convert graphicsLayer to particles" )
@@ -264,7 +294,7 @@ data class Particle(
264
294
val trajectoryProgressRange : ClosedRange <Float > = 0f ..1f ,
265
295
var color : Color ,
266
296
var velocity : Velocity = Velocity (0f, 0f),
267
- var acceleration : Float = - 2 * velocity.y
297
+ var acceleration : Float = 0f
268
298
) {
269
299
var currentPosition: Offset = initialCenter
270
300
internal set
@@ -352,7 +382,7 @@ fun Modifier.disintegrate(
352
382
}
353
383
354
384
@Composable
355
- fun rememberParticleState (particleSize : Dp = 2 .dp): ParticleState {
385
+ fun rememberParticleState (particleSize : Dp = 1 .dp): ParticleState {
356
386
return remember {
357
387
ParticleState (particleSize)
358
388
}
@@ -393,9 +423,7 @@ class ParticleState internal constructor(particleSize: Dp) {
393
423
if (animationStatus != AnimationStatus .Idle ) {
394
424
395
425
drawWithLayer {
396
-
397
426
particleList.forEach { particle ->
398
-
399
427
updateParticle(progress, particle)
400
428
401
429
val color = particle.color
@@ -423,12 +451,12 @@ class ParticleState internal constructor(particleSize: Dp) {
423
451
}
424
452
425
453
// 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
- // )
454
+ drawRect(
455
+ color = Color .Black ,
456
+ topLeft = Offset (progress * size.width, 0f ),
457
+ size = Size (size.width - progress * size.width, size.height),
458
+ style = Stroke (4 .dp.toPx())
459
+ )
432
460
}
433
461
}
434
462
}
@@ -452,7 +480,6 @@ class ParticleState internal constructor(particleSize: Dp) {
452
480
for (column in 0 until width step particleSize) {
453
481
for (row in 0 until height step particleSize) {
454
482
455
-
456
483
// Get pixel at center of this pixel rectangle
457
484
// If last pixel is out of image get it from end of the width or height
458
485
// 🔥x must be < bitmap.width() and y must be < bitmap.height()
@@ -464,11 +491,8 @@ class ParticleState internal constructor(particleSize: Dp) {
464
491
val color = Color (pixel)
465
492
466
493
if (color != Color .Unspecified ) {
494
+ // Set center
467
495
val initialCenter = Offset (pixelCenterX.toFloat(), pixelCenterY.toFloat())
468
- val horizontalDisplacement = randomInRange(- 50f , 50f )
469
-
470
- val verticalDisplacement = randomInRange(- height * .1f , height * .2f )
471
- val acceleration = randomInRange(- 2f , 2f )
472
496
473
497
// If this particle is at 20% of image width in x plane
474
498
// it returns 0.2f
@@ -494,18 +518,34 @@ class ParticleState internal constructor(particleSize: Dp) {
494
518
trajectoryProgressRange =
495
519
trajectoryProgressRange.start + startYOffset.. trajectoryProgressRange.endInclusive
496
520
521
+ val imageMinDimension = width.coerceAtMost(height) * 1f
522
+
523
+ val velocityX = randomInRange(
524
+ // Particles close to end should have less randomization to start of image
525
+ - (particleSize * 30f * (1 - fractionToImageWidth * .7f ))
526
+ .coerceAtMost(imageMinDimension),
527
+ (particleSize * 30f ).coerceAtMost(imageMinDimension)
528
+ )
529
+ val velocityY = randomInRange(
530
+ - (particleSize * 20f ).coerceAtMost(imageMinDimension),
531
+ (particleSize * 30f ).coerceAtMost(imageMinDimension)
532
+ )
533
+ val acceleration = randomInRange(- 1f , 1f )
534
+
535
+ // Set initial and final sizes
536
+ val initialSize = Size (particleSize.toFloat(), particleSize.toFloat())
497
537
val endSize = randomInRange(0f , particleSize.toFloat() * .5f )
498
538
499
539
particleList.add(
500
540
Particle (
501
541
initialCenter = initialCenter,
502
- initialSize = Size (particleSize.toFloat(), particleSize.toFloat()),
503
- trajectoryProgressRange = trajectoryProgressRange,
542
+ initialSize = initialSize,
504
543
endSize = Size (endSize, endSize),
544
+ trajectoryProgressRange = trajectoryProgressRange,
505
545
color = color,
506
546
velocity = Velocity (
507
- x = horizontalDisplacement ,
508
- y = verticalDisplacement
547
+ x = velocityX ,
548
+ y = velocityY
509
549
),
510
550
acceleration = acceleration
511
551
)
@@ -544,8 +584,8 @@ class ParticleState internal constructor(particleSize: Dp) {
544
584
// While trajectory progress is less than 80% have full alpha then slowly
545
585
// reduce to zero for particles to disappear
546
586
alpha = if (trajectoryProgress == 0f ) 1f
547
- else if (trajectoryProgress < .8f ) 1f
548
- else scale(.8f , 1f , trajectoryProgress, 1f , 0f )
587
+ else if (trajectoryProgress < .5f ) 1f
588
+ else scale(.5f , 1f , trajectoryProgress, 1f , 0f )
549
589
550
590
val horizontalDisplacement = velocity.x * trajectoryProgress
551
591
val verticalDisplacement =
0 commit comments