├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── esatgozcu
│ │ └── animationexamples
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── esatgozcu
│ │ │ └── animationexamples
│ │ │ ├── MainActivity.kt
│ │ │ ├── helper
│ │ │ ├── Constants.kt
│ │ │ ├── CustomShape.kt
│ │ │ └── Extension.kt
│ │ │ ├── navigation
│ │ │ └── NavGraph.kt
│ │ │ └── ui
│ │ │ ├── HomePage.kt
│ │ │ ├── animations
│ │ │ ├── blinkcircle
│ │ │ │ ├── BlinkCircleVM.kt
│ │ │ │ └── BlinkCircleView.kt
│ │ │ ├── circlerotation
│ │ │ │ ├── CircleRotationVM.kt
│ │ │ │ └── CircleRotationView.kt
│ │ │ ├── confetticenter
│ │ │ │ ├── ConfettiAnimationVM.kt
│ │ │ │ └── ConfettiAnimationView.kt
│ │ │ ├── fireworkcenter
│ │ │ │ ├── FireworkCenterVM.kt
│ │ │ │ └── FireworkCenterView.kt
│ │ │ ├── paperplane
│ │ │ │ ├── PaperPlaneVM.kt
│ │ │ │ └── PaperPlaneView.kt
│ │ │ └── snowflake
│ │ │ │ ├── SnowFlakeVM.kt
│ │ │ │ └── SnowFlakeView.kt
│ │ │ └── theme
│ │ │ ├── Color.kt
│ │ │ ├── Shape.kt
│ │ │ ├── Theme.kt
│ │ │ └── Type.kt
│ └── res
│ │ ├── drawable-v24
│ │ ├── ic_launcher_foreground.xml
│ │ └── ic_paper_plane.xml
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_rotate_3d.xml
│ │ └── ic_snow_flake.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── esatgozcu
│ └── animationexamples
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Esat GÖZCÜ
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Compose Animation Examples
2 |
3 | ### Step by step understand compose animation logic.
4 |
5 | This repository developed for Compose animation. There are a lot of animation with different concepts. You can select what you want and customize what you needed.
6 |
7 |
8 |
9 |
10 | ## Simple Animations
11 |
12 |
13 |
14 | | **#[Snow Flake](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/snowflake)** | **#[Paper Plane](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/paperplane)** | **#[Blink Circle](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/blinkcircle)** | **#[Circle Rotation](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/circlerotation)** |
15 | | --- | --- | --- | --- |
16 | |
|
|
|
|
17 |
18 |
19 |
20 | ## Confetti Animations
21 |
22 |
23 |
24 | | **#[Default](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter)** | **#[Firework Effect](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter)** |
25 | | --- | --- |
26 | |
|
|
27 |
28 | | **#[Image](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter)** | **#[Emoji - Text](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter)** |
29 | | --- | --- |
30 | |
|
|
31 |
32 |
33 |
34 | ## Firework Animations
35 |
36 | | **#[Firework](app/src/main/java/com/esatgozcu/animationexamples/ui/animations/fireworkcenter)** |
37 | | --- |
38 | |
|
39 |
40 |
41 |
42 | ## 🔨 Support
43 |
44 | If you like the project, don't forget to `put a star 🌟`.
45 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | applicationId "com.esatgozcu.animationexamples"
11 | minSdk 23
12 | targetSdk 32
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | vectorDrawables {
18 | useSupportLibrary true
19 | }
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | kotlinOptions {
33 | jvmTarget = '1.8'
34 | }
35 | buildFeatures {
36 | compose true
37 | }
38 | composeOptions {
39 | kotlinCompilerExtensionVersion compose_version
40 | }
41 | packagingOptions {
42 | resources {
43 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 |
50 | implementation 'androidx.core:core-ktx:1.7.0'
51 | implementation "androidx.compose.ui:ui:$compose_version"
52 | implementation "androidx.compose.material:material:$compose_version"
53 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
54 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
55 | implementation 'androidx.activity:activity-compose:1.3.1'
56 | testImplementation 'junit:junit:4.13.2'
57 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
58 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
59 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
60 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
61 | debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
62 |
63 | def nav_version = "2.5.3"
64 | implementation "androidx.navigation:navigation-compose:$nav_version"
65 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/esatgozcu/animationexamples/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.esatgozcu.animationexamples", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.material.MaterialTheme
8 | import androidx.compose.material.Surface
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.platform.LocalConfiguration
11 | import androidx.navigation.compose.rememberNavController
12 | import com.esatgozcu.animationexamples.helper.ScreenSize
13 | import com.esatgozcu.animationexamples.navigation.NavGraph
14 | import com.esatgozcu.animationexamples.ui.theme.AnimationExamplesTheme
15 |
16 | class MainActivity : ComponentActivity() {
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContent {
20 | AnimationExamplesTheme {
21 | Surface(
22 | modifier = Modifier.fillMaxSize(),
23 | color = MaterialTheme.colors.background
24 | ) {
25 | ScreenSize.screensWidth = LocalConfiguration.current.screenWidthDp.toDouble()
26 | ScreenSize.screenHeight = LocalConfiguration.current.screenHeightDp.toDouble()
27 | NavGraph(navController = rememberNavController())
28 | }
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/helper/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.helper
2 |
3 | object ScreenSize {
4 | var screensWidth : Double = 0.0
5 | var screenHeight: Double = 0.0
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/helper/CustomShape.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.helper
2 |
3 | import androidx.compose.foundation.shape.GenericShape
4 | import kotlin.math.tan
5 |
6 | class CustomShape {
7 | object Shapes{
8 | val Triangle = GenericShape { size, _ ->
9 |
10 | moveTo(size.width / 2f, 0f)
11 | lineTo(size.width, size.height)
12 | lineTo(0f, size.height)
13 | }
14 | val Parallelogram = GenericShape { size, _ ->
15 |
16 | val radian = (90 - 60) * Math.PI / 180
17 | val xOnOpposite = (size.height * tan(radian)).toFloat()
18 | moveTo(0f, size.height)
19 | lineTo(x = xOnOpposite, y = 0f)
20 | lineTo(x = size.width, y = 0f)
21 | lineTo(x = size.width - xOnOpposite, y = size.height)
22 | lineTo(x = xOnOpposite, y = size.height)
23 | }
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/helper/Extension.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.helper
2 |
3 | import androidx.compose.ui.graphics.Color
4 | import kotlin.random.Random
5 |
6 | fun Color.Companion.random() : Color {
7 | val red = Random.nextInt(256)
8 | val green = Random.nextInt(256)
9 | val blue = Random.nextInt(256)
10 | return Color(red, green, blue)
11 | }
12 |
13 | val String.color
14 | get() = Color(android.graphics.Color.parseColor(this))
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/navigation/NavGraph.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.navigation
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.navigation.NavHostController
5 | import androidx.navigation.compose.NavHost
6 | import androidx.navigation.compose.composable
7 | import com.esatgozcu.animationexamples.ui.animations.blinkcircle.BlinkCircleView
8 | import com.esatgozcu.animationexamples.ui.animations.circlerotation.CircleRotationView
9 | import com.esatgozcu.animationexamples.ui.animations.confetticenter.ConfettiCenterView
10 | import com.esatgozcu.animationexamples.ui.animations.fireworkcenter.FireworkCenterView
11 | import com.esatgozcu.animationexamples.ui.animations.paperplane.PaperPlaneView
12 | import com.esatgozcu.animationexamples.ui.animations.snowflake.SnowFlakeView
13 | import com.esatgozcu.animationexamples.ui.view.*
14 |
15 | @Composable
16 | fun NavGraph(navController: NavHostController) {
17 | NavHost(
18 | navController = navController,
19 | startDestination = Screens.HomePage.route
20 | ) {
21 | composable(route = Screens.HomePage.route) {
22 | HomePage(navController)
23 | }
24 | composable(route = Screens.SnowFlake.route) {
25 | SnowFlakeView()
26 | }
27 | composable(route = Screens.PaperPlane.route) {
28 | PaperPlaneView()
29 | }
30 | composable(route = Screens.BlinkCircle.route) {
31 | BlinkCircleView()
32 | }
33 | composable(route = Screens.CircleRotation.route) {
34 | CircleRotationView()
35 | }
36 | composable(route = Screens.ConfettiCenter.route) {
37 | ConfettiCenterView()
38 | }
39 | composable(route = Screens.FireworkCenter.route) {
40 | FireworkCenterView()
41 | }
42 | }
43 | }
44 |
45 | sealed class Screens(val route: String) {
46 | object HomePage: Screens("HomePage")
47 | object SnowFlake: Screens("SnowFlake")
48 | object PaperPlane: Screens("PaperPlane")
49 | object BlinkCircle: Screens("BlinkCircle")
50 | object CircleRotation: Screens("CircleRotation")
51 | object ConfettiCenter: Screens("ConfettiCenter")
52 | object FireworkCenter: Screens("FireworkCenter")
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/HomePage.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.view
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.foundation.shape.CircleShape
8 | import androidx.compose.material.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Alignment.Companion.CenterVertically
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.clip
14 | import androidx.compose.ui.graphics.Color
15 | import androidx.compose.ui.res.painterResource
16 | import androidx.compose.ui.tooling.preview.Preview
17 | import androidx.compose.ui.unit.dp
18 | import androidx.navigation.NavController
19 | import androidx.navigation.compose.rememberNavController
20 | import com.esatgozcu.animationexamples.R
21 | import com.esatgozcu.animationexamples.navigation.Screens
22 | import com.esatgozcu.animationexamples.ui.theme.AnimationExamplesTheme
23 |
24 | @Composable
25 | fun HomePage(navController: NavController) {
26 | Column(modifier = Modifier.fillMaxSize(),
27 | horizontalAlignment = Alignment.CenterHorizontally,
28 | verticalArrangement = Arrangement.Center,
29 | ) {
30 | HomePageItem(title = "Snow Flake", image = R.drawable.ic_snow_flake){
31 | navController.navigate(Screens.SnowFlake.route)
32 | }
33 | HomePageItem(title = "Paper Plane", image = R.drawable.ic_paper_plane){
34 | navController.navigate(Screens.PaperPlane.route)
35 | }
36 | Row(verticalAlignment = CenterVertically,
37 | horizontalArrangement = Arrangement.spacedBy(10.dp),
38 | modifier = Modifier
39 | .clickable {
40 | navController.navigate(Screens.BlinkCircle.route)
41 | }
42 | .padding(10.dp),
43 | ){
44 | Text(text = "Blink Circle")
45 | Box(
46 | modifier = Modifier
47 | .size(25.dp)
48 | .clip(CircleShape)
49 | .background(Color.Black)
50 | )
51 | }
52 | HomePageItem(title = "Circle Rotation", image = R.drawable.ic_rotate_3d){
53 | navController.navigate(Screens.CircleRotation.route)
54 | }
55 | Row(verticalAlignment = CenterVertically,
56 | horizontalArrangement = Arrangement.spacedBy(10.dp),
57 | modifier = Modifier
58 | .clickable {
59 | navController.navigate(Screens.ConfettiCenter.route)
60 | }
61 | .padding(10.dp),
62 | ){
63 | Text(text = "Confetti View")
64 | Text(
65 | text = "\uD83C\uDF89",
66 | modifier = Modifier
67 | .size(25.dp)
68 | )
69 | }
70 | Row(verticalAlignment = CenterVertically,
71 | horizontalArrangement = Arrangement.spacedBy(10.dp),
72 | modifier = Modifier
73 | .clickable {
74 | navController.navigate(Screens.FireworkCenter.route)
75 | }
76 | .padding(10.dp),
77 | ){
78 | Text(text = "Firework View")
79 | Text(
80 | text = "\uD83C\uDF86",
81 | modifier = Modifier
82 | .size(25.dp)
83 | )
84 | }
85 | }
86 | }
87 |
88 | @Composable
89 | fun HomePageItem(title:String,
90 | image:Int,
91 | click: (()->Unit)){
92 | Row(horizontalArrangement = Arrangement.spacedBy(10.dp),
93 | modifier = Modifier
94 | .clickable {
95 | click()
96 | }
97 | .padding(10.dp),
98 | verticalAlignment = CenterVertically
99 | ){
100 | Text(text = title)
101 | Image(
102 | modifier = Modifier.size(25.dp),
103 | painter = painterResource(id = image),
104 | contentDescription = ""
105 | )
106 | }
107 | }
108 |
109 | @Preview(showBackground = true)
110 | @Composable
111 | fun HomePagePreview() {
112 | AnimationExamplesTheme {
113 | HomePage(rememberNavController())
114 | }
115 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/blinkcircle/BlinkCircleVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.blinkcircle
2 |
3 | import androidx.compose.runtime.mutableStateOf
4 | import androidx.lifecycle.ViewModel
5 | import com.esatgozcu.animationexamples.helper.ScreenSize
6 |
7 | class BlinkCircleVM: ViewModel() {
8 |
9 | val smallSize = 0.2
10 | val normalSize = 1.0
11 | val animTime = 500
12 | val rowCount = mutableStateOf(2)
13 | val currentItem = mutableStateOf(rowCount.value*rowCount.value)
14 |
15 | fun calculateOffsetX(i: Int): Double {
16 | val onePiece = ScreenSize.screensWidth.div(rowCount.value)
17 | return onePiece * (i.rem(rowCount.value))
18 | }
19 | fun calculateOffsetY(i: Int): Double {
20 | val onePiece = ScreenSize.screensWidth.div(rowCount.value)
21 | val result = onePiece*(i.div(rowCount.value))
22 | val startPosition = ScreenSize.screenHeight.div(2) - ScreenSize.screensWidth.div(2)
23 | return result.plus(startPosition)
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/blinkcircle/BlinkCircleView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.blinkcircle
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.CircleShape
7 | import androidx.compose.runtime.*
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.draw.clip
10 | import androidx.compose.ui.draw.scale
11 | import androidx.compose.ui.graphics.Color
12 | import androidx.compose.ui.unit.dp
13 | import androidx.lifecycle.viewmodel.compose.viewModel
14 | import com.esatgozcu.animationexamples.helper.ScreenSize
15 | import kotlinx.coroutines.delay
16 |
17 | @Composable
18 | fun BlinkCircleView(viewModel: BlinkCircleVM = viewModel()) {
19 |
20 | @Composable
21 | fun scaleAnim(i: Int): Float {
22 | val itemTarget = remember { Animatable(viewModel.smallSize.toFloat()) }
23 | LaunchedEffect(key1 = viewModel.currentItem.value) {
24 | delay((viewModel.animTime * i).toLong())
25 | itemTarget.animateTo(
26 | targetValue = viewModel.normalSize.toFloat(),
27 | animationSpec = repeatable(
28 | iterations = 1,
29 | animation = tween(
30 | durationMillis = viewModel.animTime / 2,
31 | easing = LinearEasing
32 | ),
33 | repeatMode = RepeatMode.Restart,
34 | )
35 | )
36 | itemTarget.animateTo(
37 | targetValue = viewModel.smallSize.toFloat(),
38 | animationSpec = repeatable(
39 | iterations = 1,
40 | animation = tween(
41 | durationMillis = viewModel.animTime / 2,
42 | easing = LinearEasing
43 | ),
44 | repeatMode = RepeatMode.Restart,
45 | )
46 | )
47 | if (viewModel.currentItem.value - 1 == i) {
48 | viewModel.rowCount.value += 1
49 | viewModel.currentItem.value = viewModel.rowCount.value * viewModel.rowCount.value
50 | }
51 | }
52 | return itemTarget.value
53 | }
54 |
55 | Box(modifier = Modifier.fillMaxSize()) {
56 | (0 until viewModel.currentItem.value).forEachIndexed { i, _ ->
57 | Box(
58 | modifier = Modifier
59 | .offset(
60 | x = viewModel.calculateOffsetX(i).dp,
61 | y = viewModel.calculateOffsetY(i).dp
62 | )
63 | .size(ScreenSize.screensWidth.div(viewModel.rowCount.value).dp)
64 | .scale(
65 | scaleAnim(i = i)
66 | )
67 | .clip(CircleShape)
68 | .background(Color.Black.copy(scaleAnim(i = i)))
69 | )
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/circlerotation/CircleRotationVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.circlerotation
2 |
3 | import androidx.compose.runtime.mutableStateOf
4 | import androidx.lifecycle.ViewModel
5 | import com.esatgozcu.animationexamples.helper.ScreenSize
6 |
7 | class CircleRotationVM: ViewModel() {
8 |
9 | val itemSize = mutableStateOf(ScreenSize.screensWidth/2.0)
10 | var moveInOut = mutableStateOf(false)
11 | var itemCount = 3
12 | var degree = (360.0).div(itemCount)
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/circlerotation/CircleRotationView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.circlerotation
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.CircleShape
7 | import androidx.compose.runtime.*
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.draw.alpha
11 | import androidx.compose.ui.draw.clip
12 | import androidx.compose.ui.draw.rotate
13 | import androidx.compose.ui.draw.scale
14 | import androidx.compose.ui.graphics.Brush
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.unit.dp
17 | import androidx.lifecycle.viewmodel.compose.viewModel
18 |
19 | @Composable
20 | fun CircleRotationView(viewModel: CircleRotationVM = viewModel()) {
21 |
22 | @Composable
23 | fun infiniteRepeatable(): InfiniteRepeatableSpec{
24 | return infiniteRepeatable(
25 | animation = tween(
26 | durationMillis = 2000,
27 | easing = LinearOutSlowInEasing
28 | ),
29 | repeatMode = RepeatMode.Reverse
30 | )
31 | }
32 |
33 | Box(
34 | modifier = Modifier.fillMaxSize(),
35 | contentAlignment = Alignment.Center
36 | ) {
37 | Box(
38 | modifier = Modifier
39 | .scale(
40 | animateFloatAsState(
41 | targetValue =
42 | if (viewModel.moveInOut.value)
43 | 1.0.toFloat()
44 | else
45 | (1.0 / 4.0).toFloat(),
46 | animationSpec = infiniteRepeatable()
47 | ).value
48 | )
49 | .rotate(
50 | animateFloatAsState(
51 | targetValue =
52 | if (viewModel.moveInOut.value)
53 | 180.toFloat()
54 | else
55 | 0.toFloat(),
56 | animationSpec = infiniteRepeatable()
57 | ).value
58 | ),
59 | ) {
60 | (0 until viewModel.itemCount).forEachIndexed { i, _ ->
61 | Box(
62 | modifier = Modifier
63 | .rotate(
64 | degrees = animateFloatAsState(
65 | targetValue =
66 | if (viewModel.moveInOut.value)
67 | (viewModel.degree * i).toFloat()
68 | else
69 | 0.toFloat(),
70 | animationSpec = infiniteRepeatable()
71 | ).value
72 | )
73 | ) {
74 | Box(
75 | modifier = Modifier
76 | .size(viewModel.itemSize.value.dp)
77 | .offset(
78 | y = animateFloatAsState(
79 | targetValue =
80 | if (viewModel.moveInOut.value)
81 | -viewModel.itemSize.value.div(2).toFloat()
82 | else
83 | 0.toFloat(),
84 | animationSpec = infiniteRepeatable()
85 | ).value.dp
86 | )
87 | .clip(CircleShape)
88 | .alpha(0.5f)
89 | .background(
90 | brush = Brush.verticalGradient(
91 | colors = listOf(
92 | Color.Red,
93 | Color.White
94 | )
95 | ), alpha = 0.5f
96 | )
97 | )
98 | Box(
99 | modifier = Modifier
100 | .size(viewModel.itemSize.value.dp)
101 | .offset(
102 | y = animateFloatAsState(
103 | targetValue =
104 | if (viewModel.moveInOut.value)
105 | +viewModel.itemSize.value.div(2).toFloat()
106 | else
107 | 0.toFloat(),
108 | animationSpec = infiniteRepeatable()
109 | ).value.dp
110 | )
111 | .clip(CircleShape)
112 | .background(
113 | brush = Brush.verticalGradient(
114 | colors = listOf(
115 | Color.White,
116 | Color.Blue
117 | )
118 | ), alpha = 0.5f
119 | )
120 | )
121 | }
122 | }
123 | }
124 | }
125 |
126 | LaunchedEffect(Unit) {
127 | viewModel.moveInOut.value = true
128 | }
129 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter/ConfettiAnimationVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.confetticenter
2 |
3 | import androidx.compose.foundation.shape.CircleShape
4 | import androidx.compose.ui.graphics.*
5 | import androidx.lifecycle.ViewModel
6 | import com.esatgozcu.animationexamples.helper.CustomShape.Shapes.Parallelogram
7 | import com.esatgozcu.animationexamples.helper.CustomShape.Shapes.Triangle
8 | import com.esatgozcu.animationexamples.helper.random
9 |
10 | /// - Parameters:
11 | /// - counter: on any change of this variable the animation is run
12 | /// - num: amount of confetti
13 | /// - colors: list of colors that is applied to the default shapes
14 | /// - confettiSize: size that confetti and emojis are scaled to
15 | /// - dropHeight: vertical distance that confetti pass
16 | /// - fadesOut: reduce opacity towards the end of the animation
17 | /// - opacity: maximum opacity that is reached during the animation
18 | /// - openingAngle: boundary that defines the opening angle in degrees
19 | /// - closingAngle: boundary that defines the closing angle in degrees
20 | /// - radius: explosion radius
21 | /// - repetitions: number of repetitions of the explosion
22 | /// - repetitionInterval: duration between the repetitions
23 | class ConfettiAnimationVM(
24 | var confettiNumber: Int = 20,
25 | var confettiTypes: List = listOf(
26 | ConfettiTypes.Shape(SHAPES.TRIANGLE),
27 | ConfettiTypes.Shape(SHAPES.CIRCLE),
28 | ConfettiTypes.Shape(SHAPES.RECTANGLE),
29 | ConfettiTypes.Shape(SHAPES.PARALLELOGRAM),
30 | ),
31 | var colors: List = listOf(
32 | Color.random(),
33 | Color.random(),
34 | Color.random(),
35 | Color.random(),
36 | Color.random(),
37 | Color.random()
38 | ),
39 | var confettiSize: Float = 13.0f,
40 | var dropHeight: Float = 600.0f,
41 | var fadesOut: Boolean = true,
42 | var fireworkEffect: Boolean = false,
43 | var opacity: Double = 1.0,
44 | var openingAngle: Double = 60.0,
45 | var closingAngle: Double = 120.0,
46 | var radius: Float = 300f,
47 | var repetitions: Int = 0,
48 | var repetitionInterval: Double = 1000.0,
49 | var explosionAnimDuration: Double = 200.0,
50 | var dropAnimationDuration: Double = 4500.0,
51 | ): ViewModel() {
52 | fun getAnimDuration(): Double {
53 | return explosionAnimDuration + dropAnimationDuration
54 | }
55 | }
56 |
57 | sealed interface ConfettiTypes {
58 | data class Image(val value: Int) : ConfettiTypes
59 | data class Text(val value: String) : ConfettiTypes
60 | data class Shape(val value: SHAPES) : ConfettiTypes
61 | }
62 |
63 | enum class SHAPES(val shape: Shape){
64 | RECTANGLE(RectangleShape),
65 | CIRCLE(CircleShape),
66 | TRIANGLE(Triangle),
67 | PARALLELOGRAM(Parallelogram)
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/confetticenter/ConfettiAnimationView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.confetticenter
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.background
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.material.Button
8 | import androidx.compose.material.ButtonDefaults
9 | import androidx.compose.material.Text
10 | import androidx.compose.runtime.*
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.alpha
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.graphics.*
16 | import androidx.compose.ui.res.painterResource
17 | import androidx.compose.ui.unit.dp
18 | import androidx.compose.ui.unit.sp
19 | import androidx.lifecycle.viewmodel.compose.viewModel
20 | import kotlinx.coroutines.delay
21 | import kotlinx.coroutines.launch
22 | import kotlin.math.PI
23 | import kotlin.math.cos
24 | import kotlin.math.pow
25 | import kotlin.math.sin
26 | import kotlin.random.Random
27 |
28 | @Composable
29 | fun ConfettiCenterView(viewModel: ConfettiAnimationVM = viewModel()) {
30 |
31 | val counter = remember { mutableStateOf(0) }
32 |
33 | Box(
34 | modifier = Modifier.fillMaxSize(),
35 | contentAlignment = Alignment.Center
36 | ) {
37 | Button(
38 | colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
39 | onClick = {
40 | counter.value += 1
41 | }) {
42 | Text(text = "\uD83C\uDF89")
43 | }
44 | /* FireworkEffect
45 | viewModel.fireworkEffect = true
46 | viewModel.confettiNumber = 40
47 | viewModel.openingAngle = 0.0
48 | viewModel.closingAngle = 360.0
49 | viewModel.radius = 200.0f */
50 |
51 | /* Emoji - Text
52 | viewModel.confettiTypes = listOf(
53 | ConfettiTypes.Text("❤️"),
54 | ConfettiTypes.Text("\uD83D\uDC99"),
55 | ConfettiTypes.Text("A")
56 | )
57 | viewModel.confettiSize = 20.0f */
58 |
59 | /* Image
60 | viewModel.confettiTypes = listOf(
61 | ConfettiTypes.Image(R.drawable.ic_snow_flake),
62 | ConfettiTypes.Image(R.drawable.ic_paper_plane),
63 | ConfettiTypes.Image(R.drawable.ic_rotate_3d)
64 | )
65 | viewModel.fadesOut = false */
66 |
67 | /* Default */
68 | ConfettiView(counter, viewModel)
69 | }
70 | }
71 |
72 | @Composable
73 | fun ConfettiView(currentValue: MutableState, viewModel: ConfettiAnimationVM) {
74 |
75 | val animated = remember { mutableStateOf(0) }
76 | val firstAppear = remember { mutableStateOf(false) }
77 |
78 | val repeatInterval = viewModel.repetitionInterval
79 | val repeatCount = viewModel.repetitions
80 |
81 | Box {
82 | for (i in 0 until animated.value) {
83 | ConfettiContainer(viewModel)
84 | }
85 | }
86 |
87 | LaunchedEffect(currentValue.value) {
88 | if (firstAppear.value) {
89 | for (i in 0..repeatCount) {
90 | launch {
91 | delay((repeatInterval * i).toLong())
92 | animated.value += 1
93 | }
94 | }
95 | }
96 | firstAppear.value = true
97 | }
98 | }
99 |
100 | @Composable
101 | fun ConfettiContainer(viewModel: ConfettiAnimationVM) {
102 |
103 | val confettiNumber = remember { mutableStateOf(viewModel.confettiNumber) }
104 | val animDuration = viewModel.getAnimDuration()
105 |
106 | Box {
107 | for (i in 0 until confettiNumber.value) {
108 | ConfettiFrame(viewModel)
109 | }
110 | }
111 |
112 | LaunchedEffect(Unit) {
113 | delay(animDuration.toLong())
114 | //Clear animated
115 | confettiNumber.value = 0
116 | }
117 | }
118 |
119 | @Composable
120 | fun ConfettiFrame(viewModel: ConfettiAnimationVM) {
121 |
122 | val type = remember { viewModel.confettiTypes.random() }
123 | val color = remember { viewModel.colors.random() }
124 |
125 | val animateY = remember { Animatable(0.0f) }
126 | val animateX = remember { Animatable(0.0f) }
127 | val opacity = remember { Animatable(0.0f) }
128 |
129 | val scope = rememberCoroutineScope()
130 | val openAngle = viewModel.openingAngle
131 | val closeAngle = viewModel.closingAngle
132 | val explosionAnimationDuration = viewModel.explosionAnimDuration
133 | val dropAnimationDuration = viewModel.dropAnimationDuration
134 | val radius = viewModel.radius
135 | val dropHeight = viewModel.dropHeight
136 |
137 | fun getDelayBeforeDropAnimation(): Double {
138 | return explosionAnimationDuration * 0.0001
139 | }
140 | fun getRandomExplosionTimeVariation(): Float {
141 | return ((0..999).random().toFloat() * 0.0005).toFloat()
142 | }
143 | fun getAnimationDuration(): Double {
144 | return explosionAnimationDuration + getRandomExplosionTimeVariation()
145 | }
146 | fun getRandomAngle(): Float {
147 | return if (closeAngle == openAngle) {
148 | closeAngle.toFloat()
149 | } else if (closeAngle > openAngle) {
150 | Random.nextDouble(openAngle, closeAngle).toFloat()
151 | } else {
152 | Random.nextDouble(openAngle, (closeAngle + 360)).rem(360).toFloat()
153 | }
154 | }
155 | val randomAngle = remember {
156 | getRandomAngle()
157 | }
158 | fun getDistance(): Float {
159 | return if (viewModel.fireworkEffect){
160 | radius
161 | } else{
162 | (Random.nextDouble(0.01, 1.0).pow(0.25) * radius).toFloat()
163 | }
164 | }
165 | fun deg2rad(number: Float): Float {
166 | return (number * PI / 180).toFloat()
167 | }
168 |
169 | Box(
170 | modifier = Modifier
171 | .offset(
172 | x = animateX.value.dp,
173 | y = animateY.value.dp
174 | ),
175 | ) {
176 | ConfettiItem(color = color,
177 | type = type,
178 | alpha = opacity.value,
179 | size = viewModel.confettiSize)
180 | }
181 |
182 | LaunchedEffect(Unit) {
183 | scope.launch {
184 | animateX.animateTo(
185 | targetValue = getDistance() * cos(deg2rad(randomAngle)),
186 | animationSpec = repeatable(
187 | iterations = 1,
188 | animation = tween(
189 | durationMillis = getAnimationDuration().toInt(),
190 | easing = CubicBezierEasing(0.1f, 1.0f, 0.0f, 1.0f)
191 | )
192 | )
193 | )
194 | }
195 | scope.launch {
196 | opacity.animateTo(
197 | targetValue = viewModel.opacity.toFloat(),
198 | animationSpec = repeatable(
199 | iterations = 1,
200 | animation = tween(
201 | durationMillis = getAnimationDuration().toInt(),
202 | easing = CubicBezierEasing(0.1f, 1.0f, 0.0f, 1.0f)
203 | )
204 | )
205 | )
206 | opacity.animateTo(
207 | targetValue = if (viewModel.fadesOut) 0f else viewModel.opacity.toFloat(),
208 | animationSpec = repeatable(
209 | iterations = 1,
210 | animation = tween(
211 | durationMillis = dropAnimationDuration.toInt(),
212 | delayMillis = getDelayBeforeDropAnimation().toInt(),
213 | easing = LinearEasing
214 | )
215 | )
216 | )
217 | }
218 | scope.launch {
219 | animateY.animateTo(
220 | targetValue = -getDistance() * sin(deg2rad(randomAngle)),
221 | animationSpec = repeatable(
222 | iterations = 1,
223 | animation = tween(
224 | durationMillis = getAnimationDuration().toInt(),
225 | easing = CubicBezierEasing(0.1f, 1.0f, 0.0f, 1.0f)
226 | )
227 | )
228 | )
229 | animateY.animateTo(
230 | targetValue = dropHeight,
231 | animationSpec = repeatable(
232 | iterations = 1,
233 | animation = tween(
234 | durationMillis = dropAnimationDuration.toInt(),
235 | delayMillis = getDelayBeforeDropAnimation().toInt(),
236 | easing = CubicBezierEasing(0.12f, 0f, 0.39f, 0f)
237 | )
238 | )
239 | )
240 | }
241 | }
242 | }
243 |
244 | @Composable
245 | fun ConfettiItem(alpha: Float, color: Color, type: ConfettiTypes, size: Float) {
246 |
247 | val infiniteTransition = rememberInfiniteTransition()
248 | val randomAnchorX = remember { (0..1).random() }
249 | val randomAnchorY = remember { (0..1).random() }
250 | val spinDirX = remember { (0..1).random() * 2 - 1 }
251 | val spinDirZ = remember { (0..1).random() * 2 - 1 }
252 | val speed = remember { (500..2000).random() }
253 |
254 | val angle by infiniteTransition.animateFloat(
255 | initialValue = 0F,
256 | targetValue = 360F,
257 | animationSpec = infiniteRepeatable(
258 | animation = tween(speed, easing = LinearEasing)
259 | )
260 | )
261 |
262 | when (type) {
263 | is ConfettiTypes.Shape ->
264 | Box(
265 | modifier = Modifier
266 | .graphicsLayer(
267 | rotationX = spinDirX * angle,
268 | )
269 | .graphicsLayer(
270 | transformOrigin = TransformOrigin(
271 | pivotFractionX = randomAnchorX.toFloat(),
272 | pivotFractionY = randomAnchorY.toFloat(),
273 | ),
274 | rotationZ = spinDirZ * angle,
275 | )
276 | .size(size.dp)
277 | .alpha(alpha)
278 | .clip(type.value.shape)
279 | .background(color)
280 | )
281 | is ConfettiTypes.Image ->
282 | Image(
283 | painter = painterResource(id = type.value), "",
284 | modifier = Modifier
285 | .graphicsLayer(
286 | rotationX = spinDirX * angle,
287 | )
288 | .graphicsLayer(
289 | transformOrigin = TransformOrigin(
290 | pivotFractionX = randomAnchorX.toFloat(),
291 | pivotFractionY = randomAnchorY.toFloat(),
292 | ),
293 | rotationZ = spinDirZ * angle,
294 | )
295 | .size(size.dp)
296 | .alpha(alpha)
297 | )
298 | is ConfettiTypes.Text ->
299 | Text(
300 | text = type.value,
301 | color = color,
302 | modifier = Modifier
303 | .graphicsLayer(
304 | rotationX = spinDirX * angle,
305 | )
306 | .graphicsLayer(
307 | transformOrigin = TransformOrigin(
308 | pivotFractionX = randomAnchorX.toFloat(),
309 | pivotFractionY = randomAnchorY.toFloat(),
310 | ),
311 | rotationZ = spinDirZ * angle,
312 | )
313 | .alpha(alpha),
314 | fontSize = size.sp,
315 | )
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/fireworkcenter/FireworkCenterVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.fireworkcenter
2 |
3 | import androidx.compose.ui.graphics.*
4 | import androidx.lifecycle.ViewModel
5 | import com.esatgozcu.animationexamples.helper.color
6 | import com.esatgozcu.animationexamples.ui.animations.confetticenter.SHAPES
7 |
8 | /// - Parameters:
9 | /// - pieceCount: amount of confetti
10 | /// - colors: list of colors that is applied to the default shapes
11 | /// - pieceSize: size that confetti and emojis are scaled to
12 | /// - radius: explosion radius
13 | /// - repetitions: number of repetitions of the explosion
14 | /// - repetitionInterval: duration between the repetitions
15 | class FireworkCenterVM(
16 | var pieceCount: Int = 20,
17 | var pieceType: List = listOf(
18 | FireworkTypes.Shape(SHAPES.CIRCLE),
19 | ),
20 | var colors: List = listOf(
21 | "#f88f22".color,
22 | "#9c1d08".color,
23 | "#ce7117".color,
24 | "#f24d24".color,
25 | "#113bc6".color,
26 | "#c54a85".color,
27 | "#92af96".color,
28 | "#d23508".color,
29 | ),
30 | var pieceSize: Float = 5.0f,
31 | var radius: Float = 100f,
32 | var repetitions: Int = 0,
33 | var repetitionInterval: Double = 1000.0,
34 | var explosionAnimDuration: Double = 1200.0,
35 | var launchAnimDuration: Double = 3000.0,
36 | ): ViewModel() {
37 | fun getAnimDuration(): Double {
38 | return explosionAnimDuration + launchAnimDuration
39 | }
40 | }
41 |
42 | sealed interface FireworkTypes {
43 | data class Image(val value: Int) : FireworkTypes
44 | data class Text(val value: String) : FireworkTypes
45 | data class Shape(val value: SHAPES) : FireworkTypes
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/fireworkcenter/FireworkCenterView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.fireworkcenter
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.CircleShape
7 | import androidx.compose.material.Button
8 | import androidx.compose.material.ButtonDefaults
9 | import androidx.compose.material.Text
10 | import androidx.compose.runtime.*
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.alpha
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.geometry.Offset
16 | import androidx.compose.ui.graphics.*
17 | import androidx.compose.ui.unit.dp
18 | import androidx.lifecycle.viewmodel.compose.viewModel
19 | import kotlinx.coroutines.delay
20 | import kotlinx.coroutines.launch
21 | import kotlin.math.PI
22 | import kotlin.math.cos
23 | import kotlin.math.pow
24 | import kotlin.math.sin
25 | import kotlin.random.Random
26 | import androidx.compose.foundation.Canvas
27 | import androidx.compose.foundation.Image
28 | import androidx.compose.ui.graphics.drawscope.Stroke
29 | import androidx.compose.ui.res.painterResource
30 | import androidx.compose.ui.unit.sp
31 | import com.esatgozcu.animationexamples.helper.random
32 | import com.esatgozcu.animationexamples.ui.animations.confetticenter.ConfettiTypes
33 |
34 | @Composable
35 | fun FireworkCenterView(viewModel: FireworkCenterVM = viewModel()) {
36 |
37 | val counter = remember { mutableStateOf(0) }
38 |
39 | Box(
40 | modifier = Modifier.fillMaxSize().background(Color.Black),
41 | contentAlignment = Alignment.BottomCenter
42 | ) {
43 | Button(
44 | colors = ButtonDefaults.buttonColors(backgroundColor = Color.White),
45 | onClick = {
46 | counter.value += 1
47 | }) {
48 | Text(text = "\uD83E\uDDE8")
49 | }
50 | viewModel.repetitions = 100
51 | viewModel.repetitionInterval = 500.0
52 | FireworkView(counter, viewModel)
53 | }
54 | }
55 |
56 | @Composable
57 | fun FireworkView(currentValue: MutableState, viewModel: FireworkCenterVM) {
58 |
59 | val animated = remember { mutableStateOf(0) }
60 | val firstAppear = remember { mutableStateOf(false) }
61 |
62 | val repeatInterval = viewModel.repetitionInterval
63 | val repeatCount = viewModel.repetitions
64 |
65 | Box {
66 | for (i in 0 until animated.value) {
67 | FireworkContainer(viewModel)
68 | }
69 | }
70 |
71 | LaunchedEffect(currentValue.value) {
72 | if (firstAppear.value) {
73 | for (i in 0..repeatCount) {
74 | launch {
75 | delay((repeatInterval * i).toLong())
76 | animated.value += 1
77 | }
78 | }
79 | }
80 | firstAppear.value = true
81 | }
82 | }
83 |
84 | @Composable
85 | fun FireworkContainer(viewModel: FireworkCenterVM) {
86 |
87 | val scope = rememberCoroutineScope()
88 | val piecesNumber = remember { mutableStateOf(viewModel.pieceCount) }
89 | val animateY = remember { Animatable(0.0f) }
90 | val animateX = remember { Animatable(0.0f) }
91 | val randomX = remember { (-100..100).random() }
92 | val randomY = remember { (150..650).random() }
93 |
94 | Box(
95 | modifier = Modifier
96 | .offset(
97 | x = animateX.value.dp,
98 | y = animateY.value.dp
99 | )
100 | ) {
101 | for (i in 0 until piecesNumber.value) {
102 | FireworkFrame(viewModel, i, launchHeight = randomY.toFloat())
103 | }
104 | }
105 |
106 | LaunchedEffect(Unit) {
107 | scope.launch {
108 | animateY.animateTo(
109 | targetValue = -randomY.toFloat(),
110 | animationSpec = repeatable(
111 | iterations = 1,
112 | animation = tween(
113 | durationMillis = viewModel.launchAnimDuration.toInt(),
114 | easing = CubicBezierEasing(0.075f, 0.690f, 0.330f, 0.870f)
115 | )
116 | )
117 | )
118 | }
119 | scope.launch {
120 | animateX.animateTo(
121 | targetValue = randomX.toFloat(),
122 | animationSpec = repeatable(
123 | iterations = 1,
124 | animation = tween(
125 | durationMillis = viewModel.launchAnimDuration.toInt(),
126 | easing = CubicBezierEasing(0.075f, 0.690f, 0.330f, 0.870f)
127 | )
128 | )
129 | )
130 | }
131 | delay(viewModel.getAnimDuration().toLong())
132 | //Clear animated
133 | piecesNumber.value = 0
134 | }
135 | }
136 |
137 | @Composable
138 | fun FireworkFrame(viewModel: FireworkCenterVM, i: Int, launchHeight: Float) {
139 |
140 | val scope = rememberCoroutineScope()
141 |
142 | val type = remember { viewModel.pieceType.random() }
143 | val color = remember { viewModel.colors.random() }
144 |
145 | val animateY = remember { Animatable(0.0f) }
146 | val animateX = remember { Animatable(0.0f) }
147 | val opacity = remember { Animatable(1.0f) }
148 | val strokeAnimate = remember { Animatable(2.0f) }
149 |
150 | val radius = viewModel.radius + (launchHeight / 10)
151 |
152 | fun getRandomExplosionTimeVariation(): Float {
153 | return ((0..999).random().toFloat() * 0.0005).toFloat()
154 | }
155 |
156 | fun getAnimationDuration(): Double {
157 | return viewModel.explosionAnimDuration + getRandomExplosionTimeVariation()
158 | }
159 |
160 | fun getRandomAngle(): Float {
161 | return (360 / viewModel.pieceCount * (i)).toFloat()
162 | }
163 |
164 | fun getDistance(): Float {
165 | return radius
166 | }
167 |
168 | fun deg2rad(number: Float): Float {
169 | return (number * PI / 180).toFloat()
170 | }
171 |
172 | val randomAngle = remember {
173 | getRandomAngle()
174 | }
175 |
176 | val path = remember {
177 | Path()
178 | }
179 |
180 | Box(modifier = Modifier, contentAlignment = Alignment.Center){
181 | Box(
182 | modifier = Modifier
183 | .offset(
184 | x = animateX.value.dp,
185 | y = animateY.value.dp
186 | ),
187 | ) {
188 | FireworkItem(
189 | color = color,
190 | alpha = opacity.value,
191 | size = viewModel.pieceSize,
192 | type = type,
193 | viewModel = viewModel
194 | )
195 | }
196 | Canvas(modifier = Modifier) {
197 | path.lineTo((animateX.value*2.6).toFloat(), (animateY.value*2.6).toFloat())
198 | drawPath(
199 | color = color,
200 | path = path,
201 | style = Stroke(
202 | width = strokeAnimate.value.dp.toPx(),
203 | cap = StrokeCap.Round,
204 | join = StrokeJoin.Round
205 | ),
206 | alpha = opacity.value
207 | )
208 | }
209 | }
210 |
211 | LaunchedEffect(Unit) {
212 | delay(viewModel.launchAnimDuration.toLong())
213 | scope.launch {
214 | animateX.animateTo(
215 | targetValue = getDistance() * cos(deg2rad(randomAngle)),
216 | animationSpec = repeatable(
217 | iterations = 1,
218 | animation = tween(
219 | durationMillis = getAnimationDuration().toInt(),
220 | easing =
221 | LinearEasing
222 | )
223 | )
224 | )
225 | }
226 | scope.launch {
227 | opacity.animateTo(
228 | targetValue = 0.0f,
229 | animationSpec = repeatable(
230 | iterations = 1,
231 | animation = tween(
232 | durationMillis = getAnimationDuration().toInt(),
233 | easing = CubicBezierEasing(0.8f, 0.2f, 1.0f, 1.0f)
234 | )
235 | )
236 | )
237 | }
238 | scope.launch {
239 | animateY.animateTo(
240 | targetValue = -getDistance() * sin(deg2rad(randomAngle)),
241 | animationSpec = repeatable(
242 | iterations = 1,
243 | animation = tween(
244 | durationMillis = getAnimationDuration().toInt(),
245 | easing = if (randomAngle < 180)
246 | CubicBezierEasing(0.0f, 1.0f, 1.0f, 1.0f)
247 | else
248 | CubicBezierEasing(1f-((650-launchHeight)/1000), (650-launchHeight)/1000, 1.0f, 1.0f)
249 | )
250 | )
251 | )
252 | }
253 | scope.launch {
254 | strokeAnimate.animateTo(
255 | targetValue = 1.0f,
256 | animationSpec = repeatable(
257 | iterations = 1,
258 | animation = tween(
259 | durationMillis = getAnimationDuration().toInt(),
260 | easing = LinearEasing
261 | )
262 | )
263 | )
264 | }
265 | }
266 | }
267 |
268 | @Composable
269 | fun FireworkItem(
270 | alpha: Float,
271 | color: Color,
272 | size: Float,
273 | type: FireworkTypes,
274 | viewModel: FireworkCenterVM
275 | ) {
276 | val scope = rememberCoroutineScope()
277 | val animateSize = remember { Animatable(size) }
278 |
279 | when (type) {
280 | is FireworkTypes.Shape ->
281 | Box(
282 | modifier = Modifier
283 | .size(animateSize.value.dp)
284 | .alpha(alpha)
285 | .clip(type.value.shape)
286 | .background(color)
287 | )
288 | is FireworkTypes.Image ->
289 | Image(
290 | painter = painterResource(id = type.value), "",
291 | modifier = Modifier
292 | .size(animateSize.value.dp)
293 | .alpha(alpha)
294 | )
295 | is FireworkTypes.Text ->
296 | Text(
297 | text = type.value,
298 | color = color,
299 | modifier = Modifier
300 | .alpha(alpha),
301 | fontSize = animateSize.value.sp,
302 | )
303 | }
304 |
305 | LaunchedEffect(Unit) {
306 | scope.launch {
307 | animateSize.animateTo(
308 | targetValue = 0.0f,
309 | animationSpec = repeatable(
310 | iterations = 1,
311 | animation = tween(
312 | durationMillis = viewModel.explosionAnimDuration.toInt(),
313 | delayMillis = viewModel.launchAnimDuration.toInt(),
314 | easing = LinearEasing
315 | )
316 | )
317 | )
318 | }
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/paperplane/PaperPlaneVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.paperplane
2 |
3 | import androidx.compose.runtime.mutableStateOf
4 | import androidx.lifecycle.ViewModel
5 | import com.esatgozcu.animationexamples.helper.ScreenSize
6 |
7 | class PaperPlaneVM: ViewModel() {
8 |
9 | val itemSize = 20
10 | var action = mutableStateOf(false)
11 | //Lists
12 | var mRandomYList = List(itemSize) { (100..(ScreenSize.screenHeight.toInt())).random() }
13 | var mRandomSize = List(itemSize) { (20..100).random() }
14 | var mRandomDurationMillis = List(itemSize) { (400..1200).random() }
15 | var mDelayMillis = List(itemSize) { (0..1000).random() }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/paperplane/PaperPlaneView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.paperplane
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.runtime.*
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.res.painterResource
9 | import androidx.compose.ui.unit.dp
10 | import androidx.lifecycle.viewmodel.compose.viewModel
11 | import com.esatgozcu.animationexamples.R
12 | import com.esatgozcu.animationexamples.helper.ScreenSize
13 |
14 | @Composable
15 | fun PaperPlaneView(viewModel: PaperPlaneVM = viewModel()){
16 |
17 | Box(modifier = Modifier.fillMaxSize()) {
18 | for (i in 0 until viewModel.itemSize) {
19 | Image(modifier = Modifier
20 | .size(viewModel.mRandomSize[i].dp)
21 | .offset(
22 | x = animateDpAsState(
23 | targetValue =
24 | if (viewModel.action.value)
25 | (ScreenSize.screensWidth).dp
26 | else
27 | -(viewModel.mRandomSize[i]).dp,
28 | animationSpec = repeatable(
29 | 10,
30 | animation = tween(
31 | durationMillis = viewModel.mRandomDurationMillis[i],
32 | delayMillis = viewModel.mDelayMillis[i],
33 | easing = LinearEasing
34 | ),
35 | repeatMode = RepeatMode.Restart
36 | )
37 | ).value,
38 | y = animateDpAsState(
39 | targetValue =
40 | if (viewModel.action.value)
41 | (viewModel.mRandomYList[i]-ScreenSize.screensWidth).dp
42 | else viewModel.mRandomYList[i].dp,
43 | animationSpec = repeatable(
44 | 10,
45 | animation = tween(
46 | durationMillis = viewModel.mRandomDurationMillis[i],
47 | delayMillis = viewModel.mDelayMillis[i],
48 | easing = LinearEasing
49 | ),
50 | repeatMode = RepeatMode.Restart
51 | )
52 | ).value
53 | ),
54 | painter = painterResource(id = R.drawable.ic_paper_plane),
55 | contentDescription = "")
56 | }
57 | }
58 | LaunchedEffect(Unit){
59 | viewModel.action.value = true
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/snowflake/SnowFlakeVM.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.snowflake
2 |
3 | import androidx.compose.runtime.mutableStateOf
4 | import androidx.lifecycle.ViewModel
5 | import com.esatgozcu.animationexamples.helper.ScreenSize
6 |
7 | class SnowFlakeVM: ViewModel() {
8 |
9 | val itemSize = 20
10 | var action = mutableStateOf(false)
11 | //Lists
12 | var mRandomXList = List(itemSize) { (-20..((ScreenSize.screensWidth)+20).toInt()).random() }
13 | var mRandomSize = List(itemSize) { (30..90).random() }
14 | var mRandomDurationMillis = List(itemSize) { (2000..3000).random() }
15 | var mDelayMillis = List(itemSize) { (0..3000).random() }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/animations/snowflake/SnowFlakeView.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.animations.snowflake
2 |
3 | import androidx.compose.animation.core.*
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.runtime.*
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.res.painterResource
9 | import androidx.compose.ui.unit.dp
10 | import androidx.lifecycle.viewmodel.compose.viewModel
11 | import com.esatgozcu.animationexamples.R
12 | import com.esatgozcu.animationexamples.helper.ScreenSize
13 |
14 | @Composable
15 | fun SnowFlakeView(viewModel: SnowFlakeVM = viewModel()){
16 |
17 | Box(modifier = Modifier.fillMaxSize()) {
18 | for (i in 0 until viewModel.itemSize) {
19 | Image(
20 | modifier = Modifier
21 | .size(viewModel.mRandomSize[i].dp)
22 | .offset(
23 | x = viewModel.mRandomXList[i].dp,
24 | y = animateDpAsState(
25 | targetValue = if (viewModel.action.value) ScreenSize.screenHeight.dp else -viewModel.mRandomSize[i].dp,
26 | animationSpec = repeatable(
27 | 10,
28 | animation = tween(
29 | durationMillis = viewModel.mRandomDurationMillis[i],
30 | delayMillis = viewModel.mDelayMillis[i],
31 | easing = LinearEasing
32 | ),
33 | repeatMode = RepeatMode.Restart
34 | )
35 | ).value
36 | ),
37 | painter = painterResource(id = R.drawable.ic_snow_flake),
38 | contentDescription = ""
39 | )
40 | }
41 | }
42 | LaunchedEffect(Unit){
43 | viewModel.action.value = true
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple200 = Color(0xFFBB86FC)
6 | val Purple500 = Color(0xFF6200EE)
7 | val Purple700 = Color(0xFF3700B3)
8 | val Teal200 = Color(0xFF03DAC5)
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.theme
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.material.Shapes
5 | import androidx.compose.ui.unit.dp
6 |
7 | val Shapes = Shapes(
8 | small = RoundedCornerShape(4.dp),
9 | medium = RoundedCornerShape(4.dp),
10 | large = RoundedCornerShape(0.dp)
11 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material.MaterialTheme
5 | import androidx.compose.material.darkColors
6 | import androidx.compose.material.lightColors
7 | import androidx.compose.runtime.Composable
8 |
9 | private val DarkColorPalette = darkColors(
10 | primary = Purple200,
11 | primaryVariant = Purple700,
12 | secondary = Teal200
13 | )
14 |
15 | private val LightColorPalette = lightColors(
16 | primary = Purple500,
17 | primaryVariant = Purple700,
18 | secondary = Teal200
19 |
20 | /* Other default colors to override
21 | background = Color.White,
22 | surface = Color.White,
23 | onPrimary = Color.White,
24 | onSecondary = Color.Black,
25 | onBackground = Color.Black,
26 | onSurface = Color.Black,
27 | */
28 | )
29 |
30 | @Composable
31 | fun AnimationExamplesTheme(
32 | darkTheme: Boolean = isSystemInDarkTheme(),
33 | content: @Composable () -> Unit
34 | ) {
35 | val colors = if (darkTheme) {
36 | DarkColorPalette
37 | } else {
38 | LightColorPalette
39 | }
40 |
41 | MaterialTheme(
42 | colors = colors,
43 | typography = Typography,
44 | shapes = Shapes,
45 | content = content
46 | )
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/esatgozcu/animationexamples/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples.ui.theme
2 |
3 | import androidx.compose.material.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | body1 = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp
15 | )
16 | /* Other default text styles to override
17 | button = TextStyle(
18 | fontFamily = FontFamily.Default,
19 | fontWeight = FontWeight.W500,
20 | fontSize = 14.sp
21 | ),
22 | caption = TextStyle(
23 | fontFamily = FontFamily.Default,
24 | fontWeight = FontWeight.Normal,
25 | fontSize = 12.sp
26 | )
27 | */
28 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_paper_plane.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
10 |
12 |
15 |
18 |
21 |
22 |
23 |
25 |
26 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_rotate_3d.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_snow_flake.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AnimationExamples
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/esatgozcu/animationexamples/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.esatgozcu.animationexamples
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | compose_version = '1.1.0-beta01'
4 | }
5 | }// Top-level build file where you can add configuration options common to all sub-projects/modules.
6 | plugins {
7 | id 'com.android.application' version '7.2.1' apply false
8 | id 'com.android.library' version '7.2.1' apply false
9 | id 'org.jetbrains.kotlin.android' version '1.5.31' apply false
10 | }
11 |
12 | task clean(type: Delete) {
13 | delete rootProject.buildDir
14 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esatgozcu/Compose-Animation-Examples/553dd8e39273adbf14ce027dfe0f5b7ed4ca16b3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 14 10:08:01 PGT 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "AnimationExamples"
16 | include ':app'
17 |
--------------------------------------------------------------------------------