Jetpack Compose Basics Guide
Jetpack Compose Basics Guide
by Example
Vinay Gaba
@vinaygaba
}
}
}
fun [Link](
recomposer: Recomposer = [Link](),
content: @Composable () "-> Unit
): Composition {
"// Some magic ✨🦄
}
class HelloWorldActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
}
}
}
class HelloWorldActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
Text(text = "Hello World")
}
}
}
class HelloWorldActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
Text(text = "Hello World")
}
}
}
class HelloWorldActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
Text(text = "Hello World")
}
}
}
@Composable
fun CustomTextComponent() {
Text(text = "Hello World")
}
@Composable
fun CustomTextComponent(displayText: String) {
Text(
text = displayText,
style = TextStyle(
fontSize = [Link],
fontFamily = [Link]
)
)
}
@Composable
fun CustomTextComponent(displayText: String) {
Text(
text = displayText,
style = TextStyle(
fontSize = [Link],
fontFamily = [Link]
)
)
}
@Composable
fun CustomTextComponent(displayText: String) {
Text(
text = displayText,
style = TextStyle(
fontSize = [Link],
fontFamily = [Link]
)
)
}
@Preview
@Composable
fun CustomTextComponentPreview() {
CustomTextComponent("Hello World")
}
Display Image
@Composable
fun DrawableImage() {
}
@Composable
fun DrawableImage() {
val image = loadImageResource([Link])
}
@Composable
fun DrawableImage() {
val image = loadImageResource([Link])
[Link]"?.let {
Image(asset = it, modifier = [Link]([Link]))
}
}
@Composable
// Somewhere else in code fun AlertDialogComponent() {
if (some_condition_is_met()) {
[Link]()
} }
if (showPopup) {
AlertDialog(
onCloseRequest = { showPopup = false },
text = {
Text("Congratulations! You just clicked the text successfully")
},
confirmButton = {
Button(
onClick = onPopupDismissed
) {
Text(text = "Ok")
}
}
)
}
}
@Composable
fun AlertDialogComponent() {
var showPopup by remember { mutableStateOf(false) }
if (showPopup) {
AlertDialog(
onCloseRequest = { showPopup = false },
text = {
Text("Congratulations! You just clicked the text successfully")
},
confirmButton = {
Button(
onClick = onPopupDismissed
) {
Text(text = "Ok")
}
}
)
}
}
@Composable
fun AlertDialogComponent() {
var showPopup by remember { mutableStateOf(false) }
if (!showPopup) {
Button(onClick = { showPopup = true }) {
Text(text = "Click Me")
}
} else {
AlertDialog(
onCloseRequest = { showPopup = false },
text = {
Text("Congratulations! You just clicked the text successfully")
},
confirmButton = {
Button(
onClick = onPopupDismissed
) {
Text(text = "Ok")
}
}
)
}
}
Recomposition
Recompose
/ re·kuhm·powz /
verb
(address: String)
(imageURL: String)
[scale: Float]
(user: User)
(address: String)
(imageURL: String)
[scale: Float]
(user: User)
(address: String)
(imageURL: String)
[scale: Float]
(user: User)
(address: String)
(imageURL: String)
[scale: Float]
(user: User)
(address: String)
(imageURL: String)
[scale: Float]
(user: User)
(address: String)
(imageURL: String)
[scale: Float]
Rules of
Recomposition
Rules of
Recomposition
Text([Link])
}
"// When this component is called from inside an animation,
"// it will be called on every frame.
@Composable
fun ComponentCalledFromAnimation() {
launchInComposition
"// expensiveOperation takes 2 seconds to run
val result = expensiveOperation()
Text([Link])
}
Rules of
Recomposition
1 2
Row
1
2
Column
@Composable
fun ImageWithTitleSubtitleComponent() {
}
@Composable
fun ImageWithTitleSubtitleComponent() {
Row() {
Column() {
}
}
}
@Composable
fun ImageWithTitleSubtitleComponent() {
Row(modifier = [Link]().padding([Link])) {
Column(modifier = [Link](start = [Link])) {
}
}
}
@Composable
fun ImageWithTitleSubtitleComponent() {
Row(modifier = [Link]().padding([Link])) {
DrawableImage([Link])
Column(modifier = [Link](start = [Link])) {
CustomTextComponent(displayText = "Title")
CustomTextComponent(displayText = "Subtitle")
}
}
}
@Composable
fun ImageWithTitleSubtitleComponent(
title: String,
subtitle: String,
imageUrl: String
) {
Row(modifier = [Link]().padding([Link])) {
NetworkImage(imageUrl)
Column(modifier = [Link](start = [Link])) {
CustomTextComponent(displayText = title)
CustomTextComponent(displayText = subtitle)
}
}
}
@Composable
fun ImageWithTitleSubtitleComponent(
title: String,
subtitle: String,
imageUrl: String
) {
Row(modifier = [Link]().padding([Link])) {
NetworkImage(imageUrl)
Column(modifier = [Link](start = [Link])) {
CustomTextComponent(displayText = title)
CustomTextComponent(displayText = subtitle)
}
}
}
Display List
@Composable
fun ListComponent(superheroList: List<Person>) {
}
@Composable
fun ListComponent(superheroList: List<Person>) {
ScrollableColumn {
for(person in superheroList) {
SimpleRowComponent(
[Link],
[Link],
[Link]
)
}
}
}
[Link]
@Composable
fun ListComponent(superheroList: List<Person>) {
}
@Composable
fun ListComponent(superheroList: List<Person>) {
LazyColumnFor(items = superheroList) { person "->
}
}
@Composable
fun ListComponent(superheroList: List<Person>) {
LazyColumnFor(items = superheroList) { person "->
SimpleRowComponent(
[Link],
[Link],
[Link]
)
}
}
@Composable
fun ListComponent(superheroList: List<Person>) {
LazyColumnFor(items = superheroList) { person "->
SimpleRowComponent(
[Link],
[Link],
[Link]
)
}
}
Thank You Droid God,
For this new day. I will rest in your promises(coroutines) of a world free of
fragments. Guide me with compile-time checks and help me in every
@SuppressWarnings that I add.
Click Gesture
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String
) {
Card(
modifier = [Link]()
.padding([Link]),
shape = RoundedCornerShape([Link])
) {
""...
""...
""...
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
viewModel: SuperheroViewModel
) {
Card(
modifier = [Link]()
.padding([Link])
.cl
shape = RoundedCornerShape([Link])
) {
....
....
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
viewModel: SuperheroViewModel
) {
Card(
modifier = [Link]()
.padding([Link])
.cl
shape =clip
RoundedCornerShape([Link])
) {
.... clickable
.... clipToBounds
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
viewModel: SuperheroViewModel
) {
Card(
modifier = [Link]()
.padding([Link]) +
.clickable {
[Link]()
},
shape = RoundedCornerShape([Link])
) {
....
....
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
viewModel: SuperheroViewModel
) {
👎
Card(
modifier = [Link]()
.padding([Link]) +
.clickable {
[Link]()
},
shape = RoundedCornerShape([Link])
) {
....
....
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
onClick: () "-> Unit
) {
Card(
modifier = [Link]()
.padding([Link])
.clickable {
onClick()
},
shape = RoundedCornerShape([Link])
) {
....
....
}
}
@Composable
fun SimpleRowComponent(
titleText: String,
subtitleText: String,
imageUrl: String,
onClick: () "-> Unit
) {
Card(
modifier = [Link]()
.padding([Link])
.clickable {
onClick()
},
shape = RoundedCornerShape([Link])
) {
....
....
}
}
Pinch-to-Zoom & Drag
@Composable
fun ZoomableImageComponent(imageUrl: String) {
}
@Composable
fun ZoomableImageComponent(imageUrl: String) {
var scale by state { 1f }
var panOffset by state { Offset(0f, 0f) }
}
@Composable
fun ZoomableImageComponent(imageUrl: String) {
var scale by state { 1f }
var panOffset by state { Offset(0f, 0f) }
Box(gravity = [Link]) {
NetworkImage(
imageUrl = imageUrl,
modifier = [Link]()
)
}
}
@Composable
fun ZoomableImageComponent(imageUrl: String) {
var scale by state { 1f }
var panOffset by state { Offset(0f, 0f) }
Box(
gravity = [Link],
modifier = [Link](onZoomDelta = { scale *= it })
) {
NetworkImage(
imageUrl = imageUrl,
modifier = [Link]().drawLayer(
scaleX = scale,
scaleY = scale
)
)
}
}
@Composable
fun ZoomableImageComponent(imageUrl: String) {
var scale by state { 1f }
var panOffset by state { Offset(0f, 0f) }
Box(
gravity = [Link],
modifier = [Link](onZoomDelta = { scale *= it }).rawDragGestureFilter(
object : DragObserver {
override fun onDrag(dragDistance: Offset): Offset {
panOffset = [Link](dragDistance)
return [Link](dragDistance)
}
})
) {
NetworkImage(
imageUrl = imageUrl,
modifier = [Link]().drawLayer(
scaleX = scale,
scaleY = scale,
translationX = panOffset.x,
translationY = panOffset.y
)
)
}
}
@Composable
fun ZoomableImageComponent(imageUrl: String) {
var scale by state { 1f }
var panOffset by state { Offset(0f, 0f) }
Box(
gravity = [Link],
modifier = [Link](onZoomDelta = { scale *= it }).rawDragGestureFilter(
object : DragObserver {
override fun onDrag(dragDistance: Offset): Offset {
panOffset = [Link](dragDistance)
return [Link](dragDistance)
}
})
) {
NetworkImage(
imageUrl = imageUrl,
modifier = [Link]().drawLayer(
scaleX = scale,
scaleY = scale,
translationX = panOffset.x,
translationY = panOffset.y
)
)
}
}
Compose in Classic Android
activity_compose_in_classic_android.xml
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" "/>
<[Link]
android:id="@+id/compose_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" "/>
"</LinearLayout>
activity_compose_in_classic_android.xml
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" "/>
<[Link]
android:id="@+id/compose_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" "/>
"</LinearLayout>
class ComposeInClassicAndroidActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_compose_in_classic_android)
}
}
class ComposeInClassicAndroidActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_compose_in_classic_android)
val composeView = findViewById([Link].compose_view)
[Link] {
SimpleRowComponent()
}
}
}
class ComposeInClassicAndroidActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_compose_in_classic_android)
val composeView = findViewById([Link].compose_view)
[Link] {
SimpleRowComponent()
}
}
}
Classic Android in Compose
@Composable
fun ClassAndroidInComposeComponent() {
}
@Composable
fun ClassAndroidInComposeComponent() {
val context = [Link]
val classicTextView = remember { TextView(context) }
}
@Composable
fun ClassAndroidInComposeComponent() {
val context = [Link]
val classicTextView = remember { TextView(context) }
"// or
}
@RunWith(JUnit4"::class)
class SimpleRowComponentTest {
@get:Rule
val composeTestRule = createComposeRule(disableTransitions = true)
}
@RunWith(JUnit4"::class)
class SimpleRowComponentTest {
@get:Rule
val composeTestRule = createComposeRule(disableTransitions = true)
@Before
fun setUp() {
[Link] {
SimpleRowComponent(
titleText = "Title",
subtitleText = "Subtitle",
imageUrl = "https:"//[Link]/[Link]"
)
}
}
}
@RunWith(JUnit4"::class)
class SimpleRowComponentTest {
@get:Rule
val composeTestRule = createComposeRule(disableTransitions = true)
@Before
fun setUp() {
[Link] {
SimpleRowComponent(
titleText = "Title",
subtitleText = "Subtitle",
imageUrl = "https:"//[Link]/[Link]"
)
}
}
@Test
fun check_if_card_is_displayed() {
[Link]("Title")
}
}
@Test
fun check_if_card_is_displayed() {
[Link]("Title")
}
@Test
fun check_if_card_is_displayed() {
[Link]("Ti")
}
@Test
fun check_if_card_is_displayed() {
[Link]("TitleTag")
}
@Test
fun check_if_card_is_displayed() {
[Link]("TitleTag")
}