Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f1a8ad7

Browse files
update particle animation with blend mode
1 parent 7dfd85b commit f1a8ad7

File tree

1 file changed

+122
-23
lines changed
  • Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter9_animation

1 file changed

+122
-23
lines changed

‎Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter9_animation/ParticleAnimations.kt

Lines changed: 122 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.smarttoolfactory.tutorial1_1basics.chapter9_animation
22

33
import android.graphics.Bitmap
44
import android.util.Log
5+
import android.widget.Button
56
import android.widget.Toast
67
import androidx.compose.animation.core.Animatable
78
import androidx.compose.animation.core.AnimationSpec
@@ -23,6 +24,7 @@ import androidx.compose.foundation.layout.padding
2324
import androidx.compose.foundation.layout.size
2425
import androidx.compose.foundation.rememberScrollState
2526
import androidx.compose.foundation.verticalScroll
27+
import androidx.compose.material.Button
2628
import androidx.compose.material.Slider
2729
import androidx.compose.material.Text
2830
import androidx.compose.runtime.Composable
@@ -34,6 +36,7 @@ import androidx.compose.runtime.mutableFloatStateOf
3436
import androidx.compose.runtime.mutableStateListOf
3537
import androidx.compose.runtime.mutableStateOf
3638
import androidx.compose.runtime.remember
39+
import androidx.compose.runtime.rememberCoroutineScope
3740
import androidx.compose.runtime.setValue
3841
import androidx.compose.runtime.snapshots.SnapshotStateList
3942
import androidx.compose.ui.Alignment
@@ -42,12 +45,15 @@ import androidx.compose.ui.composed
4245
import androidx.compose.ui.draw.drawWithCache
4346
import androidx.compose.ui.geometry.Offset
4447
import androidx.compose.ui.geometry.Size
48+
import androidx.compose.ui.graphics.BlendMode
4549
import androidx.compose.ui.graphics.Color
4650
import androidx.compose.ui.graphics.ImageBitmap
4751
import androidx.compose.ui.graphics.TransformOrigin
4852
import androidx.compose.ui.graphics.asAndroidBitmap
4953
import androidx.compose.ui.graphics.asImageBitmap
5054
import androidx.compose.ui.graphics.drawscope.DrawScope
55+
import androidx.compose.ui.graphics.drawscope.clipRect
56+
import androidx.compose.ui.graphics.graphicsLayer
5157
import androidx.compose.ui.graphics.nativeCanvas
5258
import androidx.compose.ui.graphics.rememberGraphicsLayer
5359
import androidx.compose.ui.platform.LocalContext
@@ -71,11 +77,94 @@ import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
7177
import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
7278
import kotlinx.coroutines.CancellationException
7379
import kotlinx.coroutines.Dispatchers
80+
import kotlinx.coroutines.launch
7481
import kotlinx.coroutines.withContext
7582
import kotlin.math.cos
7683
import kotlin.math.roundToInt
7784
import kotlin.math.sin
7885

