Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Provide feedback

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

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add Animatable Material Components in Android Jetpack Compose. Create jetpack compose animations painless.

NotificationsYou must be signed in to change notification settings

commandiron/AnimatableCompose

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

How it looks

Phone NumberCard Dealer

Phone Number

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        )    }}

Card Dealer

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 StoryInfo Card

Insta Story

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(//        )    }}

Info Card

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(//        )    }}

How to use

You can learn to use it step by step, you need to use state and components together.

AnimatableText

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    )}

AnimatableBox

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    )}

AnimatableCard

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    ) {}}

AnimatableCardWithText

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            )        }    }}

Setup

  1. Open the filesettings.gradle (it looks like that)
dependencyResolutionManagement {    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)    repositories {        google()        mavenCentral()// add jitpack here 👇🏽        maven { url'https://jitpack.io' }...    }}...
  1. Sync the project
  2. Add dependencies
dependencies {    implementation'com.github.commandiron:AnimatableCompose:1.0.5'}

Todo ✔️

  • SharedAnimationSpec ✔️

[8]ページ先頭

©2009-2025 Movatter.jp