🚀🧨📝 Series of Tutorials to learn about Jetpack Compose with subjects Material Widgets, Layout, SubcomposeLayout, custom layouts, State, custom rememberable, recomposition, LaunchedEffect, side-effects, Gesture, Animation, Navigation, Canvas, UIs like whatsapp and others.
Series of Tutorials to learn about Jetpack Compose, Material Widgets, State, Animation, and
Navigation. Easy to search in code and in app. Each chapter module contains its own content in code.
SearchBar can be used to search with a tag or description available for each tutorial.
Recommended section is under constructions for now, when finished it will get recommended tags using
previous searches using a database, domain with ViewModel.
Tutorial
Preview
1-1 Column, Row, Box, Modifiers
Create Row that adds elements in horizontal order, and Column that adds elements in vertical order.
• Column • Row • Box • Modifier
1-2 Surface, Shape, Clickable
Create and modify Surface to draw background for Composables, add click action to any composable. Set weight or offset modifiers.
• Surface • Shape • Clickable
Material Widgets
Tutorial
Preview
2-1 Text
Create Text component with different properties such as color, background, font weight, family, style, spacing and others
• Text • Row • FontStyle • Annotated String Hyperlink
2-2 Button, IconButton, FAB, Chip
Create button with text and/or with image, Floating Action Button or Chips. Modify properties of buttons including color, text, and click actions.
Create TextField component with regular style or outlined. Set error, colors, state, icons, and IME actions.
• TextField • OutlinedTextField • IME • Phone format VisualTransformation • Regex
2-4 Image
Create Image with image, vector resource or with Painter, set image and Content scales to fit, expand or shrink image. Change shape of Image or apply ColorFilter and PorterDuff modes.
• Image • Canvas • Drawable • Bitmap
2-5 LazyColumn/Row/VerticalGrid
Vertical, horizontal grid lists with LazyColumn, LazyRow and LazyVerticalGrid. Use contentPadding set paddings for lists, verticalArrangement or horizontalArrangement for padding between items, rememberLazyListState to manually scroll.
TopAppbar with actions, overflow menus. Tabs with text only, image only and image+text with different background, divider, and indicators.
• TopAppBar • Overflow menu • TabRow and Tab • Tab Indicator, Divider
2-7 BottomNavigation
Bottom navigation bars allow movement between primary destinations in an app. BottomNavigation should contain multiple BottomNavigationItems, each representing a singular destination.
• BottomNavigation • BottomNavigationItem
2-8 BottomAppBar
A bottom app bar displays navigation and key actions at the bottom of screens.
• BottomAppBar • Scaffold
2-9-1 Side Navigation
A backdrop appears behind all other surfaces in an app, displaying contextual and actionable content.
• Scaffold • Side Navigation • DrawerState
2-9-2 ModalDrawer
Modal navigation drawers block interaction with the rest of an app’s content with a scrim. They are elevated above most of the app’s UI and don’t affect the screen’s layout grid.
• ModalDrawer • DrawerState • Scaffold
2-10-1 BottomSheet
Create bottom sheet using BottomSheetScaffold and rememberBottomSheetScaffoldState, create modal bottom sheets.
Use Modifier.onGloballyPositioned to get position of a Composable in parent, root or window.br> • Modifier • onGloballyPositioned
3-1-3 graphicsLayer
Use Modifier.offset{} and Modifier.graphicsLayer{} to scale, translate or change other properties of a Composable.
• Modifier • graphicsLayer
3-1-4 BoxWithConstraints
BoxWithConstraints is a composable that defines its own content according to the available space, based on the incoming constraints or the current LayoutDirection.
• BoxWithConstraints • Constraint
3-1-6 Chaining Size Modifiers
Observe how chaining Modifier.size.size, Modifier.sizeIn.size or Modifier.size.requiredSize or other combination of size modifiers effect final Constraints.
Add custom modifiers to Composable inside a custom layout using its scope like align modifier only available in specific Composable like a custom Column.
Subcompose layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.
Custom layout like whatsapp chat. Added quote and name tag resized to longest sibling using SubcomposeColumn from previous examples to have whole layout.
Use Interaction source to collect interactions or change scale of Composables based on interaction state.
• clickable • InteractionSource
5-1-3 InteractionSource2
Use InteractionSource to update touch state of multiple Composable or another Composable based on current interaction.
• clickable • InteractionSource
5-2 Tap&Drag Gesture
Use PointerInput to listen press, tap, long press, drag gestures. detectTapGestures is used for listening for tap, longPress, doubleTap, and press gestures.
Use PointerInput to listen for detectTransformGesture to get centroid, pan, zoom and rotate params.
• pointerInput • detectTransformGestures • centroid • pan • zoom
5-4-1 AwaitPointerEventScope1
Use AwaitPointerEventScope to get awaitFirstDown for down events, waitForUpOrCancellation for up events, and awaitPointerEvent for move events with pointers.
Use blend(Porter-Duff) to create multi colored VectorDrawables or VectorDrawables with fill/empty animations
• Canvas • DrawScope • VectorDrawable • BlendMode
6-4-2 Drawing App
Draw to canvas using touch down, move and up events using array of paths to have erase, undo, redo actions and set properties for each path separately.
Use blend(Porter-Duff) modes with androidx.compose.ui.graphics.Canvas to erase and compare pixels with erased Bitmap to find ou percentage of erased area.
Preview is broken for Tutorial 2.4 with following crash logs in Design tab.
java.lang.RuntimeException: Unable to find metadata to parse GlideModules
at com.bumptech.glide.module.ManifestParser.parse(ManifestParser.java:56)
at com.bumptech.glide.Glide.initializeGlide(Glide.java:254)
at com.bumptech.glide.Glide.initializeGlide(Glide.java:242)
at com.bumptech.glide.Glide.checkAndInitializeGlide(Glide.java:201)
at com.bumptech.glide.Glide.get(Glide.java:182)
at com.bumptech.glide.Glide.getRetriever(Glide.java:749)
at com.bumptech.glide.Glide.with(Glide.java:776)
at com.smarttoolfactory.tutorial1_1basics.chapter2_material_widgets.Tutorial2_4ImageKt.ImageDownloadWithGlideExample(Tutorial2_4Image.kt:554)
at com.smarttoolfactory.tutorial1_1basics.chapter2_material_widgets.ComposableSingletons$Tutorial2_4ImageKt$lambda-1$1.invoke(Tutorial2_4Image.kt:131)
I'm facing the error when build gradle for this project :
[Task 'prepareKotlinBuildScriptModel' not found in project ':app'](https://stackoverflow.com/questions/64290545/task-preparekotlinbuildscriptmodel-not-found-in-project-app)
To fix this issue please import this line to build.gradle(Module.app) file : task wrapper(type: Wrapper){ gradleVersion = '7.2' } tasks.register("prepareKotlinBuildScriptModel"){}
Please ignore this issue if you don't get the same error as me.
Thanks for nice tutorials.
java.lang.IllegalStateException: The offset was read before being initialized. Did you access the offset in a phase before layout, like effects or composition?
at androidx.compose.material.AnchoredDraggableState.requireOffset(AnchoredDraggable.kt:214)
at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$2$3.invoke-Bjo55l4(ModalBottomSheet.kt:622)
at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$2$3.invoke(ModalBottomSheet.kt:618)
at androidx.compose.foundation.layout.OffsetPxNode$measure$1.invoke(Offset.kt:247)
at androidx.compose.foundation.layout.OffsetPxNode$measure$1.invoke(Offset.kt:246)
at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)
at androidx.compose.ui.node.LookaheadDelegate.placeChildren(LookaheadDelegate.kt:178)
at androidx.compose.ui.node.LookaheadDelegate.placeAt-f8xVGno(LookaheadDelegate.kt:156)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:34)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative(Placeable.kt:452)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default(Placeable.kt:204)
at androidx.compose.foundation.layout.FillNode$measure$1.invoke(Size.kt:704)
at androidx.compose.foundation.layout.FillNode$measure$1.invoke(Size.kt:703)
in Tutorial2_10Screen1:
When I expand SheetContent quickly, it pops up at the bottom (maybe should be called "Fling"), showing some MainContent area. I want SheetContent to expand to its maximum height and stop at the bottom. What should I do?
Hi, i want to add an Background remover tool to my ImageToolbox app, which you are definitely know, and i used your compose tutorial 6-11 as reference, the problem is that when i use your zoom modifier then in portrait all works fine, but in landscape orientation erase area draws not as expected i.e. in different place, how to workaround this issue?
About Composable GridSnackCardWithTitle,
I thought they were the same height, but they're not.
Maybe the baseline should be considered.
or use Modifier.layout ?