This work is licensed under the Apache 2.0 License
Jetpack Compose
for Android Developers
This work is licensed under the Apache 2.0 License
Whiston Borja
Android Developer
Camp leaders
This work is licensed under the Apache 2.0 License
● Thinking in Compose
● Composable functions
● Compose toolkit
● Tooling
Agenda
This work is licensed under the Apache 2.0 License
Thinking in
Compose
This work is licensed under the Apache 2.0 License
Construct UI by
describing what,
not how.
This work is licensed under the Apache 2.0 License
goo.gle/compose-samples
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
Survey
answer
Image Text Radio button
This work is licensed under the Apache 2.0 License
<LinearLayout android:orientation=“horizontal” >
<ImageView
android:id=”@+id/answer_image” ... />
<TextView
android:id=”@+id/answer_text” ... />
<RadioButton
android:id=”@+id/answer_radio_button” ... />
</LinearLayout>
<!-- survey_answer.xml -->
This work is licensed under the Apache 2.0 License
class SurveyQuestionActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val image = findViewById(R.id.answer_image)
val text = findViewById(R.id.answer_text)
val radioButton =
findViewById(R.id.answer_radio_button)
// ...
}
}
// SurveyQuestionActivity.kt
This work is licensed under the Apache 2.0 License
class SurveyQuestionActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
image.setImage(...)
text.setText(...)
// ...
}
}
// SurveyQuestionActivity.kt
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
Survey
answer
Image Text Radio button
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
Image(answer.image)
Text(answer.text)
RadioButton(false, onClick = { /* … */ })
}
}
// SurveyAnswer.kt
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
Image(answer.image)
Text(answer.text)
RadioButton(false, onClick = { /* … */ })
}
}
// SurveyAnswer.kt
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
Image(answer.image)
Text(answer.text)
RadioButton(false, onClick = { /* … */ })
}
}
// SurveyAnswer.kt
This work is licensed under the Apache 2.0 License
Construct UI by
describing what,
not how.
This work is licensed under the Apache 2.0 License
Event
handler
UI element
onClick()
This work is licensed under the Apache 2.0 License
UI
State
This work is licensed under the Apache 2.0 License
UI 2
State 2
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
/ * ... */
var selected: Boolean = // ...
RadioButton(selected, onClick = { /* … */ })
}
}
// SurveyAnswer.kt
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
/ * ... */
var selected: Boolean = // ...
RadioButton(selected, onClick = {
selected = !selected
})
}
}
// SurveyAnswer.kt
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
/ * ... */
var selected: Boolean = // ...
RadioButton(selected, onClick = {
selected = !selected
})
}
}
// SurveyAnswer.kt
Describe what, not how
UI elements are functions
State controls UI
Events control State
1
2
3
4
This work is licensed under the Apache 2.0 License
Composable
functions
This work is licensed under the Apache 2.0 License
goo.gle/compose-samples
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
// SurveyAnswer.kt
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
Image(answer.image)
Text(answer.text)
RadioButton(false, onClick = { /* … */ })
}
}
This work is licensed under the Apache 2.0 License
// SurveyAnswer.kt
@Composable
fun SurveyAnswer(answer: Answer) {
Row {
Image(answer.image)
Text(answer.text)
RadioButton(false, onClick = { /* … */ })
}
}
This work is licensed under the Apache 2.0 License
// SurveyAnswer.kt
@Composable
fun SurveyAnswer(answer: Answer) { /* … */ }
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
// Can’t do this!!
val answer = SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
if (answers.isEmpty()) {
Text(“There are no answers to choose from!”)
} else {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
// Don’t do this! There shouldn’t be side-effects
SurveyApp.didShowSingleChoiceQuestion = true
Column {
if (answers.isEmpty()) { /* ... */ }
else { /* ... */ }
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
// Fast and no side-effects
Column {
if (answers.isEmpty()) { /* ... */ }
else { /* ... */ }
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
Column {
answers.forEach { answer ->
SurveyAnswer(answer = answer)
}
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: Answer? = null
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: Answer? = null
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: MutableState<Answer?> =
mutableStateOf(null)
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: MutableState<Answer?> =
mutableStateOf(null)
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = false,
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: MutableState<Answer?> =
mutableStateOf(null)
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer.state == answer),
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: MutableState<Answer?> =
remember { mutableStateOf(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer.state == answer),
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: MutableState<Answer?> =
rememberSaveable { mutableStateOf(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer.state == answer),
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: Answer? by
rememberSaveable { mutableStateOf(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer.state == answer),
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: Answer? by
rememberSaveable { mutableStateOf(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer == answer),
)
}
}
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
var selectedAnswer: Answer? by
rememberSaveable { mutableStateOf(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer == answer),
onAnswerSelected = { answer -> selectedAnswer = answer }
)
}
}
This work is licensed under the Apache 2.0 License
Event
handler
UI element
event
state
Events change State
This work is licensed under the Apache 2.0 License
Event
handler
UI element
onAnswerSelecte
d
answer
Events change State
This work is licensed under the Apache 2.0 License
// SingleChoiceQuestion.kt
@Composable
fun SingleChoiceQuestion(answers: List<Answer>) {
val selectedAnswer: Answer? by
rememberSaveable { mutableStateOf<Answer>(null) }
answers.forEach { answer ->
SurveyAnswer(
answer = answer,
isSelected = (selectedAnswer == answer),
onAnswerSelected = { answer -> selectedAnswer = answer }
)
}
}
This work is licensed under the Apache 2.0 License
Composable
functions can
execute in any
order.
This work is licensed under the Apache 2.0 License
// ButtonRow.kt
@Composable
fun ButtonRow() {
MyFancyNavigation {
StartScreen()
MiddleScreen()
EndScreen()
}
}
This work is licensed under the Apache 2.0 License
Composable
functions can run
in parallel.
This work is licensed under the Apache 2.0 License
@Composable
fun ListComposable(myList: List<String>) {
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Column {
for (item in myList) {
Text("Item: $item")
}
}
Text("Count: ${myList.size}")
}
}
// ListComposable.kt
This work is licensed under the Apache 2.0 License
@Composable
fun ListWithBug(myList: List<String>) {
var items = 0
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Column {
for (item in myList) {
Text("Item: $item”)
items++ // Avoid! Side-effect of the column recomposing.
}
}
Text("Count: $items")
}
}
// ListComposable.kt
This work is licensed under the Apache 2.0 License
Recomposition skips
as much as possible.
This work is licensed under the Apache 2.0 License
@Composable
fun GreetingScreen(name: String) {
Column {
Header()
Greeting(name = name)
Footer()
}
}
// GreenScreen.kt
This work is licensed under the Apache 2.0 License
Recomposition is
optimistic.
This work is licensed under the Apache 2.0 License
Composable
functions might run
frequently.
This work is licensed under the Apache 2.0 License
Summary
Create composables using the @Composable annotation
It’s quick & easy to create composables
Composables accept parameters
Use MutableState and remember
Composables should be side-effect free
This work is licensed under the Apache 2.0 License
Composables can:
Execute in any order
Run in parallel
Be skipped
Run frequently
1
2
3
4
This work is licensed under the Apache 2.0 License
Compose Toolkit
This work is licensed under the Apache 2.0 License
goo.gle/compose-samples
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
MaterialTheme(
colorScheme = MyAppsColorScheme,
typography = MyAppsTypography,
shapes = MyAppsShapes
) {
// Content goes here
}
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
Scaffold(
topBar = { SmallTopAppBar(/* ... */) },
floatingActionButtonPosition = FabPosition.End,
floatingActionButton = {
FloatingActionButton(/* ... */)
},
content = { /* ... */ }
)
This work is licensed under the Apache 2.0 License
SurveyTopAppBa
r
SurveyBottomBa
r
Question
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
Surface {
Text("Hello Compose")
}
Hello Compose
This work is licensed under the Apache 2.0 License
Surface(
color = MaterialTheme.colorScheme.primary,
) {
Text("Hello Compose")
}
Hello Compose
This work is licensed under the Apache 2.0 License
Surface(
color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(8.dp),
) {
Text("Hello Compose")
}
Hello Compose
This work is licensed under the Apache 2.0 License
Surface(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(8.dp),
border = BorderStroke(2.dp,
MaterialTheme.colorScheme.outline
)
) {
Text("Hello Compose")
}
Hello Compose
This work is licensed under the Apache 2.0 License
Surface(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(8.dp),
border = BorderStroke(2.dp,
MaterialTheme.colorScheme.surfaceVariant
),
shadowElevation = 8.dp,
tonalElevation = 8.dp,
) {
Text("Hello Compose")
}
Hello Compose
This work is licensed under the Apache 2.0 License
This work is licensed under the Apache 2.0 License
goo.gle/compose-material-
ref
m3.material.io
This work is licensed under the Apache 2.0 License
Standard layouts
This work is licensed under the Apache 2.0 License
Row {
Component1()
Component2()
Component3()
} 1 2 3
Row
This work is licensed under the Apache 2.0 License
1
2
3
Column
Column {
Component1()
Component2()
Component3()
}
This work is licensed under the Apache 2.0 License
2
1
3
Box
Box {
Component1()
Component2()
Component3()
}
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer)
{
Row {
Image(answer.image)
Text(answer.text)
RadioButton(/* … */)
}
}
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer)
{
Row(
verticalAlignment =
Alignment.CenterVertically
) {
/* ... */
}
}
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer)
{
Row(
verticalAlignment =
Alignment.CenterVertically,
horizontalArrangement =
Arrangement.SpaceBetween
) {
/* ... */
}
}
goo.gle/compose-layouts-docs
This work is licensed under the Apache 2.0 License
Modifiers
This work is licensed under the Apache 2.0 License
Text("Hello
Compose")
Hello
Compose
This work is licensed under the Apache 2.0 License
Text(
"Hello Compose!",
Modifier.background(Color.Magenta)
)
Hello
Compose
This work is licensed under the Apache 2.0 License
Text(
"Hello Compose!",
Modifier.background(Color.Magenta)
.size(200.dp, 30.dp)
)
Hello Compose
This work is licensed under the Apache 2.0 License
Text(
"Hello Compose!",
Modifier.background(Color.Magenta)
.size(200.dp, 30.dp)
.padding(5.dp)
)
Hello Compose
This work is licensed under the Apache 2.0 License
Text(
"Hello Compose!",
Modifier.background(Color.Magenta)
.size(200.dp, 30.dp)
.padding(5.dp)
.alpha(0.5f)
)
Hello Compose
This work is licensed under the Apache 2.0 License
Text(
"Hello Compose!",
Modifier.background(Color.Magenta)
.size(200.dp, 30.dp)
.padding(5.dp)
.alpha(0.5f)
.clickable {
// Called when Text clicked
}
)
Hello Compose
This work is licensed under the Apache 2.0 License
Box(Modifier.size(150.dp)) {
Text("Hello Compose")
}
Hello
Compose
This work is licensed under the Apache 2.0 License
Box(Modifier.size(150.dp)) {
Text(
"Hello Compose!",
Modifier.align(
Alignment.BottomEnd
)
)
}
Hello
Compose
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row(...) {
Image(answer.image)
Text(answer.text)
RadioButton(/* … */)
}
}
Desired
Current
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row(
Modifier.fillMaxWidth(),
/* ... */
) {
Image(answer.image)
Text(answer.text)
RadioButton(/* ... */)
}
}
Desired
Current
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Row(
Modifier.fillMaxWidth()
.padding(16.dp),
/* ... */
) {
Image(answer.image)
Text(answer.text)
RadioButton(/* ... */)
}
}
Desired
Current
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Surface(
border = BorderStroke(
1.dp,
MaterialTheme.colorScheme.outline
),
shape = MaterialTheme.shapes.small
) {
Row(/* ... */) { }
}
}
Desired
Current
goo.gle/compose-modifiers
goo.gle/compose-modifiers-
list
This work is licensed under the Apache 2.0 License
@Composable
fun SurveyAnswer(answer: Answer) {
Surface(
border = BorderStroke(
1.dp,
MaterialTheme.colorScheme.outline
),
shape = MaterialTheme.shapes.small
) {
Row(Modifier.fillMaxWidth().padding(16.dp)) {
Image(answer.image)
Text(answer.text)
RadioButton(/* … */)
}
}
}
This work is licensed under the Apache 2.0 License
Compose Tooling
This work is licensed under the Apache 2.0 License
Live demo!

