├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── deploymentTargetDropDown.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── canopas │ │ └── composeanimations │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── canopas │ │ │ └── composeanimations │ │ │ ├── MainActivity.kt │ │ │ ├── animations │ │ │ ├── ArcRotationAnimation.kt │ │ │ ├── CircleOffsetAnimation.kt │ │ │ ├── ClockLoading.kt │ │ │ ├── HeartAnimation.kt │ │ │ ├── PacmanAnimation.kt │ │ │ ├── ProgressAnimation.kt │ │ │ ├── RotateDotAnimation.kt │ │ │ ├── RotateTwoDotsAnimation.kt │ │ │ ├── RotatingCircle.kt │ │ │ ├── RotatingSquare.kt │ │ │ ├── SquareFillLoaderAnimation.kt │ │ │ ├── ThreeBounceAnimation.kt │ │ │ ├── TwinCircleAnimation.kt │ │ │ └── WavesAnimation.kt │ │ │ ├── ui │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ ├── Shape.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── Type.kt │ │ │ └── utils │ │ │ └── animateValues.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_baseline_mic_24.xml │ │ └── ic_launcher_background.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 │ └── test │ └── java │ └── com │ └── canopas │ └── composeanimations │ └── ExampleUnitTest.kt ├── build.gradle ├── gif ├── RotateDotTwo.gif ├── arcRotation.gif ├── circleOffset.gif ├── clockAnim.gif ├── heartAnim.gif ├── pacman.gif ├── progress_animation.gif ├── rotateDot.gif ├── rotatinCircle.gif ├── rotatingSquare.gif ├── sqaure_fill_loader.gif ├── stepperAnim.gif ├── three_bounce_anim.gif ├── twinCircle.gif └── waveAnim.gif ├── 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 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Compose Animations -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

cta_banner2

