Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#6 add animation and theme #12

Open
wants to merge 9 commits into
base: #1_composable_function_info
Choose a base branch
from
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# 💫 Animations in Jetpack Compose 💫

Navigation transition animations without accompanist library.

# You will learn:
- Visibility animation
- Content Animation
- Composable State Animation
- Infinite Animation
- Navigation Animation
- Navigation in Jetpack Compose

# Video

https://github.com/KaushalVasava/JetPackCompose_Basic/assets/49050597/ed4ca42d-4e59-429a-a575-88eda2d259d9

# Author
Kaushal Vasava.
28 changes: 15 additions & 13 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ plugins {
}

android {
namespace 'com.lahsuak.apps.jetpackcomposebasic'
compileSdk 33
namespace "com.lahsuak.apps.jetpackcomposebasic"
compileSdk 34

defaultConfig {
applicationId "com.lahsuak.apps.jetpackcomposebasic"
minSdk 23
targetSdk 33
targetSdk 34
versionCode 1
versionName "1.0"

Expand All @@ -27,17 +27,17 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.1.1'
kotlinCompilerExtensionVersion '1.4.5'
}
packagingOptions {
resources {
Expand All @@ -48,16 +48,18 @@ android {

dependencies {

implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation 'androidx.activity:activity-compose:1.6.1'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
implementation 'androidx.activity:activity-compose:1.7.2'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.compose.material3:material3:1.1.0-alpha03'
implementation 'androidx.compose.material3:material3:1.1.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"

implementation "androidx.navigation:navigation-compose:2.7.2"
}
160 changes: 141 additions & 19 deletions app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,50 +1,172 @@
package com.lahsuak.apps.jetpackcomposebasic

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.spring
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.rememberNavController
import com.lahsuak.apps.jetpackcomposebasic.model.AnimationItem
import com.lahsuak.apps.jetpackcomposebasic.ui.navigation.navhost.AppNavHost
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.ImageBorderAnimation
import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetPackComposeBasicTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
JetPackComposeBasicTheme(dynamicColor = false) {
AppNavHost(navController = rememberNavController())
}
}
}
}
/***
Composable functions :
A composable function is a regular function annotated with @Composable.
This enables your function to call other @Composable functions within it.
You can see how the Greeting function is marked as @Composable.
This function will produce a piece of UI hierarchy displaying the given input,
String. Text is a composable function provided by the library.
***/

@Composable
fun MyApp(modifier: Modifier = Modifier) {
/** PERSISTENT STATE
* Instead of using remember you can use rememberSaveable.
This will save each state surviving configuration changes (such as rotations) and process death.
**/
var shouldShowOnboarding by rememberSaveable { mutableStateOf(true) }

Surface(modifier) {
if (shouldShowOnboarding) {
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
} else {
Greetings()
}
}
}

@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
var expanded by rememberSaveable { mutableStateOf(false) }

val extraPadding by animateDpAsState(
if (expanded) 48.dp else 0.dp,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
), label = "Greeting"
)
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(
modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding.coerceAtLeast(0.dp))
) {
Text(text = "Hello,")
Text(
text = name, style = MaterialTheme.typography.headlineMedium.copy(
fontWeight = FontWeight.ExtraBold
)
)
}
ElevatedButton(
onClick = { expanded = !expanded }
) {
Text(if (expanded) "Show less" else "Show more")
}
}
}
}

@Preview(showBackground = true)
@Composable
private fun Greetings(
modifier: Modifier = Modifier,
names: List<String> = List(1000) { "item $it" },
) {
LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
items(items = names) { name ->
Greeting(name = name)
}
}
}

// add new on-boarding screen
@Composable
fun OnboardingScreen(
onContinueClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Welcome to the Basics Codelab!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onContinueClicked
) {
Text("Continue")
}
}
}

@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreview() {
JetPackComposeBasicTheme(dynamicColor = false) {
Greetings()
}
}

@Preview(
showBackground = true,
widthDp = 320,
uiMode = UI_MODE_NIGHT_YES,
name = "Dark"
)
@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreviewDark() {
JetPackComposeBasicTheme(dynamicColor = false) {
Greetings()
}
}

@Preview(showBackground = true, widthDp = 320, heightDp = 320)
@Composable
fun OnboardingPreview() {
JetPackComposeBasicTheme {
OnboardingScreen(onContinueClicked = {})
}
}

@Preview
@Composable
fun MyAppPreview() {
JetPackComposeBasicTheme {
Greeting("Android")
MyApp(Modifier.fillMaxSize())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.lahsuak.apps.jetpackcomposebasic.model

data class AnimationItem(
val name: String,
val navigationRoute: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.lahsuak.apps.jetpackcomposebasic.ui.navigation

enum class Screen {
Home,
AnimateVisibility,
AnimateContent,
AnimateState,
InfiniteAnimation,
ImageBorderAnimation,
}
sealed class NavigationItem(val route: String) {
object Home : NavigationItem(Screen.Home.name)
object AnimateVisibility : NavigationItem(Screen.AnimateVisibility.name)
object AnimateContent : NavigationItem(Screen.AnimateContent.name)
object AnimateState : NavigationItem(Screen.AnimateState.name)
object InfiniteAnimation : NavigationItem(Screen.InfiniteAnimation.name)
object ImageBorderAnimation : NavigationItem(Screen.ImageBorderAnimation.name)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.lahsuak.apps.jetpackcomposebasic.ui.navigation.navhost

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.lahsuak.apps.jetpackcomposebasic.ui.navigation.NavigationItem
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.AnimateContent
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.AnimateStateValue
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.AnimateViewVisibility
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.HomeScreen
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.ImageBorderAnimation
import com.lahsuak.apps.jetpackcomposebasic.ui.screen.RepeatAnimationInfinite

@Composable
fun AppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController,
startDestination: String = NavigationItem.Home.route,
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination,
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
tween(400)
)
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
tween(400)
)
},
popEnterTransition = {
slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right,
animationSpec = tween(400)
)
},
popExitTransition = {
slideOutOfContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right,
animationSpec = tween(400)
)
}
) {
composable(NavigationItem.Home.route) {
HomeScreen(navController)
}
composable(NavigationItem.AnimateState.route) {
AnimateStateValue()
}
composable(NavigationItem.AnimateContent.route) {
AnimateContent()
}
composable(NavigationItem.AnimateVisibility.route) {
AnimateViewVisibility()
}
composable(NavigationItem.InfiniteAnimation.route) {
RepeatAnimationInfinite()
}
composable(NavigationItem.ImageBorderAnimation.route) {
ImageBorderAnimation()
}
}
}
Loading