86+
@Preview
87+
@Composable
88+
fun ShakeTest() {
89+
90+
91+
val animatable = remember {
92+
Animatable(0f)
93+
}
94+
95+
val coroutineScope = rememberCoroutineScope()
96+
97+
Column(
98+
modifier = Modifier.fillMaxSize().padding(32.dp)
99+
) {
100+
101+
Image(
102+
modifier = Modifier
103+
.size(100.dp)
104+
.graphicsLayer {
105+
106+
val progress = animatable.value
107+
val endValue = .95f
108+
val scale = if (progress < endValue) 1f else scale(endValue, 1f, progress, 1f, 0f)
109+
110+
translationX = if (progress < endValue) size.width * .05f * progress * randomInRange(
111+
-1f,
112+
1f
113+
) else 1f
114+
translationY = if (progress < endValue) size.height * .05f * progress * randomInRange(
115+
-1f,
116+
1f
117+
) else 1f
118+
119+
scaleX = scale
120+
scaleY = scale
121+
alpha = scale
122+
},
123+
painter = painterResource(R.drawable.avatar_2_raster),
124+
contentDescription = null
125+
)
126+
127+
128+
129+
Spacer(modifier = Modifier.height(30.dp))
130+
Button(
131+
modifier = Modifier.fillMaxWidth(),
132+
onClick = {
133+
coroutineScope.launch {
134+
animatable.snapTo(0f)
135+
animatable.animateTo(
136+
targetValue = 1f,
137+
animationSpec = tween(800)
138+
)
139+
}
140+
}
141+
) {
142+
Text("Shake")
143+
}
144+
145+
146+
}
147+
}
148+
149+
fun Modifier.shake() = composed {
150+
val animatable = remember {
151+
Animatable(0f)
152+
}
153+
154+
155+
LaunchedEffect(Unit) {
156+
animatable.animateTo(
157+
targetValue = 1f,
158+
animationSpec = tween(1000)
159+
)
160+
}
161+
Modifier.graphicsLayer {
162+
translationX = size.width * .1f * animatable.value * randomInRange(-1f, 1f)
163+
translationY = size.width * .1f * animatable.value * randomInRange(-1f, 1f)
164+
}
165+
166+
}
167+
79168
@Preview
80169
@Composable
81170
fun SingleParticleTrajectorySample() {
@@ -229,8 +318,8 @@ fun ParticleAnimationSample() {
229318
}
230319

231320
val particleState = rememberParticleState(
232-
particleSize = 2.dp,
233-
animationSpec = tween(durationMillis = 1500, easing = FastOutSlowInEasing)
321+
particleSize = 1.5.dp,
322+
animationSpec = tween(durationMillis = 1800, easing = FastOutSlowInEasing)
234323
)
235324

236325
val particleState2 = rememberParticleState(
@@ -599,7 +688,7 @@ open class DisintegrateStrategy : ParticleStrategy {
599688
val particleSizePx = particleSize.toFloat()
600689

601690
val initialSize = setInitialSize(particleBoundaries, particleSizePx)
602-
val endSize = setEndSize(particleBoundaries, particleSizePx.toInt())
691+
val endSize = setEndSize(particleBoundaries, particleSizePx)
603692

604693
// Set alpha
605694
val alphaStart = setInitialAlpha(particleBoundaries)
@@ -673,7 +762,7 @@ open class DisintegrateStrategy : ParticleStrategy {
673762

674763
override fun setEndSize(
675764
particleBoundaries: ParticleBoundaries?,
676-
particleSize: Int
765+
particleSize: Float
677766
): Size {
678767
val endMinSize =
679768
(particleBoundaries?.endSizeLowerBound?.width) ?: (particleSize * .4f)
@@ -762,16 +851,16 @@ open class DisintegrateStrategy : ParticleStrategy {
762851
particleBoundaries: ParticleBoundaries?
763852
) {
764853
with(drawScope) {
765-
// drawWithLayer {
766-
particleList.forEach { particle ->
767-
if (particle.isActive) {
854+
drawWithLayer {
855+
particleList.forEach { particle ->
856+
// if (particle.isActive) {
768857
updateParticle(
769858
progress = progress,
770859
particle = particle
771860
)
772861

773862
val color = particle.color
774-
val radius = particle.currentSize.width * .65f
863+
val radius = particle.currentSize.width * .5f
775864
val position = particle.currentPosition
776865
val alpha = particle.alpha
777866

@@ -782,26 +871,36 @@ open class DisintegrateStrategy : ParticleStrategy {
782871
center = position,
783872
alpha = alpha
784873
)
874+
// }
785875
}
786-
}
787876

788-
// clipRect(
789-
// left = progress * size.width * 2f
790-
// ) {
791-
// drawImage(
792-
// image = imageBitmap,
793-
// blendMode = BlendMode.SrcOut
794-
// )
795-
// }
877+
if (progress < .65f) {
878+
val coEfficient = if (progress < .2f) {
879+
progress * .8f
880+
} else progress * 1.5f
881+
clipRect(
882+
left = size.width * coEfficient
883+
) {
884+
drawImage(
885+
image = imageBitmap,
886+
blendMode = BlendMode.DstIn
887+
)
796888

797-
// For debugging
889+
drawImage(
890+
image = imageBitmap,
891+
blendMode = BlendMode.SrcOut
892+
)
893+
}
894+
}
895+
896+
// For debugging
798897
// drawRect(
799898
// color = Color.Black,
800899
// topLeft = Offset(progress * size.width, 0f),
801900
// size = Size(size.width - progress * size.width, size.height),
802901
// style = Stroke(4.dp.toPx())
803902
// )
804-
// }
903+
}
805904
}
806905
}
807906

@@ -831,7 +930,7 @@ open class DisintegrateStrategy : ParticleStrategy {
831930
// Set alpha
832931
// While trajectory progress is less than 40% have full alpha then slowly
833932
// reduce to zero for particles to disappear
834-
alpha = if (trajectoryProgress == 0f) 1f
933+
alpha = if (trajectoryProgress == 0f) 0f
835934
else if (trajectoryProgress < .4f) 1f
836935
else scale(.4f, 1f, trajectoryProgress, particle.initialAlpha, particle.endAlpha)
837936

@@ -948,7 +1047,7 @@ open class DefaultStrategy : ParticleStrategy {
9481047
// Set initial and final sizes
9491048
val initialSize = setInitialSize(particleBoundaries, particleSize.toFloat())
9501049

951-
val endSize = setEndSize(particleBoundaries, particleSize)
1050+
val endSize = setEndSize(particleBoundaries, particleSize.toFloat())
9521051

9531052
// Set alpha
9541053
val alphaStart = setInitialAlpha(particleBoundaries)
@@ -1005,7 +1104,7 @@ open class DefaultStrategy : ParticleStrategy {
10051104

10061105
override fun setEndSize(
10071106
particleBoundaries: ParticleBoundaries?,
1008-
particleSize: Int
1107+
particleSize: Float
10091108
): Size {
10101109
val endSizePx = if (randomBoolean(8)) {
10111110
randomInRange(particleSize * 1f, particleSize.toFloat() * 2.5f)
@@ -1196,7 +1295,7 @@ interface ParticleStrategy {
11961295
halfHeight: Float
11971296
): Offset
11981297

1199-
fun setEndSize(particleBoundaries: ParticleBoundaries?, particleSize: Int): Size
1298+
fun setEndSize(particleBoundaries: ParticleBoundaries?, particleSize: Float): Size
12001299

12011300
fun setInitialSize(particleBoundaries: ParticleBoundaries?, particleSize: Float): Size
12021301

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /