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