@@ -21,7 +21,6 @@ import androidx.compose.material.Button
21
21
import androidx.compose.material.Slider
22
22
import androidx.compose.material.Text
23
23
import androidx.compose.runtime.Composable
24
- import androidx.compose.runtime.DisposableEffect
25
24
import androidx.compose.runtime.LaunchedEffect
26
25
import androidx.compose.runtime.Stable
27
26
import androidx.compose.runtime.getValue
@@ -46,7 +45,7 @@ import androidx.compose.ui.res.painterResource
46
45
import androidx.compose.ui.tooling.preview.Preview
47
46
import androidx.compose.ui.unit.dp
48
47
import androidx.compose.ui.unit.sp
49
- import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.mapInRange
48
+ import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
50
49
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.toPx
51
50
import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
52
51
import kotlinx.coroutines.CancellationException
@@ -58,11 +57,11 @@ fun SingleParticleTrajectorySample() {
58
57
59
58
var progress by remember { mutableFloatStateOf(0f ) }
60
59
61
- var visibilityThresholdLow by remember {
60
+ var trajectoryProgressStart by remember {
62
61
mutableFloatStateOf(0f )
63
62
}
64
63
65
- var visibilityThresholdHigh by remember {
64
+ var trajectoryProgressEnd by remember {
66
65
mutableFloatStateOf(1f )
67
66
}
68
67
@@ -80,7 +79,7 @@ fun SingleParticleTrajectorySample() {
80
79
81
80
val particleState = rememberParticleState()
82
81
83
- LaunchedEffect (visibilityThresholdLow, visibilityThresholdHigh ) {
82
+ LaunchedEffect (trajectoryProgressStart, trajectoryProgressEnd ) {
84
83
particleState.particleList.clear()
85
84
particleState.addParticle(
86
85
Particle (
@@ -91,18 +90,17 @@ fun SingleParticleTrajectorySample() {
91
90
),
92
91
initialSize = Size (5 .dp.toPx(), 5 .dp.toPx()),
93
92
endSize = Size (sizePx, sizePx),
94
- finalCenter = Offset (
93
+ displacement = Offset (
95
94
sizePxHalf,
96
95
sizePxHalf
97
96
),
98
- trajectoryProgressRange = visibilityThresholdLow .. visibilityThresholdHigh ,
97
+ trajectoryProgressRange = trajectoryProgressStart .. trajectoryProgressEnd ,
99
98
row = 0 ,
100
99
column = 0
101
100
)
102
101
)
103
102
}
104
103
105
-
106
104
Column (
107
105
modifier = Modifier .fillMaxSize()
108
106
.verticalScroll(rememberScrollState())
@@ -158,22 +156,22 @@ fun SingleParticleTrajectorySample() {
158
156
}
159
157
)
160
158
161
- Text (" visibilityThresholdLow : $visibilityThresholdLow " )
159
+ Text (" trajectoryProgressStart : $trajectoryProgressStart " )
162
160
Slider (
163
161
modifier = Modifier .fillMaxWidth(),
164
- value = visibilityThresholdLow ,
162
+ value = trajectoryProgressStart ,
165
163
onValueChange = {
166
- visibilityThresholdLow = it.coerceAtMost(visibilityThresholdHigh )
164
+ trajectoryProgressStart = it.coerceAtMost(trajectoryProgressEnd )
167
165
},
168
166
valueRange = 0f .. 1f
169
167
)
170
168
171
- Text (" visibilityThresholdHigh : $visibilityThresholdHigh " )
169
+ Text (" trajectoryProgressEnd : $trajectoryProgressEnd " )
172
170
Slider (
173
171
modifier = Modifier .fillMaxWidth(),
174
- value = visibilityThresholdHigh ,
172
+ value = trajectoryProgressEnd ,
175
173
onValueChange = {
176
- visibilityThresholdHigh = it.coerceAtLeast(visibilityThresholdLow )
174
+ trajectoryProgressEnd = it.coerceAtLeast(trajectoryProgressStart )
177
175
},
178
176
valueRange = 0f .. 1f
179
177
)
@@ -188,7 +186,7 @@ fun ParticleAnimationSample() {
188
186
modifier = Modifier
189
187
.fillMaxSize()
190
188
.verticalScroll(rememberScrollState())
191
- .padding(16 .dp),
189
+ .padding(horizontal = 16 .dp, vertical = 32 .dp),
192
190
verticalArrangement = Arrangement .spacedBy(8 .dp)
193
191
) {
194
192
@@ -201,11 +199,15 @@ fun ParticleAnimationSample() {
201
199
202
200
val context = LocalContext .current
203
201
202
+ var progress by remember {
203
+ mutableFloatStateOf(0f )
204
+ }
204
205
Image (
205
206
painter = painterResource(R .drawable.avatar_2_raster),
206
207
modifier = Modifier
207
208
.border(2 .dp, Color .Red )
208
209
.explode(
210
+ progress = progress,
209
211
particleState = particleState,
210
212
onStart = {
211
213
Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
@@ -218,6 +220,12 @@ fun ParticleAnimationSample() {
218
220
contentDescription = null
219
221
)
220
222
223
+ Slider (
224
+ value = progress,
225
+ onValueChange = {
226
+ progress = it
227
+ }
228
+ )
221
229
Button (
222
230
modifier = Modifier .fillMaxWidth(),
223
231
onClick = {
@@ -231,12 +239,12 @@ fun ParticleAnimationSample() {
231
239
232
240
data class Particle (
233
241
val initialCenter : Offset ,
234
- val finalCenter : Offset ,
242
+ val displacement : Offset ,
235
243
val initialSize : Size ,
236
244
val endSize : Size ,
237
245
val color : Color ,
238
246
val trajectoryProgressRange : ClosedRange <Float > = 0f ..1f ,
239
- val velocity : Float = 4 * finalCenter .y,
247
+ val velocity : Float = 4 * displacement .y,
240
248
val acceleration : Float = -2 * velocity,
241
249
val column : Int ,
242
250
val row : Int
@@ -254,6 +262,7 @@ data class Particle(
254
262
}
255
263
256
264
fun Modifier.explode (
265
+ progress : Float ,
257
266
particleState : ParticleState ,
258
267
onStart : () -> Unit = {},
259
268
onEnd : () -> Unit = {}
@@ -305,11 +314,13 @@ fun Modifier.explode(
305
314
306
315
if (animationStatus != AnimationStatus .Idle ) {
307
316
308
- val progress = particleState.progress
317
+ // val progress = particleState.progress
309
318
310
319
particleState.particleList.forEach { particle ->
311
320
312
- // particleState.updateParticle(progress, particle)
321
+ if (progress > 0 && progress <= 1f ) {
322
+ particleState.updateParticle(progress, particle)
323
+ }
313
324
314
325
val color = particle.color
315
326
val radius = particle.currentSize.width / 2f
@@ -341,7 +352,7 @@ fun rememberParticleState(): ParticleState {
341
352
@Stable
342
353
class ParticleState internal constructor() {
343
354
344
- var particleSize by mutableStateOf(50 .dp)
355
+ var particleSize by mutableStateOf(200 .dp)
345
356
346
357
val animatable = Animatable (0f )
347
358
val particleList = mutableStateListOf<Particle >()
@@ -396,17 +407,23 @@ class ParticleState internal constructor() {
396
407
if (color != Color .Unspecified ) {
397
408
398
409
val initialCenter = Offset (pixelCenterX.toFloat(), pixelCenterY.toFloat())
410
+ val horizontalDisplacement = width / 2f
411
+ val verticalDisplacement = height / 2f
412
+
413
+ val velocity = 4 * verticalDisplacement
414
+ val acceleration = - 2 * velocity
415
+
399
416
particleList.add(
400
417
Particle (
401
418
initialCenter = initialCenter,
402
- finalCenter = initialCenter.plus( Offset (width / 2f , - height / 2f ) ),
419
+ displacement = Offset (horizontalDisplacement, verticalDisplacement ),
403
420
initialSize = Size (particleSize.toFloat(), particleSize.toFloat()),
404
421
endSize = Size .Zero ,
405
422
color = color,
406
423
column = column,
407
424
row = row,
408
- velocity = 0f ,
409
- acceleration = 0f
425
+ velocity = velocity ,
426
+ acceleration = acceleration
410
427
)
411
428
)
412
429
@@ -416,7 +433,7 @@ class ParticleState internal constructor() {
416
433
}
417
434
}
418
435
419
- // println("PARTICLE count: ${particleList.size}")
436
+ println (" PARTICLE count: ${particleList.size} " )
420
437
421
438
}
422
439
@@ -432,22 +449,27 @@ class ParticleState internal constructor() {
432
449
// Each 0.1f change in trajectoryProgress 0.5f total range
433
450
// corresponds to 0.2f change of current time
434
451
435
- val visibilityThresholdLow = trajectoryProgressRange.start
436
- val visibilityThresholdHigh = trajectoryProgressRange.endInclusive
452
+ val trajectoryProgressStart = trajectoryProgressRange.start
453
+ val trajectoryProgressEnd = trajectoryProgressRange.endInclusive
437
454
438
455
val startXPosition = initialCenter.x
439
456
val startYPosition = initialCenter.x
440
457
441
- val maxHorizontalDisplacement = finalCenter .x
458
+ val maxHorizontalDisplacement = displacement .x
442
459
443
460
trajectoryProgress =
444
- if (explosionProgress < visibilityThresholdLow ) {
461
+ if (explosionProgress < trajectoryProgressStart ) {
445
462
0f
446
- } else if (explosionProgress > visibilityThresholdHigh ) {
463
+ } else if (explosionProgress > trajectoryProgressEnd ) {
447
464
1f
448
465
} else {
449
- explosionProgress
450
- .mapInRange(visibilityThresholdLow, visibilityThresholdHigh, 0f , 1f )
466
+ scale(
467
+ a1 = trajectoryProgressStart,
468
+ b1 = trajectoryProgressEnd,
469
+ x1 = explosionProgress,
470
+ a2 = 0f ,
471
+ b2 = 1f
472
+ )
451
473
}
452
474
453
475
currentTime = trajectoryProgress
@@ -457,12 +479,16 @@ class ParticleState internal constructor() {
457
479
// alpha = if (trajectoryProgress < .7f) 1f else
458
480
// scale(.7f, 1f, trajectoryProgress, 1f, 0f)
459
481
482
+ val horizontalDisplacement = maxHorizontalDisplacement * trajectoryProgress
483
+
460
484
val verticalDisplacement =
461
- currentTime * velocity + 0.5 * acceleration * currentTime * currentTime
485
+ velocity * currentTime + 0.5f * acceleration * currentTime * currentTime
486
+
487
+ println (" horizontalDisplacement: $horizontalDisplacement , verticalDisplacement: $verticalDisplacement " )
462
488
463
489
currentPosition = Offset (
464
- x = startXPosition + maxHorizontalDisplacement * trajectoryProgress ,
465
- y = ( startYPosition - verticalDisplacement).toFloat()
490
+ x = startXPosition + horizontalDisplacement ,
491
+ y = startYPosition - verticalDisplacement
466
492
)
467
493
}
468
494
}
@@ -475,7 +501,7 @@ class ParticleState internal constructor() {
475
501
try {
476
502
animatable.snapTo(0f )
477
503
animatable.animateTo(1f , tween(2000 ))
478
- animationStatus = AnimationStatus .Idle
504
+ // animationStatus = AnimationStatus.Idle
479
505
} catch (e: CancellationException ) {
480
506
println (" FAILED: ${e.message} " )
481
507
}
0 commit comments