Wajahat Karim
wajahatkarim.com
WajahatKarim
a modern UI toolkit which simplifies and accelerates UI development on Android with less code, powerful tools, and intuitive Kotlin APIs.
@Composable
fun ExpandableText() {
val shortText = "Click me"
val longText = "Very long text passage that spans
\nacross multiple lines, paragraphs
\nand pages"
var short by remember { mutableStateOf(true) }
Box(
modifier = Modifier
.background(
Color.Blue,
RoundedCornerShape(15.dp)
)
.clickable { short = !short }
.padding(20.dp)
.wrapContentSize()
.animateContentSize()
) {
Text(
if (short) {
shortText
} else {
longText
},
style = TextStyle(color = Color.White)
)
}
}
@Composable
fun PortraitModeImage() {
var portraitMode by remember { mutableStateOf(true) }
Box(
Modifier.clickable { portraitMode = !portraitMode }
.sizeIn(maxWidth = 300.dp, maxHeight = 300.dp)
.background(
if (portraitMode) Color(0xFFfffbd0) else Color(0xFFe3ffd9))
.animateContentSize(
animSpec = tween(500, easing = LinearEasing),
endListener = { startSize, endSize ->
Log.d("droidcon", "$startSize -> $endSize")
}
)
.aspectRatio(if (portraitMode) 3 / 4f else 16 / 9f)
) {
Text(
if (portraitMode) {
"3 : 4"
} else {
"16 : 9"
},
style = TextStyle(color = Color.Black)
)
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun VisibilityAnimationFAB() {
var expanded by remember { mutableStateOf(true) }
FloatingActionButton(
onClick = { expanded = !expanded },
) {
Row(Modifier.padding(start = 16.dp, end = 16.dp)) {
Icon(
asset = Icons.Default.Favorite,
Modifier.align(Alignment.CenterVertically)
)
AnimatedVisibility(
expanded,
modifier = Modifier.align(Alignment.CenterVertically)
) {
Text(modifier = Modifier.padding(start = 8.dp), text = "Like")
}
}
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun VisibilityAnimationFAB() {
var expanded by remember { mutableStateOf(true) }
FloatingActionButton(
onClick = { expanded = !expanded },
) {
Row(Modifier.padding(start = 16.dp, end = 16.dp)) {
Icon(
asset = Icons.Default.Favorite,
Modifier.align(Alignment.CenterVertically)
)
AnimatedVisibility(
expanded,
modifier = Modifier.align(Alignment.CenterVertically),
enter = slideInHorizontally(
initialOffsetX = { 300 },
animSpec = tween(durationMillis = 2000)
),
exit = slideOutVertically(
targetOffsetY = { 100 },
animSpec = tween(durationMillis = 2000)
)
) {
Text(text = "Like")
}
}
}
}
Default
Enter
Enter + Exit
cs.android.com
AnimatedVisibility in LazyColumn
AnimatedVisibility in multiple Composables
A simple method for animations between current and target state.
Supports Int, Dp, Color, Rect and many more types.
@Composable
fun ScaleAndColorAnimation() {
val enabled = remember { mutableStateOf(true) }
val color = if (enabled.value) MaterialTheme.colors.primary
else MaterialTheme.colors.secondary
val height = if (enabled.value) 40.dp else 60.dp
val width = if (enabled.value) 150.dp else 300.dp
Button(
onClick = { enabled.value = !enabled.value },
backgroundColor = animate(color),
modifier = Modifier
.padding(16.dp)
.preferredHeight(animate(height))
.preferredWidth(animate(width)),
) {
Text("Scale & Color")
}
}
@Composable
fun GenderSelectAnimation() {
val female = remember { mutableStateOf(true) }
Row(horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
asset = imageResource(R.drawable.male),
contentScale = ContentScale.Crop,
modifier = Modifier
.preferredSize(animate(if (female.value) 100.dp else 250.dp))
.border(width = animate(if (female.value) 0.dp else 4.dp),
color = animate(if (female.value) Color.Transparent else Color.Red))
.padding(8.dp)
.clickable { female.value = !female.value }
.clip(RoundedCornerShape(animate(if (female.value) 0.dp else 8.dp)))
)
Image(
asset = imageResource(R.drawable.female),
contentScale = ContentScale.Crop,
modifier = Modifier
// ...
// Like previous image
)
}
}
github.com/Gurupreet/ComposeCookBook
@Composable
fun HeartBeatDemo() {
val animScale = animatedFloat(initVal = 1f)
val animColor = animatedColor(initVal = Color.Red)
onActive {
animScale.animateTo(
targetValue = 1.3f,
anim = repeatable(
iterations = AnimationConstants.Infinite,
animation = tween(durationMillis = 300,
easing = FastOutLinearInEasing, delayMillis = 1000)
)
)
animColor.animateTo(
targetValue = Color.Blue,
anim = repeatable(
iterations = AnimationConstants.Infinite,
animation = tween(durationMillis = 300,
easing = LinearEasing, delayMillis = 1000)
)
)
}
Image(asset = Icons.Default.Favorite,
modifier = Modifier.padding(10.dp).size((40*animScale.value).dp),
colorFilter = ColorFilter.tint(animColor.value)
)
}
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
DrawScope - Handles the drawing API
drawRect()
drawOval()
drawLine()
drawImage()
drawRoundRect()
drawCircle()
drawArc()
drawPath()
fun DrawScope.drawMyShape() { }
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
@Composable
fun MovingSquare() {
val animPosX = animatedFloat(initVal = 0f)
onActive {
animPosX.animateTo(
targetValue = 500f,
anim = repeatable(
iterations = AnimationConstants.Infinite,
animation = tween(durationMillis = 1000)
)
)
}
Canvas(modifier = Modifier.preferredSize(100.dp), onDraw = {
withTransform({
translate(left = animPosX.value)
}) {
drawRect(color = Color.Red)
}
})
}
A simple moving square example
Its all about mathematics & drawing
github.com/wajahatkarim3/DinoCompose
github.com/alexjlockwood/bees-and-bombs-compose/
class DroidconActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DroidconEMEA2020Theme {
Scaffold(
topBar = {
TopAppBar( /* App Bar */ )
},
floatingActionButton = {
ExplodingFabButton()
},
bodyContent = {
// Content Composables
}
}
}
}
}
enum class FabSizeState {
NORMAL, EXPLODED
}
val fabSizeKey = FloatPropKey()
@Composable
fun ExplodingFabButton() {
val fabSizeState = remember { mutableStateOf(FabSizeState.NORMAL) }
val fabTransitionDef = transitionDefinition<FabSizeState> {
// What happens when Normal
state(FabSizeState.NORMAL) {
this[fabSizeKey] = 80f
}
// What happens when Exploded
state(FabSizeState.EXPLODED) {
this[fabSizeKey] = 5000f
}
}
}
@Composable
fun ExplodingFabButton() {
val fabSizeState = remember { mutableStateOf(FabSizeState.NORMAL) }
val fabTransitionDef = transitionDefinition<FabSizeState> {
/* ---- States from Previous Slide ---- */
// Transition from Normal to Exploded
transition(FabSizeState.NORMAL to FabSizeState.EXPLODED) {
fabSizeKey using keyframes {
durationMillis = 1000
80f at 0
35f at 200
5000f at 1000
}
}
// Transition from Exploded to Normal
transition(FabSizeState.EXPLODED to FabSizeState.NORMAL) {
fabSizeKey using tween(durationMillis = 1000,
easing = FastOutSlowInEasing)
}
}
}
@Composable
fun ExplodingFabButton() {
val fabSizeState = remember { mutableStateOf(FabSizeState.NORMAL) }
val fabTransitionDef = transitionDefinition<FabSizeState> {
/* ---- States from Previous Slide ---- */
/* ---- Transitions from Previous Slide ---- */
}
val transitionState = transition(
definition = fabTransitionDef,
initState = fabSizeState.value,
toState = if (fabSizeState.value == FabSizeState.NORMAL)
FabSizeState.EXPLODED
else FabSizeState.NORMAL
)
FabButton(fabSizeState = fabSizeState, transitionState = transitionState)
}
@Composable
fun ExplodingFabButton() {
/* From Previous Slides */
}
@Composable
fun FabButton(fabSizeState: MutableState<FabSizeState>,
transitionState: TransitionState
) {
FloatingActionButton(
onClick = { },
modifier = Modifier.size(transitionState[fabSizeKey].dp)
) {
Icon(asset = Icons.Default.Add)
}
}
https://joebirch.co/
https://www.raywenderlich.com/13282144-jetpack-compose-animations-tutorial-getting-started
Alex Lockwood
https://github.com/alexjlockwood/bees-and-bombs-compose
https://github.com/alexjlockwood/android-2048-compose
Joe Birch
https://joebirch.co/exploring-jetpack-compose/
Gurupreet Singh
https://github.com/Gurupreet/ComposeCookBook
Leland Richardson
https://www.twitch.tv/intelligibabble
Official by Google
https://developer.android.com/courses/pathways/compose
Vinay Gaba
https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example
Code is available at
https://github.com/wajahatkarim3/droidcon2020
WajahatKarim
wajahatkarim.com/subscribe
wajahatkarim.com