- Notifications
You must be signed in to change notification settings - Fork2
commandiron/AnimatableCompose
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Add Animatable Material Components in Android Jetpack Compose.
Create jetpack compose animation painless.
What you can create from Material 3 components right now;
- Spacer Animation
- Text Animation
- Box Animation
- Card Animation
- Icon Animation
- LazyRow Animation
- and combinations
| Phone Number | Card Dealer |
|---|---|
![]() | ![]() |
States
//Create components stateval animatableCardState= rememberAnimatableCardState( initialSize=DpSize(80.dp,80.dp), targetSize=DpSize(Dp.Infinity,120.dp), toTargetSizeAnimationSpec= tween(500,500),// specify delay(500) for target initialShape=RoundedCornerShape(32.dp), targetShape=RoundedCornerShape(0.dp), toTargetShapeAnimationSpec= tween(500,500), initialOffset=DpOffset(0.dp,0.dp), targetOffset=DpOffset(0.dp,-Dp.Infinity), toInitialOffsetAnimationSpec= tween(500,500),)val animatableIconState= rememberAnimatableIconState( initialSize=DpSize(40.dp,40.dp), targetSize=DpSize(80.dp,80.dp), toTargetSizeAnimationSpec= tween(500,500), initialOffset=DpOffset(0.dp,0.dp), targetOffset=DpOffset((-50).dp,0.dp), toTargetOffsetAnimationSpec= tween(500,500))val animatableTextState= rememberAnimatableTextState( initialFontSize=0.sp, targetFontSize=26.sp, toTargetFontSizeAnimationSpec= tween(500,500), initialOffset=DpOffset(0.dp,0.dp), targetOffset=DpOffset((-25).dp,0.dp), toTargetOffsetAnimationSpec= tween(500,500))// Create shared stateval sharedAnimatableState= rememberSharedAnimatableState(listOf( animatableCardState, animatableIconState,// default index = 0 animatableIconState.copy(// create state with copy func. for same params index=1,// specify index for same components initialSize=DpSize(0.dp,0.dp), targetSize=DpSize(36.dp,36.dp), targetOffset=DpOffset(40.dp,0.dp), ), animatableTextState,// default index = 0 animatableTextState.copy( index=1,// specify index for same components targetFontSize=12.sp ) ))
Components
AnimatableCard( onClick= { sharedAnimatableState.animate() }, state= sharedAnimatableState// pass shared state) {Row( modifier=Modifier.fillMaxSize(), verticalAlignment=Alignment.CenterVertically, horizontalArrangement=Arrangement.Center ) {AnimatableIcon( imageVector=Icons.Default.Person, contentDescription=null, state= sharedAnimatableState// pass shared state )Column {AnimatableText( text="Emir Demirli", state= sharedAnimatableState// pass shared state )AnimatableText( text="+90 0535 508 55 52", state= sharedAnimatableState,// pass shared state stateIndex=1// specify index for same components ) }AnimatableIcon( imageVector=Icons.Default.Phone, contentDescription=null, state= sharedAnimatableState,// pass shared state stateIndex=1// specify index for same components ) }}
States
val cards by remember { mutableStateOf(listOf("A","K","Q","J","10","9","8","7","6","5","4","3","2"))}var deck by remember { mutableStateOf(cards+ cards+ cards+ cards)}val animatableCardState= rememberAnimatableCardState( initialSize=DpSize(64.dp,64.dp), targetSize=DpSize(64.dp,64.dp), initialOffset=DpOffset(0.dp,120.dp), targetOffset=DpOffset(-Dp.Infinity,-Dp.Infinity))val animatableTextState= rememberAnimatableTextState( initialFontSize=0.sp, targetFontSize=24.sp)val cardStates= mutableListOf<AnimatableState>()val textStates= mutableListOf<AnimatableState>()deck.indices.forEach { cardStates.add( animatableCardState.copy( index= it, toTargetOffsetAnimationSpec= tween(400, (it*400)), targetOffset=DpOffset(if(it%2==0) (-100).dpelse100.dp, (-150).dp) ) ) textStates.add( animatableTextState.copy( index= it, toTargetFontSizeAnimationSpec= tween(400, (it*400)) ) )}val sharedAnimatableState= rememberSharedAnimatableState(cardStates+ textStates)
Components
Box( modifier=Modifier .fillMaxSize() .clickable { deck= deck.shuffled() sharedAnimatableState.animate() }, contentAlignment=Alignment.Center) { deck.indices.forEach {AnimatableCard( onClick= {}, state= sharedAnimatableState, stateIndex= it, fixedShape=RoundedCornerShape(16.dp) ) {Box(Modifier.fillMaxSize(),Alignment.Center) {AnimatableText( text= deck[it], state= sharedAnimatableState, stateIndex= it ) } } }}
| Insta Story | Info Card |
|---|---|
![]() | ![]() |
States
val lazyListState= rememberLazyListState()val scope= rememberCoroutineScope()var selectedIndex by remember { mutableStateOf(0) }val stories by remember { mutableStateOf(Story.stories) }val animatableCardState= rememberAnimatableCardState( initialSize=DpSize(width=70.dp, height=70.dp), targetSize=DpSize(width=Dp.Infinity, height=Dp.Infinity), initialShape=CircleShape, targetShape=RoundedCornerShape(0.dp), initialPadding=PaddingValues(4.dp,8.dp), targetPadding=PaddingValues(0.dp), initialBorder=BorderStroke(2.dp,Brush.verticalGradient(listOf(Color.Red,Color.Yellow))), targetBorder=BorderStroke(0.dp,Color.Unspecified))val cardStates= mutableListOf<AnimatableState>()stories.indices.forEach { index-> cardStates.add( animatableCardState.copy( index= index, onAnimation= {when(it) {AnimationState.INITIAL-> {}AnimationState.INITIAL_TO_TARGET-> { scope.launch { delay(150) lazyListState.animateScrollToItem(selectedIndex) } }AnimationState.TARGET-> {}AnimationState.TARGET_TO_INITIAL-> {} } }, toTargetAnimationSpec= tween(250) ) )}val sharedAnimatableState= rememberSharedAnimatableState(cardStates)
Components
Box( modifier=Modifier.fillMaxSize(),) {LazyRow( state= lazyListState ) { items(stories.size) { index->AnimatableCard( modifier=Modifier .size(100.dp), onClick= { selectedIndex= index cardStates[index].animate() }, state= sharedAnimatableState, stateIndex= index ) {AsyncImage( model= stories[index].url, contentDescription=null, contentScale=ContentScale.Crop, modifier=Modifier.fillMaxSize() ) } } }}
Data
data classStory(valurl:String) {companionobject {val stories=listOf(// ) }}
States
val lazyListState= rememberLazyListState()val snapperFlingBehavior= rememberSnapperFlingBehavior( lazyListState= lazyListState, snapOffsetForItem=SnapOffsets.Start,)val scope= rememberCoroutineScope()var selectedIndex by remember { mutableStateOf(0) }val animatableCardState= rememberAnimatableCardState( initialSize=DpSize(width=340.dp, height=180.dp), targetSize=DpSize(width=Dp.Infinity, height=340.dp), initialShape=RoundedCornerShape(32.dp), targetShape=RoundedCornerShape(0.dp,0.dp,32.dp,32.dp), toTargetShapeAnimationSpec= tween(750), initialPadding=PaddingValues(horizontal=8.dp), targetPadding=PaddingValues(0.dp), onAnimation= {when(it) {AnimationState.INITIAL-> {}AnimationState.INITIAL_TO_TARGET-> { scope.launch { delay(500) lazyListState.animateScrollToItem(selectedIndex) } }AnimationState.TARGET-> {}AnimationState.TARGET_TO_INITIAL-> {} } })val animatableBoxState= rememberAnimatableBoxState( initialAlignment=Alignment.Center, targetAlignment=Alignment.TopCenter)val animatableTextState= rememberAnimatableTextState( initialFontSize=0.sp, targetFontSize=12.sp, initialOffset=DpOffset(x=0.dp, y=300.dp), targetOffset=DpOffset(x=0.dp, y=0.dp), toTargetAnimationSpec= tween(250))val animatableSpacerState= rememberAnimatableSpacerState( initialSize=DpSize(width=0.dp, height=0.dp), targetSize=DpSize(width=0.dp, height=16.dp))val infoCards by remember { mutableStateOf(InfoCard.infoCards) }val cardStates= mutableListOf<AnimatableState>()val boxStates= mutableListOf<AnimatableState>()val textStates= mutableListOf<AnimatableState>()val spacerStates= mutableListOf<AnimatableState>()infoCards.indices.forEach { index-> cardStates.add( animatableCardState.copy( index= index ) ) boxStates.add( animatableBoxState.copy( index= index ) ) textStates.add( animatableTextState.copy( index= index ) )if(index==0) { spacerStates.add( animatableSpacerState.copy( index= index, initialSize=DpSize(width=0.dp, height=300.dp), targetSize=DpSize(width=0.dp, height=0.dp) ) ) } spacerStates.add( animatableSpacerState.copy( index= index+1, ) )}val sharedAnimatableState= rememberSharedAnimatableState( animatableStates= cardStates+ boxStates+ textStates+ spacerStates)
Components
Column( modifier=Modifier.fillMaxSize(),) {AnimatableSpacer( state= sharedAnimatableState )LazyRow( verticalAlignment=Alignment.CenterVertically, state= lazyListState, flingBehavior= snapperFlingBehavior ) { items(infoCards.size) { index->AnimatableCard( onClick= { selectedIndex= index sharedAnimatableState.animate() }, state= sharedAnimatableState, stateIndex= index, colors=CardDefaults.cardColors( containerColor=Color(0xFFE9E7FE) ) ) {Row( modifier=Modifier.fillMaxSize(), verticalAlignment=Alignment.CenterVertically, horizontalArrangement=Arrangement.SpaceBetween ) {AnimatableBox( modifier=Modifier .weight(1f) .fillMaxHeight() .padding(16.dp), stateIndex= index, state= sharedAnimatableState ) {LazyColumn(horizontalAlignment=Alignment.CenterHorizontally) { item {Text( text= infoCards[index].title, fontSize=22.sp, fontWeight=FontWeight.Bold )Text( modifier=Modifier.align(Alignment.CenterStart), text="MGS 1", fontSize=12.sp, color=Color.Gray )AnimatableSpacer( stateIndex= index+1, state= sharedAnimatableState )AnimatableText( text= infoCards[index].info, stateIndex= index, state= sharedAnimatableState, fontWeight=FontWeight.Bold ) } } }AsyncImage( modifier=Modifier .weight(1f) .padding(8.dp) .clip(RoundedCornerShape(32.dp)), model= infoCards[index].imageUrl, contentDescription=null, contentScale=ContentScale.Crop ) } } } }}
Data
data classInfoCard(valimageUrl:String,valtitle:String,valinfo:String){companionobject {val infoCards=listOf(// ) }}
You can learn to use it step by step, you need to use state and components together.
State
// Simply create state and pass it to AnimatableTextval state= rememberAnimatableTextState( initialFontSize=12.sp, targetFontSize=60.sp)
Component
Column( modifier=Modifier .fillMaxSize() .clickable { state.animate()// animate }, verticalArrangement=Arrangement.Center, horizontalAlignment=Alignment.CenterHorizontally) {AnimatableText( text="Animatable", state= state// pass state )AnimatableText( text="Compose", state= state// pass state )}
State
// Simply create box state and pass it to AnimatableBoxval state= rememberAnimatableBoxState( initialSize=DpSize(60.dp,60.dp),// set initial size targetSize=DpSize(Dp.Infinity,120.dp),// set target size initialOffset=DpOffset(x=0.dp, y=0.dp),// set initial offset targetOffset=DpOffset(x=0.dp, y=-Dp.Infinity)// set target offset// Dp.Infinity will take the maximum value according to the screen size,// ps: Dp.Infinity for offset needs centered component and sizes, however you may not use it if you want initialAlignment=Alignment.Center,// set initial alignment targetAlignment=Alignment.TopStart// set target alignment)
Component
AnimatableBox( modifier=Modifier .border(1.dp,Color.Red) .clickable { state.animate() }, state= state) {Icon( modifier=Modifier.padding(8.dp), imageVector=Icons.Default.Add, contentDescription=null )}
State
// Simply create card state and pass it to AnimatableCardval animatableCardState= rememberAnimatableCardState( initialSize=DpSize(width=70.dp, height=70.dp), targetSize=DpSize(width=200.dp, height=70.dp), initialShape=CircleShape, targetShape=RoundedCornerShape(0.dp,0.dp,24.dp,0.dp), initialOffset=DpOffset(x=0.dp, y=0.dp), targetOffset=DpOffset(x=-Dp.Infinity, y=-Dp.Infinity))
Component
Box( modifier=Modifier .fillMaxSize() .clickable { animatableCardState.animateToInitial()// animate to initial }, contentAlignment=Alignment.Center) {AnimatableCard( modifier=Modifier.size(100.dp), onClick= { animatableCardState.animateToTarget()// animate to target }, state= animatableCardState ) {}}
States
// Simply create card state and text stateval animatableCardState= rememberAnimatableCardState( initialSize=DpSize(width=50.dp, height=25.dp), targetSize=DpSize(width=300.dp, height=150.dp), initialShape=CircleShape, targetShape=RoundedCornerShape(16.dp))val animatableTextState= rememberAnimatableTextState( initialFontSize=4.sp, targetFontSize=36.sp)// Merge the states you created into sharedState and pass it to AnimatableCard and AnimatableTextval sharedAnimatableState= rememberSharedAnimatableState( animatableStates=listOf( animatableCardState, animatableTextState ), toTargetAnimationSpec= infiniteRepeatable(tween(1000),RepeatMode.Reverse)//specify shared animation spec)
Components
Box( modifier=Modifier .fillMaxSize() .clickable { sharedAnimatableState.animate() }, contentAlignment=Alignment.Center) {AnimatableCard( modifier=Modifier.size(100.dp), state= sharedAnimatableState// pass shared state ) {Box(Modifier.fillMaxSize(),Alignment.Center) {AnimatableText( text="Animatable", state= sharedAnimatableState// pass shared state ) } }}
- Open the file
settings.gradle(it looks like that)
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral()// add jitpack here 👇🏽 maven { url'https://jitpack.io' }... }}...- Sync the project
- Add dependencies
dependencies { implementation'com.github.commandiron:AnimatableCompose:1.0.5'}- SharedAnimationSpec ✔️
About
Add Animatable Material Components in Android Jetpack Compose. Create jetpack compose animations painless.
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
No packages published