2 | 3 | # Jetpack Compose animations 4 | 5 | Badge 6 | 7 | ## 🚀 Showcase 8 | 9 | 10 | 15 | 20 | 25 | 26 | 27 | 32 | 37 | 42 | 43 | 44 | 49 | 54 | 59 | 60 | 61 | 66 | 71 | 76 | 77 | 78 | 83 | 88 | 89 | 94 | 95 |
11 | 12 |
13 | Stepper animation 14 |
16 | 17 |
18 | Jumping Heart 19 |
21 | 22 |
23 | Progress Dots 24 |
28 | 29 |
30 | Wave 31 |
33 | 34 |
35 | Twin circle Scale 36 |
38 | 39 |
40 | Pacman 41 |
45 | 46 |
47 | TwinCircle Transition 48 |
50 | 51 |
52 | Arc rotation 53 |
55 | 56 |
57 | Rotating Square 58 |
62 | 63 |
64 | Clock 65 |
67 | 68 |
69 | Rotating Circle 70 |
72 | 73 |
74 | Sqare fill 75 |
79 | 80 |
81 | Three Bounce 82 |
84 | 85 |
86 | Rotate Dot 87 |
90 | 91 |
92 | Rotate Two Dots 93 |
96 | 97 | 98 | 99 | 100 | For detailed information about implementation checkout [article 1](https://blog.canopas.com/animations-in-jetpack-compose-with-examples-48307ba9dff1) & [article 2](https://blog.canopas.com/progress-animations-in-jetpack-compose-with-examples-eb76cc28fbb6) 101 | 102 | 103 | # Bugs and Feedback 104 | For bugs, questions and discussions please use the [Github Issues](https://github.com/canopas/Jetpack-compose-animations-examples/issues). 105 | 106 | # Credits 107 | 108 | This repository owned and maintained by the [Canopas team](https://canopas.com/). You can follow them on X at [@canopassoftware](https://x.com/canopassoftware) for project updates and releases. If you are interested in building apps or designing products, please let us know. We'd love to hear from you! 109 | 110 | 111 | 112 | 113 | 114 | # Licence 115 | 116 | ``` 117 | Copyright 2022 Canopas Software LLP 118 | 119 | Licensed under the Apache License, Version 2.0 (the "License"); 120 | you may not use this file except in compliance with the License. 121 | You may obtain a copy of the License at 122 | 123 | http://www.apache.org/licenses/LICENSE-2.0 124 | 125 | Unless required by applicable law or agreed to in writing, software 126 | distributed under the License is distributed on an "AS IS" BASIS, 127 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128 | See the License for the specific language governing permissions and 129 | limitations under the License. 130 | ``` 131 | 132 | -------------------------------------------------------------------------------- /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 31 8 | 9 | defaultConfig { 10 | applicationId "com.canopas.composeanimations" 11 | minSdk 21 12 | targetSdk 31 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.3' 58 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 59 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" 60 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" 61 | } -------------------------------------------------------------------------------- /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/canopas/composeanimations/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations 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.canopas.composeanimations", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.animation.core.FastOutSlowInEasing 7 | import androidx.compose.animation.core.animateFloatAsState 8 | import androidx.compose.animation.core.tween 9 | import androidx.compose.foundation.background 10 | import androidx.compose.foundation.clickable 11 | import androidx.compose.foundation.layout.* 12 | import androidx.compose.material.Surface 13 | import androidx.compose.material.Text 14 | import androidx.compose.runtime.* 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.Alignment.Companion.Center 17 | import androidx.compose.ui.Alignment.Companion.CenterHorizontally 18 | import androidx.compose.ui.Modifier 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.graphics.graphicsLayer 21 | import androidx.compose.ui.tooling.preview.Preview 22 | import androidx.compose.ui.unit.dp 23 | import androidx.compose.ui.unit.sp 24 | import com.canopas.composeanimations.ui.theme.ComposeAnimationsTheme 25 | import com.canopas.composeanimations.ui.theme.ThemeColor 26 | 27 | class MainActivity : ComponentActivity() { 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | setContent { 31 | ComposeAnimationsTheme { 32 | // A surface container using the 'background' color from the theme 33 | Surface( 34 | modifier = Modifier 35 | .fillMaxSize(), 36 | color = ThemeColor 37 | ) { 38 | Column( 39 | modifier = Modifier 40 | .fillMaxSize() 41 | .padding(50.dp), 42 | verticalArrangement = Arrangement.Center, 43 | horizontalAlignment = Alignment.CenterHorizontally 44 | ) { 45 | StepperAnimation(modifier = Modifier.align(CenterHorizontally)) 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | @Composable 54 | fun StepperAnimation(modifier: Modifier) { 55 | var currentNumber by remember { 56 | mutableStateOf(0) 57 | } 58 | 59 | var frontNumber by remember { 60 | mutableStateOf(currentNumber) 61 | } 62 | var backNumber by remember { 63 | mutableStateOf(currentNumber) 64 | } 65 | 66 | var targetAngle by remember { 67 | mutableStateOf(0f) 68 | } 69 | 70 | val rotation = animateFloatAsState( 71 | targetValue = targetAngle, 72 | animationSpec = tween( 73 | durationMillis = 400, 74 | easing = FastOutSlowInEasing, 75 | ) 76 | ) 77 | 78 | fun isFront(): Boolean { 79 | val value = kotlin.math.abs(rotation.value % 360) 80 | return value < 90 || value > 270 81 | } 82 | 83 | fun flipBack() { 84 | currentNumber -= 1 85 | if (isFront()) { 86 | backNumber = currentNumber 87 | } else { 88 | frontNumber = currentNumber 89 | } 90 | targetAngle -= 180f 91 | } 92 | 93 | fun flipNext() { 94 | currentNumber += 1 95 | if (isFront()) { 96 | backNumber = currentNumber 97 | } else { 98 | frontNumber = currentNumber 99 | } 100 | targetAngle += 180f 101 | } 102 | 103 | @Composable 104 | fun Step(number: Int, rotationY: Float) { 105 | Row( 106 | modifier = Modifier 107 | .fillMaxSize() 108 | .background(Color.White) 109 | .graphicsLayer { 110 | this.rotationY = rotationY 111 | } 112 | ) { 113 | Box(modifier = Modifier 114 | .weight(1f) 115 | .fillMaxHeight() 116 | .clickable { 117 | flipBack() 118 | }) 119 | 120 | Box( 121 | modifier = Modifier 122 | .weight(1f) 123 | .fillMaxHeight() 124 | ) { 125 | Text( 126 | modifier = Modifier.align(Center), 127 | text = number.toString(), color = Color.Black, fontSize = 40.sp 128 | ) 129 | } 130 | 131 | Box(modifier = Modifier 132 | .weight(1f) 133 | .fillMaxHeight() 134 | .clickable { 135 | flipNext() 136 | }) 137 | } 138 | 139 | } 140 | 141 | Box( 142 | modifier = modifier 143 | .height(80.dp) 144 | .width(200.dp) 145 | .graphicsLayer { 146 | rotationY = rotation.value 147 | } 148 | ) { 149 | if (isFront()) { 150 | //Front 151 | Step(number = frontNumber, rotationY = 0f) 152 | } else { 153 | //Back 154 | Step(number = backNumber, rotationY = rotation.value) 155 | } 156 | } 157 | 158 | } 159 | 160 | @Preview(showBackground = true) 161 | @Composable 162 | fun DefaultPreview() { 163 | ComposeAnimationsTheme { 164 | StepperAnimation(Modifier) 165 | } 166 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/ArcRotationAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.* 4 | import androidx.compose.foundation.Canvas 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.foundation.layout.size 9 | import androidx.compose.material.Surface 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.runtime.getValue 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.graphics.StrokeCap 16 | import androidx.compose.ui.graphics.drawscope.Stroke 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import com.canopas.composeanimations.ui.theme.ThemeColor 20 | 21 | @Preview 22 | @Composable 23 | fun PreviewArcRotationAnimation() { 24 | Surface( 25 | modifier = Modifier 26 | .fillMaxSize(), 27 | color = ThemeColor 28 | ) { 29 | ArcRotationAnimation() 30 | } 31 | } 32 | 33 | @Composable 34 | fun ArcRotationAnimation() { 35 | val infiniteTransition = rememberInfiniteTransition() 36 | 37 | 38 | val circleColor = Color(0xFFAFE1AF) 39 | val arcColor = Color(0XFFFFFFFF) 40 | val arcAngle1 by infiniteTransition.animateFloat( 41 | initialValue = 0F, 42 | targetValue = 180F, 43 | animationSpec = infiniteRepeatable( 44 | animation = tween(1000, easing = LinearEasing), 45 | repeatMode = RepeatMode.Restart 46 | ) 47 | ) 48 | 49 | val arcAngle2 by infiniteTransition.animateFloat( 50 | initialValue = 180F, 51 | targetValue = 360F, 52 | animationSpec = infiniteRepeatable( 53 | animation = tween(1000, easing = LinearEasing), 54 | repeatMode = RepeatMode.Restart 55 | ) 56 | ) 57 | 58 | val greenCircleAnimation by infiniteTransition.animateFloat( 59 | initialValue = 50f, 60 | targetValue = 80f, 61 | animationSpec = infiniteRepeatable( 62 | animation = tween(1000, delayMillis = 100, easing = FastOutLinearInEasing), 63 | repeatMode = RepeatMode.Reverse 64 | ) 65 | ) 66 | 67 | Box( 68 | modifier = Modifier.fillMaxSize(), 69 | contentAlignment = Alignment.Center 70 | ) { 71 | Canvas( 72 | modifier = Modifier 73 | .padding(12.dp) 74 | .size(100.dp) 75 | ) { 76 | drawArc( 77 | color = arcColor, 78 | startAngle = arcAngle1, 79 | sweepAngle = 90f, 80 | useCenter = false, 81 | style = Stroke(width = 10f, cap = StrokeCap.Round), 82 | ) 83 | 84 | drawArc( 85 | color = arcColor, 86 | startAngle = arcAngle2, 87 | sweepAngle = 90f, 88 | useCenter = false, 89 | style = Stroke(width = 10f, cap = StrokeCap.Round), 90 | ) 91 | 92 | drawCircle( 93 | color = arcColor, 94 | radius = 120f, 95 | ) 96 | 97 | drawCircle( 98 | color = circleColor, 99 | radius = greenCircleAnimation, 100 | ) 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/CircleOffsetAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.animateColor 4 | import androidx.compose.animation.core.* 5 | import androidx.compose.foundation.Canvas 6 | import androidx.compose.foundation.layout.Box 7 | import androidx.compose.foundation.layout.fillMaxSize 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.foundation.layout.size 10 | import androidx.compose.material.Surface 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.getValue 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.geometry.Offset 16 | import androidx.compose.ui.graphics.Color 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | import com.canopas.composeanimations.ui.theme.ThemeColor 20 | import com.canopas.composeanimations.utils.animateValues 21 | 22 | 23 | @Preview 24 | @Composable 25 | fun PreviewCircleOffsetAnimation() { 26 | Surface( 27 | modifier = Modifier 28 | .fillMaxSize(), 29 | color = ThemeColor 30 | ) { 31 | CircleOffsetAnimation() 32 | } 33 | } 34 | 35 | @Composable 36 | fun CircleOffsetAnimation() { 37 | val infiniteTransition = rememberInfiniteTransition() 38 | 39 | val easing = LinearOutSlowInEasing 40 | 41 | val color by infiniteTransition.animateColor( 42 | initialValue = Color(0xff2E5984), 43 | targetValue = Color(0xFF91BAD6), 44 | animationSpec = infiniteRepeatable( 45 | animation = tween(1500, easing = easing), 46 | repeatMode = RepeatMode.Reverse 47 | ) 48 | ) 49 | 50 | val color2 by infiniteTransition.animateColor( 51 | initialValue = Color(0xFF91BAD6), 52 | targetValue = Color(0xff2E5984), 53 | animationSpec = infiniteRepeatable( 54 | animation = tween(1500, easing = easing), 55 | repeatMode = RepeatMode.Reverse 56 | ) 57 | ) 58 | 59 | val offsetX by animateValues( 60 | values = listOf(0f, 100f, -100f, 0f), 61 | animationSpec = infiniteRepeatable( 62 | animation = tween(durationMillis = 1500, easing = easing), 63 | repeatMode = RepeatMode.Restart 64 | ) 65 | ) 66 | 67 | val scale by animateValues( 68 | values = listOf(1f, 10f, 10f, 10f, 1f), 69 | animationSpec = infiniteRepeatable( 70 | animation = tween(1500, easing = easing), 71 | repeatMode = RepeatMode.Restart 72 | ) 73 | ) 74 | 75 | Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 76 | Canvas( 77 | modifier = Modifier 78 | .padding(top = 16.dp) 79 | .size(100.dp) 80 | 81 | ) { 82 | drawCircle( 83 | color = Color.White, 84 | ) 85 | drawCircle( 86 | color = color2, 87 | radius = 80f + scale * 4f, 88 | center = Offset(-offsetX + this.center.x, this.center.y) 89 | ) 90 | drawCircle( 91 | color = color, 92 | radius = 80f + scale * 4f, 93 | center = Offset(offsetX + this.center.x, this.center.y) 94 | ) 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/ClockLoading.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.* 4 | import androidx.compose.foundation.Canvas 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.border 7 | import androidx.compose.foundation.layout.Box 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.foundation.layout.size 10 | import androidx.compose.foundation.shape.CircleShape 11 | import androidx.compose.material.Surface 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.runtime.getValue 14 | import androidx.compose.ui.Alignment 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.geometry.Offset 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.graphics.StrokeCap 19 | import androidx.compose.ui.graphics.drawscope.withTransform 20 | import androidx.compose.ui.tooling.preview.Preview 21 | import androidx.compose.ui.unit.Dp 22 | import androidx.compose.ui.unit.dp 23 | import com.canopas.composeanimations.ui.theme.ThemeColor 24 | 25 | @Preview 26 | @Composable 27 | fun PreviewClockLoading() { 28 | Surface( 29 | modifier = Modifier 30 | .fillMaxSize(), 31 | color = ThemeColor 32 | ) { 33 | ClockLoading() 34 | } 35 | } 36 | 37 | @Composable 38 | fun ClockLoading() { 39 | 40 | val infiniteTransition = rememberInfiniteTransition() 41 | 42 | val minHeightWidth: Dp = 80.dp 43 | 44 | val progressRotation by infiniteTransition.animateFloat( 45 | initialValue = 0F, 46 | targetValue = 1F, 47 | animationSpec = infiniteRepeatable( 48 | animation = tween(1500, easing = LinearEasing) 49 | ) 50 | ) 51 | 52 | val hourRotation by infiniteTransition.animateFloat( 53 | initialValue = 0F, 54 | targetValue = 1F, 55 | animationSpec = infiniteRepeatable( 56 | animation = tween(10000, easing = LinearEasing) 57 | ) 58 | ) 59 | 60 | Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 61 | Canvas( 62 | modifier = Modifier 63 | .size(150.dp) 64 | .border(2.dp, color = Color.Black, shape = CircleShape) 65 | .background(Color.White, shape = CircleShape) 66 | ) { 67 | val middle = Offset(size.minDimension / 2, size.minDimension / 2) 68 | withTransform( 69 | { 70 | rotate(360f * progressRotation, middle) 71 | }, { 72 | drawLine( 73 | strokeWidth = 6.dp.toPx(), 74 | cap = StrokeCap.Round, 75 | color = ThemeColor, 76 | start = middle, 77 | end = Offset( 78 | size.minDimension / 2, 79 | (minHeightWidth / 2 - 20.dp).toPx() 80 | ) 81 | ) 82 | } 83 | ) 84 | withTransform( 85 | { 86 | rotate(360f * hourRotation, middle) 87 | }, { 88 | drawLine( 89 | strokeWidth = 6.dp.toPx(), 90 | cap = StrokeCap.Round, 91 | color = Color.Black, 92 | start = middle, 93 | end = Offset( 94 | size.minDimension / 2, 95 | (minHeightWidth / 2 - 12.dp).toPx() 96 | ) 97 | ) 98 | } 99 | ) 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/HeartAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 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.Icon 8 | import androidx.compose.material.Surface 9 | import androidx.compose.material.icons.Icons 10 | import androidx.compose.material.icons.filled.Favorite 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.getValue 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.graphics.graphicsLayer 17 | import androidx.compose.ui.platform.LocalDensity 18 | import androidx.compose.ui.tooling.preview.Preview 19 | import androidx.compose.ui.unit.dp 20 | import com.canopas.composeanimations.ui.theme.ThemeColor 21 | 22 | @Preview 23 | @Composable 24 | fun PreviewHeartAnimation() { 25 | Surface( 26 | modifier = Modifier 27 | .fillMaxSize(), 28 | color = ThemeColor 29 | ) { 30 | HeartAnimation() 31 | } 32 | } 33 | 34 | @Composable 35 | fun HeartAnimation() { 36 | 37 | val infiniteTransition = rememberInfiniteTransition() 38 | val dy by infiniteTransition.animateFloat( 39 | initialValue = 0f, 40 | targetValue = 1f, 41 | animationSpec = infiniteRepeatable( 42 | animation = tween(1000, easing = LinearEasing), 43 | repeatMode = RepeatMode.Reverse 44 | ) 45 | ) 46 | 47 | val travelDistance = with(LocalDensity.current) { 30.dp.toPx() } 48 | 49 | Column( 50 | modifier = Modifier 51 | .width(200.dp), 52 | horizontalAlignment = Alignment.CenterHorizontally, 53 | verticalArrangement = Arrangement.Center 54 | ) { 55 | Icon( 56 | imageVector = Icons.Filled.Favorite, 57 | "", 58 | tint = Color.White, 59 | modifier = Modifier 60 | .size(100.dp) 61 | .align(Alignment.CenterHorizontally) 62 | .graphicsLayer { 63 | translationY = dy * travelDistance 64 | }, 65 | ) 66 | 67 | Spacer(modifier = Modifier.height(30.dp)) 68 | 69 | Box( 70 | modifier = Modifier 71 | .width(40.dp) 72 | .height(10.dp) 73 | .align(Alignment.CenterHorizontally) 74 | .graphicsLayer { 75 | scaleX = 0.5f + dy / 2 76 | alpha = 0.3f + dy / 2 77 | } 78 | ) { 79 | Box( 80 | modifier = Modifier 81 | .fillMaxSize() 82 | .background(color = Color.White, shape = CircleShape) 83 | ) 84 | } 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/PacmanAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.* 4 | import androidx.compose.foundation.Canvas 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.foundation.layout.size 9 | import androidx.compose.material.Surface 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.runtime.getValue 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.geometry.Offset 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import com.canopas.composeanimations.ui.theme.ThemeColor 19 | 20 | @Preview 21 | @Composable 22 | fun PreviewPacmanAnimation() { 23 | Surface( 24 | modifier = Modifier 25 | .fillMaxSize(), 26 | color = ThemeColor 27 | ) { 28 | PacmanAnimation() 29 | } 30 | } 31 | 32 | @Composable 33 | fun PacmanAnimation() { 34 | val infiniteTransition = rememberInfiniteTransition() 35 | 36 | val mouthAnimation by infiniteTransition.animateFloat( 37 | initialValue = 360F, 38 | targetValue = 280F, 39 | animationSpec = infiniteRepeatable( 40 | animation = tween(800, easing = FastOutSlowInEasing), 41 | repeatMode = RepeatMode.Restart 42 | ) 43 | ) 44 | 45 | val antiMouthAnimation by infiniteTransition.animateFloat( 46 | initialValue = 0F, 47 | targetValue = 40F, 48 | animationSpec = infiniteRepeatable( 49 | animation = tween(800, easing = FastOutSlowInEasing), 50 | repeatMode = RepeatMode.Restart 51 | ) 52 | ) 53 | 54 | Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 55 | Canvas( 56 | modifier = Modifier 57 | .padding(top = 16.dp) 58 | .size(100.dp) 59 | 60 | ) { 61 | drawArc( 62 | color = Color.White, 63 | startAngle = antiMouthAnimation, 64 | sweepAngle = mouthAnimation, 65 | useCenter = true, 66 | ) 67 | 68 | drawCircle( 69 | color = Color.Black, 70 | radius = 15f, 71 | center = Offset(x = this.center.x + 15f, y = this.center.y - 85f) 72 | ) 73 | } 74 | 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/ProgressAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 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.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.LaunchedEffect 10 | import androidx.compose.runtime.remember 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.graphics.Color 14 | import androidx.compose.ui.graphics.graphicsLayer 15 | import androidx.compose.ui.platform.LocalDensity 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import com.canopas.composeanimations.ui.theme.ThemeColor 19 | import kotlinx.coroutines.delay 20 | 21 | @Preview 22 | @Composable 23 | fun PreviewWaProgressAnimation() { 24 | Surface( 25 | modifier = Modifier 26 | .fillMaxSize(), 27 | color = ThemeColor 28 | ) { 29 | ProgressAnimation() 30 | } 31 | } 32 | 33 | @Composable 34 | fun ProgressAnimation() { 35 | 36 | val dots = listOf( 37 | remember { Animatable(0f) }, 38 | remember { Animatable(0f) }, 39 | remember { Animatable(0f) }, 40 | ) 41 | 42 | val animationSpec = infiniteRepeatable( 43 | animation = tween(4000, easing = FastOutLinearInEasing), 44 | repeatMode = RepeatMode.Restart, 45 | ) 46 | 47 | dots.forEachIndexed { index, animatable -> 48 | LaunchedEffect(animatable) { 49 | delay(index * 100L) 50 | animatable.animateTo( 51 | targetValue = 1f, animationSpec = infiniteRepeatable( 52 | animation = keyframes { 53 | durationMillis = 2000 54 | 0.0f at 0 with LinearOutSlowInEasing // for 0-15 ms 55 | 1.0f at 200 with LinearOutSlowInEasing // for 15-75 ms 56 | 0.0f at 400 with LinearOutSlowInEasing // for 0-15 ms 57 | 0.0f at 2000 58 | }, 59 | repeatMode = RepeatMode.Restart, 60 | ) 61 | ) 62 | } 63 | } 64 | 65 | val dys = dots.map { it.value } 66 | 67 | val travelDistance = with(LocalDensity.current) { 15.dp.toPx() } 68 | 69 | Row( 70 | modifier = Modifier.fillMaxSize(), 71 | verticalAlignment = Alignment.CenterVertically, 72 | horizontalArrangement = Arrangement.Center 73 | ) { 74 | dys.forEachIndexed { index, dy -> 75 | Box( 76 | Modifier 77 | .size(25.dp) 78 | .graphicsLayer { 79 | translationY = -dy * travelDistance 80 | }, 81 | ) { 82 | Box( 83 | Modifier 84 | .fillMaxSize() 85 | .background(color = Color.White, shape = CircleShape) 86 | ) 87 | } 88 | 89 | if (index != dys.size - 1) { 90 | Spacer(modifier = Modifier.width(10.dp)) 91 | } 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/RotateDotAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.* 4 | import androidx.compose.foundation.Canvas 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.getValue 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.geometry.Offset 13 | import androidx.compose.ui.graphics.Color 14 | import androidx.compose.ui.graphics.drawscope.Stroke 15 | import androidx.compose.ui.tooling.preview.Preview 16 | import com.canopas.composeanimations.ui.theme.ThemeColor 17 | import kotlin.math.cos 18 | import kotlin.math.sin 19 | 20 | @Preview 21 | @Composable 22 | fun PreviewRotateDotAnimation() { 23 | Surface( 24 | modifier = Modifier 25 | .fillMaxSize(), 26 | color = ThemeColor 27 | ) { 28 | RotateDotAnimation() 29 | } 30 | } 31 | 32 | @Composable 33 | fun RotateDotAnimation() { 34 | val infiniteTransition = rememberInfiniteTransition() 35 | 36 | val rotation by infiniteTransition.animateFloat( 37 | initialValue = 0F, 38 | targetValue = 360F, 39 | animationSpec = infiniteRepeatable( 40 | animation = tween(1400, easing = FastOutSlowInEasing), 41 | ) 42 | ) 43 | 44 | Box( 45 | modifier = Modifier.fillMaxSize(), 46 | contentAlignment = Alignment.Center 47 | ) { 48 | 49 | Canvas(modifier = Modifier) { 50 | 51 | drawCircle( 52 | Color.White.copy(.6f), center = center, 53 | radius = 150f, 54 | style = Stroke(width = 10f) 55 | ) 56 | 57 | val x = (center.x + cos(Math.toRadians(rotation.toDouble())) * 120f).toFloat() 58 | val y = (center.y + sin(Math.toRadians(rotation.toDouble())) * 120f).toFloat() 59 | 60 | drawCircle( 61 | Color.White, center = Offset(x, y), 62 | radius = 20f 63 | ) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/RotateTwoDotsAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.* 4 | import androidx.compose.foundation.Canvas 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.getValue 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.geometry.Offset 13 | import androidx.compose.ui.graphics.Color 14 | import androidx.compose.ui.graphics.drawscope.scale 15 | import androidx.compose.ui.graphics.drawscope.withTransform 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import com.canopas.composeanimations.ui.theme.ThemeColor 18 | import kotlin.math.cos 19 | import kotlin.math.sin 20 | 21 | 22 | @Preview 23 | @Composable 24 | fun PreviewRotateTwoDotsAnimation() { 25 | Surface( 26 | modifier = Modifier 27 | .fillMaxSize(), 28 | color = ThemeColor 29 | ) { 30 | RotateTwoDotsAnimation() 31 | } 32 | } 33 | 34 | @Composable 35 | fun RotateTwoDotsAnimation() { 36 | val infiniteTransition = rememberInfiniteTransition() 37 | 38 | val animValue by infiniteTransition.animateFloat( 39 | initialValue = .2f, 40 | targetValue = .8f, 41 | animationSpec = infiniteRepeatable( 42 | animation = tween(1500, easing = FastOutSlowInEasing), 43 | repeatMode = RepeatMode.Reverse 44 | ) 45 | ) 46 | 47 | val animValue2 by infiniteTransition.animateFloat( 48 | initialValue = .2f, 49 | targetValue = 1f, 50 | animationSpec = infiniteRepeatable( 51 | animation = tween(1500, easing = FastOutSlowInEasing), 52 | repeatMode = RepeatMode.Reverse 53 | ) 54 | ) 55 | val rotation by infiniteTransition.animateFloat( 56 | initialValue = 360F, 57 | targetValue = 0F, 58 | animationSpec = infiniteRepeatable( 59 | animation = tween(1500, easing = FastOutSlowInEasing), 60 | repeatMode = RepeatMode.Reverse 61 | ) 62 | ) 63 | 64 | Box( 65 | modifier = Modifier.fillMaxSize(), 66 | contentAlignment = Alignment.Center 67 | ) { 68 | 69 | Canvas(modifier = Modifier) { 70 | withTransform({ 71 | scale(animValue) 72 | }, { 73 | drawCircle( 74 | Color.White, center = center, 75 | alpha = animValue, 76 | radius = 50f 77 | ) 78 | 79 | }) 80 | 81 | val x = (center.x + cos(Math.toRadians(rotation.toDouble())) * 140f).toFloat() 82 | val y = (center.y + sin(Math.toRadians(rotation.toDouble())) * 140f).toFloat() 83 | 84 | withTransform({ 85 | scale(animValue2) 86 | }, { 87 | drawCircle( 88 | Color.White, alpha = animValue2, center = Offset(x, y), 89 | radius = 50f 90 | ) 91 | }) 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/RotatingCircle.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.LinearEasing 4 | import androidx.compose.animation.core.LinearOutSlowInEasing 5 | import androidx.compose.animation.core.animate 6 | import androidx.compose.animation.core.tween 7 | import androidx.compose.foundation.background 8 | import androidx.compose.foundation.layout.Box 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.size 11 | import androidx.compose.foundation.shape.CircleShape 12 | import androidx.compose.material.Surface 13 | import androidx.compose.runtime.* 14 | import androidx.compose.ui.Alignment 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.graphics.Color 17 | import androidx.compose.ui.graphics.graphicsLayer 18 | import androidx.compose.ui.tooling.preview.Preview 19 | import androidx.compose.ui.unit.dp 20 | import com.canopas.composeanimations.ui.theme.ThemeColor 21 | 22 | @Preview 23 | @Composable 24 | fun PreviewRotatingCircle() { 25 | Surface( 26 | modifier = Modifier 27 | .fillMaxSize(), 28 | color = ThemeColor 29 | ) { 30 | RotatingCircle() 31 | } 32 | } 33 | 34 | 35 | @Composable 36 | fun RotatingCircle() { 37 | 38 | var xRotation by remember { 39 | mutableStateOf(0f) 40 | } 41 | var yRotation by remember { 42 | mutableStateOf(0f) 43 | } 44 | 45 | LaunchedEffect(key1 = Unit, block = { 46 | while (true) { 47 | animate( 48 | 0f, 49 | 180f, 50 | animationSpec = tween(800, easing = LinearOutSlowInEasing), 51 | block = { value, _ -> xRotation = value } 52 | ) 53 | animate( 54 | 0f, 55 | 180f, 56 | animationSpec = tween(600, easing = LinearEasing), 57 | block = { value, _ -> yRotation = value } 58 | ) 59 | } 60 | }) 61 | 62 | Box( 63 | modifier = Modifier.fillMaxSize(), 64 | contentAlignment = Alignment.Center 65 | ) { 66 | Box( 67 | modifier = Modifier 68 | .size(100.dp) 69 | .graphicsLayer { 70 | rotationX = xRotation 71 | rotationY = yRotation 72 | } 73 | .background(Color.White, CircleShape) 74 | ) 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/RotatingSquare.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.LinearEasing 4 | import androidx.compose.animation.core.animate 5 | import androidx.compose.animation.core.tween 6 | import androidx.compose.foundation.background 7 | import androidx.compose.foundation.layout.Box 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.foundation.layout.size 10 | import androidx.compose.material.Surface 11 | import androidx.compose.runtime.* 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.graphics.graphicsLayer 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import com.canopas.composeanimations.ui.theme.ThemeColor 19 | 20 | @Preview 21 | @Composable 22 | fun PreviewRotatingSquare() { 23 | Surface( 24 | modifier = Modifier 25 | .fillMaxSize(), 26 | color = ThemeColor 27 | ) { 28 | RotatingSquare() 29 | } 30 | } 31 | 32 | @Composable 33 | fun RotatingSquare() { 34 | 35 | var xRotation by remember { 36 | mutableStateOf(0f) 37 | } 38 | var yRotation by remember { 39 | mutableStateOf(0f) 40 | } 41 | 42 | val animationSpec = tween(1000, easing = LinearEasing) 43 | 44 | LaunchedEffect(key1 = Unit, block = { 45 | while (true) { 46 | animate( 47 | 0f, 48 | 180f, 49 | animationSpec = animationSpec, 50 | block = { value, _ -> xRotation = value } 51 | ) 52 | animate( 53 | 0f, 54 | 180f, 55 | animationSpec = animationSpec, 56 | block = { value, _ -> yRotation = value } 57 | ) 58 | } 59 | }) 60 | 61 | Box( 62 | modifier = Modifier.fillMaxSize(), 63 | contentAlignment = Alignment.Center 64 | ) { 65 | Box( 66 | modifier = Modifier 67 | .size(100.dp) 68 | .graphicsLayer { 69 | rotationX = xRotation 70 | rotationY = yRotation 71 | } 72 | .background(Color.White) 73 | ) 74 | } 75 | 76 | } 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/SquareFillLoaderAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | import androidx.compose.animation.core.LinearEasing 4 | import androidx.compose.animation.core.animate 5 | import androidx.compose.animation.core.rememberInfiniteTransition 6 | import androidx.compose.animation.core.tween 7 | import androidx.compose.foundation.Canvas 8 | import androidx.compose.foundation.layout.Box 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.wrapContentSize 11 | import androidx.compose.material.Surface 12 | import androidx.compose.runtime.* 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.geometry.Offset 16 | import androidx.compose.ui.geometry.Size 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.graphics.drawscope.Stroke 19 | import androidx.compose.ui.graphics.drawscope.rotate 20 | import androidx.compose.ui.tooling.preview.Preview 21 | import com.canopas.composeanimations.ui.theme.ThemeColor 22 | 23 | @Preview 24 | @Composable 25 | fun previewSquareFillLoaderAnimation() { 26 | Surface( 27 | modifier = Modifier 28 | .fillMaxSize(), 29 | color = ThemeColor 30 | ) { 31 | SquareFillLoaderAnimation() 32 | } 33 | } 34 | 35 | @Composable 36 | fun SquareFillLoaderAnimation() { 37 | 38 | val infiniteTransition = rememberInfiniteTransition() 39 | 40 | var rotation by remember { 41 | mutableStateOf(0f) 42 | } 43 | var height by remember { 44 | mutableStateOf(0f) 45 | } 46 | 47 | LaunchedEffect(key1 = Unit, block = { 48 | while (true) { 49 | animate( 50 | 0f, 51 | 180f, 52 | animationSpec = tween(500, easing = LinearEasing), 53 | block = { value, _ -> rotation = value } 54 | ) 55 | animate( 56 | 400f, 0f, 57 | animationSpec = tween(1000, easing = LinearEasing), 58 | block = { value, _ -> height = value } 59 | ) 60 | } 61 | }) 62 | 63 | Box( 64 | modifier = Modifier.fillMaxSize(), 65 | contentAlignment = Alignment.Center 66 | ) { 67 | 68 | Canvas(modifier = Modifier.wrapContentSize()) { 69 | val topLeft = Offset(this.center.x - 200f, this.center.y - 200f) 70 | rotate(degrees = rotation) { 71 | drawRect( 72 | Color.White, topLeft, size = Size(400f, 400f), 73 | style = Stroke(width = 20f) 74 | ) 75 | } 76 | 77 | drawRect( 78 | Color.White, topLeft, size = Size(400f, height) 79 | ) 80 | 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/ThreeBounceAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 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.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.LaunchedEffect 10 | import androidx.compose.runtime.remember 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.scale 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import com.canopas.composeanimations.ui.theme.ThemeColor 19 | import kotlinx.coroutines.delay 20 | 21 | 22 | @Preview 23 | @Composable 24 | fun PreviewThreeBounceAnimation() { 25 | Surface( 26 | modifier = Modifier 27 | .fillMaxSize(), 28 | color = ThemeColor 29 | ) { 30 | ThreeBounceAnimation() 31 | } 32 | } 33 | 34 | @Composable 35 | fun ThreeBounceAnimation() { 36 | 37 | val dots = listOf( 38 | remember { Animatable(0.2f) }, 39 | remember { Animatable(0.2f) }, 40 | remember { Animatable(0.2f) }, 41 | ) 42 | 43 | dots.forEachIndexed { index, animatable -> 44 | LaunchedEffect(animatable) { 45 | delay(index * 200L) 46 | animatable.animateTo( 47 | targetValue = 1f, animationSpec = infiniteRepeatable( 48 | animation = tween(600, easing = FastOutLinearInEasing), 49 | repeatMode = RepeatMode.Reverse, 50 | ) 51 | ) 52 | } 53 | } 54 | 55 | val dys = dots.map { it.value } 56 | 57 | Row( 58 | modifier = Modifier.fillMaxSize(), 59 | verticalAlignment = Alignment.CenterVertically, 60 | horizontalArrangement = Arrangement.Center 61 | ) { 62 | dys.forEachIndexed { index, dy -> 63 | 64 | Box( 65 | Modifier 66 | .size(30.dp) 67 | .scale(dy) 68 | .alpha(dy) 69 | .background(color = Color.White, shape = CircleShape) 70 | ) 71 | 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/TwinCircleAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 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.Surface 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.getValue 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.draw.clip 13 | import androidx.compose.ui.draw.scale 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.tooling.preview.Preview 16 | import androidx.compose.ui.unit.dp 17 | import com.canopas.composeanimations.ui.theme.ThemeColor 18 | 19 | @Preview 20 | @Composable 21 | fun PreviewTwinCircleAnimation() { 22 | Surface( 23 | modifier = Modifier 24 | .fillMaxSize(), 25 | color = ThemeColor 26 | ) { 27 | TwinCircleAnimation() 28 | } 29 | } 30 | 31 | @Composable 32 | fun TwinCircleAnimation() { 33 | val infiniteTransition = rememberInfiniteTransition() 34 | 35 | val twinCircleAnimation by infiniteTransition.animateFloat( 36 | initialValue = 1f, 37 | targetValue = 7f, 38 | animationSpec = infiniteRepeatable( 39 | animation = tween(1500, easing = FastOutSlowInEasing), 40 | repeatMode = RepeatMode.Reverse 41 | ) 42 | ) 43 | Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 44 | Row( 45 | modifier = Modifier 46 | .size(120.dp) 47 | .padding(12.dp) 48 | .clip(CircleShape) 49 | .background(Color.Red), 50 | horizontalArrangement = Arrangement.Center, 51 | verticalAlignment = Alignment.CenterVertically 52 | ) { 53 | 54 | Box( 55 | modifier = Modifier 56 | .size(15.dp) 57 | .scale(twinCircleAnimation) 58 | .clip(CircleShape) 59 | .background(Color.White) 60 | ) 61 | 62 | Spacer(modifier = Modifier.width(6.dp)) 63 | 64 | Box( 65 | modifier = Modifier 66 | .size(15.dp) 67 | .scale(twinCircleAnimation) 68 | .clip(CircleShape) 69 | .background(Color.White) 70 | ) 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/animations/WavesAnimation.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.animations 2 | 3 | 4 | import androidx.compose.animation.core.* 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.Box 7 | import androidx.compose.foundation.layout.fillMaxSize 8 | import androidx.compose.foundation.layout.size 9 | import androidx.compose.foundation.shape.CircleShape 10 | import androidx.compose.material.Icon 11 | import androidx.compose.material.Surface 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.runtime.LaunchedEffect 14 | import androidx.compose.runtime.remember 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.Alignment.Companion.Center 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.graphics.Color 19 | import androidx.compose.ui.graphics.graphicsLayer 20 | import androidx.compose.ui.res.painterResource 21 | import androidx.compose.ui.tooling.preview.Preview 22 | import androidx.compose.ui.unit.dp 23 | import com.canopas.composeanimations.R 24 | import com.canopas.composeanimations.ui.theme.ThemeColor 25 | import kotlinx.coroutines.delay 26 | 27 | @Preview 28 | @Composable 29 | fun PreviewWaveAnimation() { 30 | Surface( 31 | modifier = Modifier 32 | .fillMaxSize(), 33 | color = ThemeColor 34 | ) { 35 | WavesAnimation() 36 | } 37 | } 38 | 39 | @Composable 40 | fun WavesAnimation() { 41 | 42 | val waves = listOf( 43 | remember { Animatable(0f) }, 44 | remember { Animatable(0f) }, 45 | remember { Animatable(0f) }, 46 | remember { Animatable(0f) }, 47 | ) 48 | 49 | val animationSpec = infiniteRepeatable( 50 | animation = tween(4000, easing = FastOutLinearInEasing), 51 | repeatMode = RepeatMode.Restart, 52 | ) 53 | 54 | waves.forEachIndexed { index, animatable -> 55 | LaunchedEffect(animatable) { 56 | delay(index * 1000L) 57 | animatable.animateTo( 58 | targetValue = 1f, animationSpec = animationSpec 59 | ) 60 | } 61 | } 62 | 63 | val dys = waves.map { it.value } 64 | 65 | Box( 66 | modifier = Modifier.fillMaxSize(), 67 | contentAlignment = Center 68 | ) { 69 | // Waves 70 | dys.forEach { dy -> 71 | Box( 72 | Modifier 73 | .size(50.dp) 74 | .align(Alignment.Center) 75 | .graphicsLayer { 76 | scaleX = dy * 4 + 1 77 | scaleY = dy * 4 + 1 78 | alpha = 1 - dy 79 | }, 80 | ) { 81 | Box( 82 | Modifier 83 | .fillMaxSize() 84 | .background(color = Color.White, shape = CircleShape) 85 | ) 86 | } 87 | } 88 | 89 | // Mic icon 90 | Box( 91 | Modifier 92 | .size(50.dp) 93 | .align(Alignment.Center) 94 | .background(color = Color.White, shape = CircleShape) 95 | ) { 96 | Icon( 97 | painter = painterResource(id = R.drawable.ic_baseline_mic_24), 98 | "", 99 | tint = Color.Black, 100 | modifier = Modifier 101 | .size(32.dp) 102 | .align(Alignment.Center) 103 | ) 104 | } 105 | 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Teal200 = Color(0xFF03DAC5) 6 | val ThemeColor = Color(0xFFFF7373) -------------------------------------------------------------------------------- /app/src/main/java/com/canopas/composeanimations/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.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/canopas/composeanimations/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.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 = ThemeColor, 11 | primaryVariant = ThemeColor, 12 | secondary = Teal200 13 | ) 14 | 15 | private val LightColorPalette = lightColors( 16 | primary = ThemeColor, 17 | primaryVariant = ThemeColor, 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 ComposeAnimationsTheme( 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/canopas/composeanimations/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.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/java/com/canopas/composeanimations/utils/animateValues.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations.utils 2 | 3 | import androidx.compose.animation.core.AnimationSpec 4 | import androidx.compose.animation.core.animate 5 | import androidx.compose.animation.core.spring 6 | import androidx.compose.runtime.* 7 | 8 | @Composable 9 | fun animateValues( 10 | values: List, 11 | animationSpec: AnimationSpec = spring(), 12 | ): State { 13 | 14 | // 1. Create the groups zipping with next entry 15 | val groups by rememberUpdatedState(newValue = values.zipWithNext()) 16 | // 2. Start the state with the first value 17 | val state = remember { mutableStateOf(values.first()) } 18 | 19 | LaunchedEffect(key1 = groups) { 20 | val (_, setValue) = state 21 | // Start the animation from 0 to groups quantity 22 | animate( 23 | initialValue = 0f, 24 | targetValue = groups.size.toFloat(), 25 | animationSpec = animationSpec, 26 | ) { frame, _ -> 27 | // Get which group is being evaluated 28 | val integerPart = frame.toInt() 29 | val (initialValue, finalValue) = groups[frame.toInt()] 30 | // Get the current "position" from the group animation 31 | val decimalPart = frame - integerPart 32 | // Calculate the progress between the initial and final value 33 | setValue( 34 | initialValue + (finalValue - initialValue) * decimalPart 35 | ) 36 | } 37 | } 38 | return state 39 | } -------------------------------------------------------------------------------- /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/ic_baseline_mic_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /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/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/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/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 | #FFFF7373 9 | #FF000000 10 | #FFFFFFFF 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Compose Animations 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/test/java/com/canopas/composeanimations/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.canopas.composeanimations 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.0.1' 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.1.1' apply false 8 | id 'com.android.library' version '7.1.1' apply false 9 | id 'org.jetbrains.kotlin.android' version '1.5.21' apply false 10 | } 11 | 12 | task clean(type: Delete) { 13 | delete rootProject.buildDir 14 | } -------------------------------------------------------------------------------- /gif/RotateDotTwo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/RotateDotTwo.gif -------------------------------------------------------------------------------- /gif/arcRotation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/arcRotation.gif -------------------------------------------------------------------------------- /gif/circleOffset.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/circleOffset.gif -------------------------------------------------------------------------------- /gif/clockAnim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/clockAnim.gif -------------------------------------------------------------------------------- /gif/heartAnim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/heartAnim.gif -------------------------------------------------------------------------------- /gif/pacman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/pacman.gif -------------------------------------------------------------------------------- /gif/progress_animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/progress_animation.gif -------------------------------------------------------------------------------- /gif/rotateDot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/rotateDot.gif -------------------------------------------------------------------------------- /gif/rotatinCircle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/rotatinCircle.gif -------------------------------------------------------------------------------- /gif/rotatingSquare.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/rotatingSquare.gif -------------------------------------------------------------------------------- /gif/sqaure_fill_loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/sqaure_fill_loader.gif -------------------------------------------------------------------------------- /gif/stepperAnim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/stepperAnim.gif -------------------------------------------------------------------------------- /gif/three_bounce_anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/three_bounce_anim.gif -------------------------------------------------------------------------------- /gif/twinCircle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/twinCircle.gif -------------------------------------------------------------------------------- /gif/waveAnim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gif/waveAnim.gif -------------------------------------------------------------------------------- /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/canopas/compose-animations-examples/67da54a12ef3a341701f287930d7743a0aae4add/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jan 22 20:12:26 IST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-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 = "Compose Animations" 16 | include ':app' 17 | --------------------------------------------------------------------------------