Compose Camp - Jetpack Compose for Android Developers Introduction Session Deck.pdf

  • 1.
    This work islicensed under the Apache 2.0 License Jetpack Compose for Android Developers
  • 2.
    This work islicensed under the Apache 2.0 License Whiston Borja Android Developer Camp leaders
  • 3.
    This work islicensed under the Apache 2.0 License ● Thinking in Compose ● Composable functions ● Compose toolkit ● Tooling Agenda
  • 4.
    This work islicensed under the Apache 2.0 License Thinking in Compose
  • 5.
    This work islicensed under the Apache 2.0 License Construct UI by describing what, not how.
  • 6.
    This work islicensed under the Apache 2.0 License goo.gle/compose-samples
  • 7.
    This work islicensed under the Apache 2.0 License
  • 8.
    This work islicensed under the Apache 2.0 License Survey answer Image Text Radio button
  • 9.
    This work islicensed under the Apache 2.0 License <LinearLayout android:orientation=“horizontal” > <ImageView android:id=”@+id/answer_image” ... /> <TextView android:id=”@+id/answer_text” ... /> <RadioButton android:id=”@+id/answer_radio_button” ... /> </LinearLayout> <!-- survey_answer.xml -->
  • 10.
    This work islicensed under the Apache 2.0 License class SurveyQuestionActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val image = findViewById(R.id.answer_image) val text = findViewById(R.id.answer_text) val radioButton = findViewById(R.id.answer_radio_button) // ... } } // SurveyQuestionActivity.kt
  • 11.
    This work islicensed under the Apache 2.0 License class SurveyQuestionActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { // ... image.setImage(...) text.setText(...) // ... } } // SurveyQuestionActivity.kt
  • 12.
    This work islicensed under the Apache 2.0 License
  • 13.
    This work islicensed under the Apache 2.0 License
  • 14.
    This work islicensed under the Apache 2.0 License
  • 15.
    This work islicensed under the Apache 2.0 License
  • 16.
    This work islicensed under the Apache 2.0 License
  • 17.
    This work islicensed under the Apache 2.0 License Survey answer Image Text Radio button
  • 18.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(false, onClick = { /* … */ }) } } // SurveyAnswer.kt
  • 19.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(false, onClick = { /* … */ }) } } // SurveyAnswer.kt
  • 20.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(false, onClick = { /* … */ }) } } // SurveyAnswer.kt
  • 21.
    This work islicensed under the Apache 2.0 License Construct UI by describing what, not how.
  • 22.
    This work islicensed under the Apache 2.0 License Event handler UI element onClick()
  • 23.
    This work islicensed under the Apache 2.0 License UI State
  • 24.
    This work islicensed under the Apache 2.0 License UI 2 State 2
  • 25.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { / * ... */ var selected: Boolean = // ... RadioButton(selected, onClick = { /* … */ }) } } // SurveyAnswer.kt
  • 26.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { / * ... */ var selected: Boolean = // ... RadioButton(selected, onClick = { selected = !selected }) } } // SurveyAnswer.kt
  • 27.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { / * ... */ var selected: Boolean = // ... RadioButton(selected, onClick = { selected = !selected }) } } // SurveyAnswer.kt
  • 28.
    Describe what, nothow UI elements are functions State controls UI Events control State 1 2 3 4
  • 29.
    This work islicensed under the Apache 2.0 License Composable functions
  • 30.
    This work islicensed under the Apache 2.0 License goo.gle/compose-samples
  • 31.
    This work islicensed under the Apache 2.0 License
  • 32.
    This work islicensed under the Apache 2.0 License // SurveyAnswer.kt @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(false, onClick = { /* … */ }) } }
  • 33.
    This work islicensed under the Apache 2.0 License // SurveyAnswer.kt @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(false, onClick = { /* … */ }) } }
  • 34.
    This work islicensed under the Apache 2.0 License // SurveyAnswer.kt @Composable fun SurveyAnswer(answer: Answer) { /* … */ } @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> SurveyAnswer(answer = answer) } } }
  • 35.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> SurveyAnswer(answer = answer) } } }
  • 36.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> SurveyAnswer(answer = answer) } } }
  • 37.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt
  • 38.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> // Can’t do this!! val answer = SurveyAnswer(answer = answer) } } }
  • 39.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> SurveyAnswer(answer = answer) } } }
  • 40.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { if (answers.isEmpty()) { Text(“There are no answers to choose from!”) } else { answers.forEach { answer -> SurveyAnswer(answer = answer) } } } }
  • 41.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { // Don’t do this! There shouldn’t be side-effects SurveyApp.didShowSingleChoiceQuestion = true Column { if (answers.isEmpty()) { /* ... */ } else { /* ... */ } } }
  • 42.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { // Fast and no side-effects Column { if (answers.isEmpty()) { /* ... */ } else { /* ... */ } } }
  • 43.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { Column { answers.forEach { answer -> SurveyAnswer(answer = answer) } } }
  • 44.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 45.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 46.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 47.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: Answer? = null answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 48.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: Answer? = null answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 49.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: MutableState<Answer?> = mutableStateOf(null) answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 50.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: MutableState<Answer?> = mutableStateOf(null) answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = false, ) } }
  • 51.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: MutableState<Answer?> = mutableStateOf(null) answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer.state == answer), ) } }
  • 52.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: MutableState<Answer?> = remember { mutableStateOf(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer.state == answer), ) } }
  • 53.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: MutableState<Answer?> = rememberSaveable { mutableStateOf(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer.state == answer), ) } }
  • 54.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: Answer? by rememberSaveable { mutableStateOf(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer.state == answer), ) } }
  • 55.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: Answer? by rememberSaveable { mutableStateOf(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer == answer), ) } }
  • 56.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { var selectedAnswer: Answer? by rememberSaveable { mutableStateOf(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer == answer), onAnswerSelected = { answer -> selectedAnswer = answer } ) } }
  • 57.
    This work islicensed under the Apache 2.0 License Event handler UI element event state Events change State
  • 58.
    This work islicensed under the Apache 2.0 License Event handler UI element onAnswerSelecte d answer Events change State
  • 59.
    This work islicensed under the Apache 2.0 License // SingleChoiceQuestion.kt @Composable fun SingleChoiceQuestion(answers: List<Answer>) { val selectedAnswer: Answer? by rememberSaveable { mutableStateOf<Answer>(null) } answers.forEach { answer -> SurveyAnswer( answer = answer, isSelected = (selectedAnswer == answer), onAnswerSelected = { answer -> selectedAnswer = answer } ) } }
  • 60.
    This work islicensed under the Apache 2.0 License Composable functions can execute in any order.
  • 61.
    This work islicensed under the Apache 2.0 License // ButtonRow.kt @Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
  • 62.
    This work islicensed under the Apache 2.0 License Composable functions can run in parallel.
  • 63.
    This work islicensed under the Apache 2.0 License @Composable fun ListComposable(myList: List<String>) { Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") } } Text("Count: ${myList.size}") } } // ListComposable.kt
  • 64.
    This work islicensed under the Apache 2.0 License @Composable fun ListWithBug(myList: List<String>) { var items = 0 Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item”) items++ // Avoid! Side-effect of the column recomposing. } } Text("Count: $items") } } // ListComposable.kt
  • 65.
    This work islicensed under the Apache 2.0 License Recomposition skips as much as possible.
  • 66.
    This work islicensed under the Apache 2.0 License @Composable fun GreetingScreen(name: String) { Column { Header() Greeting(name = name) Footer() } } // GreenScreen.kt
  • 67.
    This work islicensed under the Apache 2.0 License Recomposition is optimistic.
  • 68.
    This work islicensed under the Apache 2.0 License Composable functions might run frequently.
  • 69.
    This work islicensed under the Apache 2.0 License Summary Create composables using the @Composable annotation It’s quick & easy to create composables Composables accept parameters Use MutableState and remember Composables should be side-effect free
  • 70.
    This work islicensed under the Apache 2.0 License Composables can: Execute in any order Run in parallel Be skipped Run frequently 1 2 3 4
  • 71.
    This work islicensed under the Apache 2.0 License Compose Toolkit
  • 72.
    This work islicensed under the Apache 2.0 License goo.gle/compose-samples
  • 73.
    This work islicensed under the Apache 2.0 License
  • 74.
    This work islicensed under the Apache 2.0 License
  • 75.
    This work islicensed under the Apache 2.0 License MaterialTheme( colorScheme = MyAppsColorScheme, typography = MyAppsTypography, shapes = MyAppsShapes ) { // Content goes here }
  • 76.
    This work islicensed under the Apache 2.0 License
  • 77.
    This work islicensed under the Apache 2.0 License
  • 78.
    This work islicensed under the Apache 2.0 License
  • 79.
    This work islicensed under the Apache 2.0 License
  • 80.
    This work islicensed under the Apache 2.0 License
  • 81.
    This work islicensed under the Apache 2.0 License Scaffold( topBar = { SmallTopAppBar(/* ... */) }, floatingActionButtonPosition = FabPosition.End, floatingActionButton = { FloatingActionButton(/* ... */) }, content = { /* ... */ } )
  • 82.
    This work islicensed under the Apache 2.0 License SurveyTopAppBa r SurveyBottomBa r Question
  • 83.
    This work islicensed under the Apache 2.0 License
  • 84.
    This work islicensed under the Apache 2.0 License
  • 85.
    This work islicensed under the Apache 2.0 License
  • 86.
    This work islicensed under the Apache 2.0 License
  • 87.
    This work islicensed under the Apache 2.0 License
  • 88.
    This work islicensed under the Apache 2.0 License Surface { Text("Hello Compose") } Hello Compose
  • 89.
    This work islicensed under the Apache 2.0 License Surface( color = MaterialTheme.colorScheme.primary, ) { Text("Hello Compose") } Hello Compose
  • 90.
    This work islicensed under the Apache 2.0 License Surface( color = MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(8.dp), ) { Text("Hello Compose") } Hello Compose
  • 91.
    This work islicensed under the Apache 2.0 License Surface( color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(8.dp), border = BorderStroke(2.dp, MaterialTheme.colorScheme.outline ) ) { Text("Hello Compose") } Hello Compose
  • 92.
    This work islicensed under the Apache 2.0 License Surface( color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(8.dp), border = BorderStroke(2.dp, MaterialTheme.colorScheme.surfaceVariant ), shadowElevation = 8.dp, tonalElevation = 8.dp, ) { Text("Hello Compose") } Hello Compose
  • 93.
    This work islicensed under the Apache 2.0 License
  • 94.
    This work islicensed under the Apache 2.0 License
  • 95.
  • 96.
    This work islicensed under the Apache 2.0 License Standard layouts
  • 97.
    This work islicensed under the Apache 2.0 License Row { Component1() Component2() Component3() } 1 2 3 Row
  • 98.
    This work islicensed under the Apache 2.0 License 1 2 3 Column Column { Component1() Component2() Component3() }
  • 99.
    This work islicensed under the Apache 2.0 License 2 1 3 Box Box { Component1() Component2() Component3() }
  • 100.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row { Image(answer.image) Text(answer.text) RadioButton(/* … */) } }
  • 101.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row( verticalAlignment = Alignment.CenterVertically ) { /* ... */ } }
  • 102.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { /* ... */ } }
  • 103.
  • 104.
    This work islicensed under the Apache 2.0 License Modifiers
  • 105.
    This work islicensed under the Apache 2.0 License Text("Hello Compose") Hello Compose
  • 106.
    This work islicensed under the Apache 2.0 License Text( "Hello Compose!", Modifier.background(Color.Magenta) ) Hello Compose
  • 107.
    This work islicensed under the Apache 2.0 License Text( "Hello Compose!", Modifier.background(Color.Magenta) .size(200.dp, 30.dp) ) Hello Compose
  • 108.
    This work islicensed under the Apache 2.0 License Text( "Hello Compose!", Modifier.background(Color.Magenta) .size(200.dp, 30.dp) .padding(5.dp) ) Hello Compose
  • 109.
    This work islicensed under the Apache 2.0 License Text( "Hello Compose!", Modifier.background(Color.Magenta) .size(200.dp, 30.dp) .padding(5.dp) .alpha(0.5f) ) Hello Compose
  • 110.
    This work islicensed under the Apache 2.0 License Text( "Hello Compose!", Modifier.background(Color.Magenta) .size(200.dp, 30.dp) .padding(5.dp) .alpha(0.5f) .clickable { // Called when Text clicked } ) Hello Compose
  • 111.
    This work islicensed under the Apache 2.0 License Box(Modifier.size(150.dp)) { Text("Hello Compose") } Hello Compose
  • 112.
    This work islicensed under the Apache 2.0 License Box(Modifier.size(150.dp)) { Text( "Hello Compose!", Modifier.align( Alignment.BottomEnd ) ) } Hello Compose
  • 113.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row(...) { Image(answer.image) Text(answer.text) RadioButton(/* … */) } } Desired Current
  • 114.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row( Modifier.fillMaxWidth(), /* ... */ ) { Image(answer.image) Text(answer.text) RadioButton(/* ... */) } } Desired Current
  • 115.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Row( Modifier.fillMaxWidth() .padding(16.dp), /* ... */ ) { Image(answer.image) Text(answer.text) RadioButton(/* ... */) } } Desired Current
  • 116.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Surface( border = BorderStroke( 1.dp, MaterialTheme.colorScheme.outline ), shape = MaterialTheme.shapes.small ) { Row(/* ... */) { } } } Desired Current
  • 117.
  • 118.
    This work islicensed under the Apache 2.0 License @Composable fun SurveyAnswer(answer: Answer) { Surface( border = BorderStroke( 1.dp, MaterialTheme.colorScheme.outline ), shape = MaterialTheme.shapes.small ) { Row(Modifier.fillMaxWidth().padding(16.dp)) { Image(answer.image) Text(answer.text) RadioButton(/* … */) } } }
  • 119.
    This work islicensed under the Apache 2.0 License Compose Tooling
  • 120.
    This work islicensed under the Apache 2.0 License Live demo!