Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jetpack Compose: UI toolkit for Android and Desktop apps

Jetpack Compose: UI toolkit for Android and Desktop apps

Jetpack Compose, the new UI toolkit by Google, has been in dev and alpha stage for more than a year and it is now in beta. Throught several live examples, let’s see how you can bring high quality UI to your Android application and how functional programming helped achieving such as thing. We will go even further and I’ll introduce Jetpack Compose for Desktop application where components from your Android app can be reused to keep the same quality of design design accross the platforms.

Julien Salvi

October 22, 2021
Tweet

More Decks by Julien Salvi

Other Decks in Programming

Transcript

  1. Jetpack Compose: UI toolkit for Android and Desktop apps Julien

    Salvi - Android GDE | Lead Android Engineer @ Aircall DevFest Nantes 2021 @JulienSalvi
  2. What’s Jetpack Compose? Jetpack Compose is a declarative UI framework

    made by Google. Stable since Aug. 2021. It is composed of a compiler, a runtime and a bunch of core UI libraries. Made with Kotlin. Nice interoperability with View UI framework.
  3. Jetpack Compose Jetpack Compose 1.0.0 🥳 Jetpack Compose 1.0.0-alpha-01 2020

    Compose 0.1.0-dev-01 Compose Web preview 2019 2021 2022 Jetpack Compose 1.0.0-beta-01 Compose Desktop dev-01 Compose Desktop and Web alpha
  4. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...)
  5. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...) title.text = ... desc.isVisible = ... group += View() a = MyAdapter()
  6. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...) title.text = ... desc.isVisible = ... group += View() a = MyAdapter() STATE
  7. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...) title.text = ... desc.isVisible = ... group += View() a = MyAdapter() STATE
  8. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...) title.text = ... desc.isVisible = ... group += View() a = MyAdapter() STATE STATE STATE STATE STATE
  9. Jetpack Compose From XML/View to Compose XML layout Activity /

    Fragment / View <FrameLayout> <LinearLayout> <TextView> <RecyclerView> setContentView(...) inflate(...) findViewById(...) title.text = ... desc.isVisible = ... group += View() a = MyAdapter() STATE STATE STATE STATE STATE ⚠ 💥 ⚠ 💥 ⚠ 💥 ⚠ 💥 ⚠ 💥
  10. Jetpack Compose Let’s explore the foundation of Compose: • How

    Compose transforms a state to a UI component by demystifying the declarative paradigm • How to make UI components: Composable • What Compose has to offer as a UI Toolkit to build top notch apps on Android
  11. Declarative UI • Every Composable is a function annotated with

    @Composable • You can split your UI into a set of tiny reusable components • Produce and render components @Composable fun IngredientList(ingredients: List<Ingredient>) { Column(modifier = modifier .fillMaxWidth() .wrapContentHeight() ) { Text(text = "Ingrédients") LazyRow { items(ingredients) { ing -> IngredientItem(ingredient = ing) } } } }
  12. Declarative UI • Basic conditions to show or hide UI

    components @Composable fun TwoPanel() { val threshold = density.run { 400.dp.toPx() } BoxWithConstraints { if (maxWidth.value > threshold) { TwoColumnsLayout() } else { HomeScreen() } } }
  13. Declarative UI • Basic conditions to show or hide UI

    components • You can pass parameters to your Composable • A change in these parameters will trigger the re-composition @Composable fun IngredientList(ingredients: List<Ingredient>) { Column(modifier = modifier .fillMaxWidth() .wrapContentHeight() ) { Text(text = "Ingrédients") LazyRow { items(ingredients) { ing -> IngredientItem(ingredient = ing) } } } }
  14. Declarative UI • ViewModel can handle LiveData or StateFlow that

    can be bound and collected a Composable • Every time a new state will be pushed it will re-compose the UI @Composable fun RecipeDetailsScreen(recipeId: Int) { val vm = hiltViewModel<RecipesViewModel>() val recipe = vm.recipe.collectAsState().value if (recipe.ingredients.isNotEmpty()) { IngredientList( ingredients = recipe.ingredients ) } }
  15. Declarative UI • Composable are immutable... • … but they

    can be dynamic! • You can “remember” internal state in order to trigger local changes @Composable fun StepItem(step: Step) { var expand by remember{ mutableStateOf(false) } Text( text = step.desc, modifier = Modifier.clickable { expand = !expand }, style = MaterialTheme.typography.body2, color = AppColorsTheme.colors.text, maxLines = if (expanded) MAX_VALUE else 3, overflow = if (expanded) Clip else Ellipsis ) }
  16. UI Toolkit • Override MaterialTheme to define your default Typography,

    Shapes and Colors • It has a great support for dark/light mode • Replaces old XML styles for Views @Composable fun RecipeekTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val colors = if (darkTheme) { DarkColorPalette } else { LightColorPalette } ProvideAppColors(colors) { MaterialTheme( colors = debugColors(darkTheme), typography = Typography, shapes = RecipeekShapes, content = content ) } }
  17. UI Toolkit • Compose offers a large set of atomic

    components (Button, Text, TextField, Image…) • As well as container (Box, Row, Column…) to organize your UI • Multiple Modifier to construct your components Button( onClick = { onNavigateTo(recipe.id) }, shape = MaterialTheme.shapes.medium, contentPadding = PaddingValues(0.dp), modifier = Modifier .fillMaxWidth() .wrapContentHeight() .background( color = AppColorsTheme.colors.main shape = MaterialTheme.shapes.medium ) .padding(8.dp) ) Column(modifier = modifier) { Text( text = "Préparation", style = MaterialTheme.typography.h5, color = AppColorsTheme.colors.text, ) Spacer(modifier = Modifier.size(8.dp)) steps.forEach { step -> StepItem(step = step) Spacer(modifier = Modifier.size(8.dp)) } }
  18. UI Toolkit • Modifier allow you to shape your UI

    but also interact with your Compose (click, touch events…) • When manipulating Modifer, keep in mind that the order matters! • Use them wisely 🙂 Text( text = "Some text", modifier = Modifier .fillMaxWidth() .padding(32.dp) .border( width = 4.dp, color = red700, shape = CutCornerShape(32.dp) ) .graphicsLayer { shadowElevation = 8.dp.toPx() shape = CutCornerShape(32.dp) clip = true } .background(color = greenLight700) .padding(32.dp) )
  19. UI Toolkit • Use the @Preview annotation to have a

    sneak peek of your UI @MustBeDocumented @Retention(AnnotationRetention.SOURCE) @Target( AnnotationTarget.FUNCTION ) @Repeatable annotation class Preview( val name: String = "", val group: String = "", @IntRange(from = 1) val apiLevel: Int = -1, val widthDp: Int = -1, val heightDp: Int = -1, val locale: String = "", @FloatRange(from = 0.01) val fontScale: Float = 1f, val showSystemUi: Boolean = false, val showBackground: Boolean = false, val backgroundColor: Long = 0, @UiMode val uiMode: Int = 0, @Device val device: String = Devices.DEFAULT )
  20. UI Toolkit • Use the @Preview annotation to have a

    sneak peek of your UI • Customize your Previews by showing the system UI or by enabling the dark mode @Preview( showSystemUi = true, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES ) @Composable fun StepPreview() { RecipeekTheme { val step = Step( position = 3, desc = "Lorem ipsum dolor sit amet" ) StepItem(step = step) } }
  21. UI Toolkit • Use the @Preview annotation to have a

    sneak peek of your UI • Customize your Previews by showing the system UI or by enabling the dark mode • Mock your data to see it in action!
  22. UI Toolkit • Support for interoperability with the View framework

    • Call Composable in View code val myComposeView = ComposeView(requireContext()).apply { // Dispose the Composition // when the view's LifecycleOwner is destroyed setViewCompositionStrategy( DisposeOnViewTreeLifecycleDestroyed ) setContent { // Compose stuff MaterialTheme { Text("Hello DevFest Nantes!") } } }
  23. UI Toolkit • Support for interoperability with the View framework

    • Call Composable in View code • Call View code in Composable @Composable fun CustomView() { // Adds view to Compose AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> // Creates custom view CustomView(context).apply { // Setup your View here } }, update = { view -> // Populate your view with new state // -> re-compose view.setStuff = newStuff() } ) }
  24. Jetpack Compose Live coding! Let’s code a small recipe app

    🍱 ⚠ Architecture in MVC (Model-View-Crado) ⚠
  25. Compose Android Let’s build a small list/detail app: RECIPEEK On

    the main screen we’ll have a Toolbar, a search bar and a list of recipes with some information What we’re going to learn: - Modifier - LazyColumn - State - Theming https://github.com/oleur/recipeek
  26. Compose Android On the recipe details screen we’ll have a

    look at more Modifiers and how to place Composables and add some nice Animations. What we’re going to learn: - More Modifiers - Shapes - ConstraintLayout Compose - State - Animations
  27. Compose Desktop Developed and maintained by JetBrains based on Jetpack

    Compose for Android Uses Skia for a power rendering Desktop extensions for mouse/keyboard events, menus, window manipulation... AWT and Swing interoperability
  28. Compose for Desktop Live coding! Let’s bring our recipe app

    to desktop 🍱 ⚠ Architecture in MVC (Model-View-Crado) ⚠
  29. Compose Desktop With the desktop version of the app we’ll

    see how to adapt Compose Android code to make it work on desktop. What we’re going to learn: - Desktop Modifiers - Theme for Desktop - Layouts - State - Animations https://github.com/oleur/Recipeek-desktop
  30. Compose Multiplatform If you want to maintain only one code

    base to develop your app for Android, Desktop or iOS you might want to take a look at Kotlin Multiplatform. Some Compose tools are only supported on Android (ConstraintLayout, Lifecycle, Coil…) Developing for desktop might take a bit longer than Android as the library ecosystem is not as rich as Android yet.
  31. Resources Compose Desktop & Web Official Documentation https://www.jetbrains.com/lp/compose/ Sources, Samples

    & Tutorials https://github.com/jetbrains/compose-jb Recipeek Desktop https://github.com/oleur/Recipeek-desktop
  32. Merci! Julien Salvi - Android GDE | Lead Android Engineer

    @ Aircall DevFest Nantes 2021 @JulienSalvi Have fun with Jetpack Compose!