Koreography
Choreograph your Compose Animation
A lightweight Compose Animation utility library to choreograph low-level Animation API (https://developer.android.com/jetpack/compose/animation#animation) through Kotlin DSL. It does the heavy lifting of dealing with coroutines under the hood so that you can focus on your animation choreography.
Including in your project
Koreography is available on mavenCentral()
implementation 'io.github.sagar-viradiya:koreography:0.2.0'
Usage
Creating koreography is the process of recording moves that can be either parallel or sequential. You can declare complex choreography through clean and concise Kotlin DSL.
Choreographying sequential animation
val koreography = rememberKoreography {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
}
The
move
call is identical toanimate
suspend function of compose except it is not suspend function since, creating koregraphy is just a process of recording moves
Choreographying parallel animation
val koreography = rememberKoreography {
parallelMoves {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
}
}
Complex choreography
You can have a nested hierarchy of moves to create complex choreography. The example below has three animations running parallelly and out of them, the last one has two animations within running sequentially.
val koreography = rememberKoreography {
parallelMoves {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
sequentialMoves {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
}
}
}
Executing koreography outside composable scope
Once Koreography
is ready it's time to dance!
You can execute the choreography outside the composable scope (button click) by calling dance
function.
koreography.dance(coroutineScope)
Please note the
coroutineScope
should be obtained throughrememberCoroutineScope()
. Make sure you pass coroutine scope which will get cleared once you exit composition.
π
Executing koreography based on state change Executing choreography based on state change is also supported. This API is similar to LaunchedEffect
API of compose side effects.
LaunchKoreography(state) {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, velocity ->
// Update the state value used for animation here
}
}
The choreography passed in the trailing lambda above would be executed on every state
change.
Example 1
The following example consists of two animations running sequentially having two parallel animations (Scale + Fade) within each. The first animation fades in alpha value and scales up the image. The second fade out and scale the image.
screen-20220916-005525_2.mp4
// Composable scope
var alpha by remember { mutableStateOf(0f) }
var scale by remember { mutableStateOf(0f) }
val koreography = rememberKoreography {
parallelMoves {
move(
initialValue = 0f,
targetValue = 1f,
animationSpec = tween(500)
) { value, _ ->
alpha = value
}
move(
initialValue = 0f,
targetValue = 2f,
animationSpec = tween(500)
) { value, _ ->
scale = value
}
}
parallelMoves {
move(
initialValue = 1f,
targetValue = 0f,
animationSpec = tween(500)
) { value, _ ->
alpha = value
}
move(
initialValue = 2f,
targetValue = 4f,
animationSpec = tween(500)
) { value, _ ->
scale = value
}
}
}
koreography.dance(rememberCoroutineScope())
Example 2
The following animation consists of two animations running sequentially. Each has three animations running parallelly (Scale + Rotate + Fade)
screen-20220916-013120_2.mp4
The code for choreographing above animation is there in the sample app.
Contribution
This is the early preview and unfortunately it is not ready to accept any contribution yet. Once this is stable enough contribution guidelines will be updated here. Meanwhile feel free to start GitHub Discussions for feature request and improvements.
License
Copyright 2022 Koreography Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.