SlideShare a Scribd company logo
Jetpack
Compose
a new way to implement UI on Android
Nelson Glaube
r

@nglauber
Jetpack Compose is a
modern declarative UI
Toolkit to simplify and
accelerate native Android
UI development with less
code, powe
rf
ul tools, and
intuitive Kotlin APIs.
Imperative UI x Declarative UI
• In Imperative UI, an UI entity is fully de
fi
ned and then it is updated using
public methods and/or prope
rt
ies (e.g: Android View class).


• In Declarative UI, the UI and its state is de
fi
ned together and a
framework has the responsibility to update this state (which will cause
the UI re
fl
ects the changes automatically).
Motivation
• It’s not easy (or simple) to create a custom view…


• Current toolkit was created in 2008, but UIs are much more complex
nowadays…


• Declarative UI approach becomes popular among mobile developers
thanks to frameworks like React Native, Swi
ft
UI and Flu
tt
er.
Jetpack Compose
• A new way of thinking the UI development: components over screens.


• Compatible with existing Android apps, so you can adopt it progressively.


•
⚠︎
Currently in Beta stage! Don’t use it in production (yet)!
Ge
tt
ing sta
rt
ed
with Compose
Android Studio 4.2
(Preview)
Compose Preview
Interactive Mode
Launch
Composable
@Preview
setContent
class MainActivity : ComponentActivity()
{

override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState
)

setContent
{

MyAppTheme
{

Surface(color = MaterialTheme.colors.background)
{

Greeting("Android"
)

}

}

}

}

}

@Composabl
e

fun Greeting(name: String)
{

Text(text = "Hello $name!"
)

}
setContent
class MainActivity : ComponentActivity()
{

override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState
)

setContent
{

MyAppTheme
{

Surface(color = MaterialTheme.colors.background)
{

Greeting("Android"
)

}

}

}

}

}

@Composabl
e

fun Greeting(name: String)
{

Text(text = "Hello $name!"
)

}
setContent
class MainActivity : ComponentActivity()
{

override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState
)

setContent
{

MyAppTheme
{

Surface(color = MaterialTheme.colors.background)
{

Greeting("Android"
)

}

}

}

}

}

@Composabl
e

fun Greeting(name: String)
{

Text(text = "Hello $name!"
)

}
setContent
class MainActivity : ComponentActivity()
{

override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState
)

setContent
{

MyAppTheme
{

Surface(color = MaterialTheme.colors.background)
{

Greeting("Android"
)

}

}

}

}

}

@Composabl
e

fun Greeting(name: String)
{

Text(text = "Hello $name!"
)

}
setContent
class MainActivity : ComponentActivity()
{

override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState
)

setContent
{

MyAppTheme
{

Surface(color = MaterialTheme.colors.background)
{

Greeting("Android"
)

}

}

}

}

}

@Composabl
e

fun Greeting(name: String)
{

Text(stringResource(R.string.hello, name)
)

}
Material Theme
• De
fi
ne application’s theme with its respective colors, fonts, shapes, …


• O
ft
en is the root element of the screen (but you can nested themes).
setContent {


MyAppTheme {


Greeting("Android")


}


}
Material Theme
@Composable


fun MyAppTheme(


darkTheme: Boolean = isSystemInDarkTheme(),


content: @Composable () -> Unit) {


val colors = if (darkTheme) {


DarkColorPalette


} else {


LightColorPalette


}


MaterialTheme(


colors = colors,


typography = Typography,


shapes = Shapes,


content = content


)


}


private val DarkColorPalette =


darkColors(


primary = Purple200,


primaryVariant = Purple700,


secondary = Teal200


)


private val LightColorPalette =


lightColors(


primary = Purple500,


primaryVariant = Purple700,


secondary = Teal200


)
Modi
fi
ers
• Decorate an element


• Provide layout parameters


• Assign behavior


• They’re chained and the order is signi
fi
cant!
val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp)


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp)


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp)


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp)


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
val shape = RoundedCornerShape(8.dp)


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
val shape = CircleShape


Text(


text = "Text 1",


style = TextStyle(


color = Color.White,


fontWeight = FontWeight.Bold,


textAlign = TextAlign.Center),


modifier = Modifier.fillMaxWidth()


.padding(16.dp)


.border(2.dp, MaterialTheme.colors.secondary, shape)


.padding(1.dp)


.background(MaterialTheme.colors.primary, shape)


.clickable(onClick = {


// Click event


})


.padding(16.dp)


)
Layouts
Column Row Box Constraint


Layout
Box(modifier = Modifier.fillMaxWidth()) {


Column(


modifier = Modifier


.padding(16.dp)


.fillMaxWidth()


) {


Text("Column Text 1")


Text("Column Text 2")


Row(


modifier = Modifier.fillMaxWidth(),


horizontalArrangement = Arrangement.SpaceEvenly


) {


Text(text = "Row Text 1")


Text(text = "Row Text 2")


}


}


Text(


"Stack Text",


modifier = Modifier


.align(Alignment.TopEnd)


.padding(end = 16.dp, top = 16.dp)


)


}
Box(modifier = Modifier.fillMaxWidth()) {


Column(


modifier = Modifier


.padding(16.dp)


.fillMaxWidth()


) {


Text("Column Text 1")


Text("Column Text 2")


Row(


modifier = Modifier.fillMaxWidth(),


horizontalArrangement = Arrangement.SpaceEvenly


) {


Text(text = "Row Text 1")


Text(text = "Row Text 2")


}


}


Text(


"Stack Text",


modifier = Modifier


.align(Alignment.TopEnd)


.padding(end = 16.dp, top = 16.dp)


)


}
Box(modifier = Modifier.fillMaxWidth()) {


Column(


modifier = Modifier


.padding(16.dp)


.fillMaxWidth()


) {


Text("Column Text 1")


Text("Column Text 2")


Row(


modifier = Modifier.fillMaxWidth(),


horizontalArrangement = Arrangement.SpaceEvenly


) {


Text(text = "Row Text 1")


Text(text = "Row Text 2")


}


}


Text(


"Stack Text",


modifier = Modifier


.align(Alignment.TopEnd)


.padding(end = 16.dp, top = 16.dp)


)


}
Box(modifier = Modifier.fillMaxWidth()) {


Column(


modifier = Modifier


.padding(16.dp)


.fillMaxWidth()


) {


Text("Column Text 1")


Text("Column Text 2")


Row(


modifier = Modifier.fillMaxWidth(),


horizontalArrangement = Arrangement.SpaceEvenly


) {


Text(text = "Row Text 1")


Text(text = "Row Text 2")


}


}


Text(


"Stack Text",


modifier = Modifier


.align(Alignment.TopEnd)


.padding(end = 16.dp, top = 16.dp)


)


}
ConstraintLayout
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha05
"
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
👇
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
👇
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
👇
ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) {


val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs()


Text("User registration", modifier = Modifier.constrainAs(text1Ref) {


top.linkTo(parent.top)


centerHorizontallyTo(parent)


})


TextField(modifier = Modifier.padding(top = 8.dp)


.constrainAs(edit1Ref) {


start.linkTo(parent.start)


end.linkTo(parent.end)


top.linkTo(text1Ref.bottom)


})


Button(onClick = {}, modifier = Modifier.padding(top = 8.dp)


.constrainAs(btn1Ref) {


end.linkTo(edit1Ref.end)


top.linkTo(edit1Ref.bottom)


}


)


TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp)


.constrainAs(btn2Ref) {


end.linkTo(btn1Ref.start)


baseline.linkTo(btn1Ref.baseline)


}


)


}
👇
More
components…
Bu
tt
on
Button(onClick = {}) {


Text("Button")


}


OutlinedButton(onClick = {}) {


Text("OutlinedButton")


}


TextButton(onClick = {}) {


Text("TextButton")


}
Bu
tt
on
Button(onClick = {})
{

if (isLoading)
{

CircularProgressIndicator(color = Color.White
)

} else
{

Text("Button"
)

}

}
Image
Image
(

painterResource(R.drawable.recife)
,

contentDescription = null
,

contentScale = ContentScale.FillHeigh
t

)
Image
(

painterResource(R.drawable.ic_android_orange)
,

contentDescription = null
,

contentScale = ContentScale.Fit
,

colorFilter = ColorFilter.tint(Color.Cyan
)

)
• Window Insets


• System UI (status and navigation bars
colors)


• AppCompat Theme Adapter


• ViewPager like
• Flexbox layout


• Swipe to refresh


• Image loading (Glide and Coil)


https://github.com/google/accompanist
Image from the network
Image
(

rememberCoilPainter
(

request = "https://img.com/img.jpg”
,

)
,

contentDescription = null
,

modifier = Modifier.size(50.dp, 50.dp
)

)
Image
(

rememberGlidePainter
(

request = "https://img.com/img.jpg”
,

)
,

contentDescription = null
,

modifier = Modifier.size(50.dp, 50.dp
)

)
Column + Scroll
Column(modifier = Modifie
r

.verticalScroll(rememberScrollState()
)

)
{

for (i in 0..200)
{

Text
(

"Item: $i"
,

modifier = Modifie
r

.padding(8.dp
)

.fillMaxWidth(
)

)

}

}
Row + Scroll
Row(modifier = Modifie
r

.horizontalScroll(rememberScrollState()
)

)
{

for (i in 0..200)
{

Text
(

"Item: $i"
,

modifier = Modifie
r

.padding(8.dp
)

)

}

}
Lists in current toolkit
• De
fi
ne a layout
fi
le for each item of the list


• Create an adapter subclass (view holder, get count, in
fl
ate view, …)


• Declare a RecyclerView/ListView in the screen’s XML
fi
le


• Set up everything in your activity/fragment


• What about you need a header and/or a footer?
🤦
List in Compose
@Composabl
e

fun UserListScreen(users: List<User>)
{

LazyColumn
(

modifier = Modifier.fillMaxSize())
{

item
{

Text("Header"
,

Modifier.fillMaxWidth().padding(8.dp
)

)

}

items(users) { user -
>

Text("${user.name} - ${user.age}"
,

Modifier.fillMaxWidth().padding(8.dp
)

)

}

}

}
List in Compose (with index)
@Composabl
e

fun UserListScreen(users: List<User>)
{

LazyColumn
(

modifier = Modifier.fillMaxSize())
{

item
{

Text("Header"
,

Modifier.fillMaxWidth().padding(8.dp
)

)

}

itemsIndexed(users) { index, user -
>

Text("${user.name} - ${user.age}"
,

Modifier.fillMaxWidth().padding(8.dp
)

)

}

}

}
Sca
ff
old
Scaffold(


topBar = {...},


floatingActionButton = {...},


bottomBar = {...}


) {...}
TopAppBar
(

title = { Text(text = "Compose") }
,

backgroundColor = MaterialTheme.colors.primary
,

contentColor = Color.Yellow
,

actions =
{

IconButton(onClick = {})
{

Icon(Icons.Default.Search, "Search"
)

}

IconButton
(

onClick = { …
}

)
{

Icon(Icons.Filled.MoreVert, "More"
)

DropdownMenu(…
)

}
}

)
FloatingActionButton
(

onClick = { … }
,

backgroundColor = Color.Red
,

contentColor = Color.Whit
e

)
{

Icon(Icons.Filled.Add, "Add"
)

}
BottomAppBar(


backgroundColor = MaterialTheme.colors.primary,


content = {


BottomNavigationItem(


icon = { Icon(Icons.Filled.Home) },


selected = selectedTab == 0,


onClick = { selectedTab = 0 },


selectedContentColor = Color.White,


unselectedContentColor = Color.DarkGray,


label = { Text(text = "Home") }


)


BottomNavigationItem(…)


}


)
BottomAppBar(


backgroundColor = MaterialTheme.colors.primary,


content = {


BottomNavigationItem(


icon = { Icon(Icons.Filled.Home) },


selected = selectedTab == 0,


onClick = { selectedTab = 0 },


selectedContentColor = Color.White,


unselectedContentColor = Color.DarkGray,


label = { Text(text = "Home") }


)


BottomNavigationItem(…)


}


)
State
• State in an app is any value that can change over time. 


• Component is updated when state has changed
var nameState by remember { mutableStateOf("") }
TextField
(

value = nameState
,

label = { Text("Name") }
,

onValueChange = { s: String -
>

nameState =
s

}

)
State
data class Score
(

var team: String
,

var score: In
t

)
State
class Score
(

team: String
,

score: In
t

)
{

var team by mutableStateOf(team
)

var score by mutableStateOf(score)
}
class Score
(

team: String
,

score: In
t

)
{

var team by mutableStateOf(team
)

var score by mutableStateOf(score)
}
@Composabl
e

fun TeamScore(score: Score)
{

Column(horizontalAlignment = Alignment.CenterHorizontally)
{

Text(text = score.team, style = MaterialTheme.typography.h6
)

Button
(

content = { Text("+") }
,

onClick = { score.score += 1
}

)

Text(text = score.score.toString(), style = MaterialTheme.typography.h5
)

Button
(

content = { Text("-") }
,

onClick = { score.score = max(score.score - 1, 0)
}

)

}

}
@Composabl
e

fun ScoreScreen(homeScore: Score, visitorScore: Score)
{

Column
(

modifier = Modifier.fillMaxSize()
,

verticalArrangement = Arrangement.Center
,

horizontalAlignment = Alignment.CenterHorizontall
y

)
{

Row
{

TeamScore(score = homeScore
)

Text(text = "x"
,

modifier = Modifier.padding(horizontal = 8.dp)
,

style = MaterialTheme.typography.h6
)

TeamScore(score = visitorScore
)

}

OutlinedButton
(

modifier = Modifier.padding(top = 16.dp)
,

content = { Text("Reset") }
,

onClick =
{

homeScore.score =
0

visitorScore.score =
0

}

)

}

}
Compose in your
MVVM app
Observing state
• LiveData.observeAsState


• Flow.collectAsState


• Observable.subscribeAsState
View Model
UI
state event
LiveData
@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) {
val users by usersLiveData.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
onSaveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = onDeleteUser
)

}

}
LiveData
@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) {
val users by usersLiveData.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
onSaveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = onDeleteUser
)

}

}
LiveData
@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) {
val users by usersLiveData.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
onSaveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = onDeleteUser
)

}

}
LiveData
@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) {
val users by usersLiveData.observeAsState(
)

Column(modifier = Modifier.fillMaxSize()) {
InputPanel(currentUser, onInsertUser = { user ->
onSaveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = onDeleteUser
)

}

}
LiveData
@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) {
val users by usersLiveData.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
onSaveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = onDeleteUser
)

}

}
LiveData
UserScreen
(

usersLiveData = viewModel.allUsers
,

onSaveUser = { user ->
 

viewModel.saveUser(user
)

}
,

onDeleteUser = { user -
>

viewModel.deleteUser(user
)

}

)

@Composabl
e

fun UserScreen
(

usersLiveData: LiveData<List<UserBinding>>
,

onSaveUser: (UserBinding) -> Unit
,

onDeleteUser: (UserBinding) -> Uni
t

) { …
}
ViewModel + LiveData + Compose
@Composabl
e

fun UserScreen
(

viewModel: UsersViewMode
l

) {
val users by viewModel.allUsers.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
viewModel.saveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = { user -
>

viewModel.deleteUser(user
)

}
)

}

}
ViewModel + LiveData + Compose
@Composabl
e

fun UserScreen()
{

val viewModel: UsersViewModel = viewModel()
val users by viewModel.allUsers.observeAsState(
)

Column(modifier = Modifier.fillMaxSize())
{

InputPanel(currentUser, onInsertUser = { user ->
viewModel.saveUser(user
)

}
)

UserList
(

users = users ?: emptyList()
,

onDeleteUser = { user -
>

viewModel.deleteUser(user
)

}
)

}

}

implementation "androidx.lifecycle:lifecycle-viewmodel-compose:<version>
"
Interoperability
In fragments…
class MyFragment: Fragment()
{

override fun onCreateView
(

inflater: LayoutInflater
,

container: ViewGroup?
,

savedInstanceState: Bundle
?

): View?
{

return ComposeView(requireContext()).apply
{

setContent
{

AppTheme
{

YourComposable(
)

}

}

}

}

}
In fragments…
class MyFragment: Fragment()
{

override fun onCreateView
(

inflater: LayoutInflater
,

container: ViewGroup?
,

savedInstanceState: Bundle
?

): View?
{

return ComposeView(requireContext()).apply
{

setContent
{

AppTheme
{

YourComposable(
)

}

}

}

}

}
In layout
fi
les
<androidx.compose.ui.platform.ComposeVie
w

android:id="@+id/my_composable
"

android:layout_width="wrap_content
"

android:layout_height="wrap_content" /
>

findViewById<ComposeView>(R.id.my_composable).setContent
{

MaterialTheme
{

Surface
{

Text(text = "Hello!"
)

}

}

}
ComposeView
class MyComposeVie
w

@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
:

AbstractComposeView(context, attrs)
{

@Composabl
e

override fun Content()
{

MyComposableFunction(
)

}

}

<br.com.nglauber.MyComposeVie
w

android:layout_width="match_parent
"

android:layout_height="match_parent"/
>
@Composabl
e

fun MyCalendar(onDateUpdate: (Date) -> Unit)
{

AndroidView
(

factory = { context: Context -
>

val view
=

LayoutInflater.from(context).inflate(R.layout.my_layout, null, false
)

val textView = view.findViewById<TextView>(R.id.txtDate
)

val calendarView = view.findViewById<CalendarView>(R.id.calendarView
)

calendarView?.setOnDateChangeListener { cv, year, month, day -
>

val date = Calendar.getInstance().apply
{

set(year, month, day
)

}.tim
e

textView?.text = date.toString(
)

onDateUpdate(date
)

}
vie
w

}
,

update = { view -
>

// Update vie
w

}

)

}
@Composabl
e

fun MyCalendar(onDateUpdate: (Date) -> Unit)
{

AndroidView(
factory = { context: Context -
>

val view
=

LayoutInflater.from(context).inflate(R.layout.my_layout, null, false
)

val textView = view.findViewById<TextView>(R.id.txtDate
)

val calendarView = view.findViewById<CalendarView>(R.id.calendarView
)

calendarView?.setOnDateChangeListener { cv, year, month, day -
>

val date = Calendar.getInstance().apply
{

set(year, month, day
)

}.tim
e

textView?.text = date.toString(
)

onDateUpdate(date
)

}
vie
w

}
,

update = { view -
>

// Update vie
w

}

)

}
@Composabl
e

fun MyCalendar(onDateUpdate: (Date) -> Unit)
{

AndroidView
(

factory = { context: Context -
>

val view
=

LayoutInflater.from(context).inflate(R.layout.my_layout, null, false
)

val textView = view.findViewById<TextView>(R.id.txtDate
)

val calendarView = view.findViewById<CalendarView>(R.id.calendarView
)

calendarView?.setOnDateChangeListener { cv, year, month, day -
>

val date = Calendar.getInstance().apply
{

set(year, month, day
)

}.tim
e

textView?.text = date.toString(
)

onDateUpdate(date
)

}
vie
w

},
update = { view -
>

// Update vie
w

}

)

}
AndroidViewBinding
android
{

..
.

viewBinding
{

enabled = tru
e

}

}
implementation "androidx.compose.ui:ui-viewbinding:$compose_version"
AndroidViewBinding(factory = MyBindingLayoutBinding::inflate)
{

textView.text = "My Text
"

seekBar.progress = 5
0

}
Resource
fi
les
• stringResources(R.string.your_string)


• dimensionResource(R.dimen.padding_small)


• colorResource(R.color.blue)


• …
On con
fi
g changes…
Unlike the current UI toolkit, the state is not saved automatically across
con
fi
guration changes.
var state by rememberSaveable
{

mutableStateOf("Compose!!!"
)

}
Coroutines
E
ff
ects
• LaunchedE
ff
ect


• DisposableE
ff
ect
LaunchedEffect(someKey)
{

// do something on launc
h

}
DisposableEffect(someKey)
{

// do something on launc
h

onDispose {
 

// Cleanu
p

}

}
Coroutines
LaunchedEffect launch a coroutine when
the composition is added and it is
automatically cancelled when the execution
leaves the composition.
@Composabl
e

fun MyComposable()
{

val welcomeMsg = remember { mutableStateOf("Initial")
}

LaunchedEffect(welcomeMsg)
{

val s = withContext(Dispatchers.IO)
{

delay(5_000
)

"Hello Compose!
"

}

welcomeMsg.value =
s

}

Text(text = welcomeMsg.value
)

}
Coroutines
rememberCoroutineScope returns the
associated CoroutineScope to a given
position of the composition. It should be used
to launch coroutines as response of callback
events
@Composabl
e

fun MyComposable()
{

val scope = rememberCoroutineScope(
)

val count = remember { mutableStateOf(0)
}

Text(text = "Current count: ${count.value}"
)

Button(onClick =
{

scope.launch {
 

for (i in 1..10)
{

withContext(Dispatchers.IO)
{

delay(1_000
)

}

count.value =
i

}

}

}, content = { Text("Start!") }
)

}
Learn more…
• Samples (goo.gle/compose-samples)


• Codelabs (goo.gle/compose-codelabs)


• Documentation (goo.gle/compose-docs)


• Issue Tracker (goo.gle/compose-feedback)


• Slack Channel (goo.gle/compose-slack)
Wrap up
• The way of Compose works seems very interesting, once it is following
the same modern paradigm of other UI toolkits.


• Compose is also available for desktop apps (alpha) and now for web
(preview)!


• Jetpack Compose is in beta stage (beta-06), so DON’T USE IN
PRODUCTION!


• Be prepared, because declarative is the new standard 😉
Thank you!
Nelson Glaube
r

@nglauber

More Related Content

What's hot

Jetpack Compose.pptx
Jetpack Compose.pptxJetpack Compose.pptx
Jetpack Compose.pptx
GDSCVJTI
 
Jetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning TourJetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning Tour
Matthew Clarke
 
Jetpack Compose - Android’s modern toolkit for building native UI
Jetpack Compose - Android’s modern toolkit for building native UIJetpack Compose - Android’s modern toolkit for building native UI
Jetpack Compose - Android’s modern toolkit for building native UI
Gilang Ramadhan
 
Kotlin Basics & Introduction to Jetpack Compose.pptx
Kotlin Basics & Introduction to Jetpack Compose.pptxKotlin Basics & Introduction to Jetpack Compose.pptx
Kotlin Basics & Introduction to Jetpack Compose.pptx
takshilkunadia
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
Nelson Glauber Leal
 
Modern app development with Jetpack Compose.pptx
Modern app development with Jetpack Compose.pptxModern app development with Jetpack Compose.pptx
Modern app development with Jetpack Compose.pptx
Md Shamsul Arafin Mahtab
 
Threading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
Threading Made Easy! A Busy Developer’s Guide to Kotlin CoroutinesThreading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
Threading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
Lauren Yew
 
Jetpack Compose.pdf
Jetpack Compose.pdfJetpack Compose.pdf
Jetpack Compose.pdf
SumirVats
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
Shaul Rosenzwieg
 
Angular - Chapter 7 - HTTP Services
Angular - Chapter 7 - HTTP ServicesAngular - Chapter 7 - HTTP Services
Angular - Chapter 7 - HTTP Services
WebStackAcademy
 
Coroutines in Kotlin
Coroutines in KotlinCoroutines in Kotlin
Coroutines in Kotlin
Alexey Soshin
 
Routing & Navigating Pages in Angular 2
Routing & Navigating Pages in Angular 2Routing & Navigating Pages in Angular 2
Routing & Navigating Pages in Angular 2
Knoldus Inc.
 
KMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and SwiftKMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and Swift
Commit University
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
Fabio Collini
 
Reactive state management with Jetpack Components
Reactive state management with Jetpack ComponentsReactive state management with Jetpack Components
Reactive state management with Jetpack Components
Gabor Varadi
 
Understanding iOS from an Android perspective
Understanding iOS from an Android perspectiveUnderstanding iOS from an Android perspective
Understanding iOS from an Android perspective
Lauren Yew
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of Signals
Coding Academy
 
Angular 6 Form Validation with Material
Angular 6 Form Validation with MaterialAngular 6 Form Validation with Material
Angular 6 Form Validation with Material
Malika Munaweera
 
Angular 14.pptx
Angular 14.pptxAngular 14.pptx
Angular 14.pptx
MohaNedGhawar
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
Dzmitry Naskou
 

What's hot (20)

Jetpack Compose.pptx
Jetpack Compose.pptxJetpack Compose.pptx
Jetpack Compose.pptx
 
Jetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning TourJetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning Tour
 
Jetpack Compose - Android’s modern toolkit for building native UI
Jetpack Compose - Android’s modern toolkit for building native UIJetpack Compose - Android’s modern toolkit for building native UI
Jetpack Compose - Android’s modern toolkit for building native UI
 
Kotlin Basics & Introduction to Jetpack Compose.pptx
Kotlin Basics & Introduction to Jetpack Compose.pptxKotlin Basics & Introduction to Jetpack Compose.pptx
Kotlin Basics & Introduction to Jetpack Compose.pptx
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
 
Modern app development with Jetpack Compose.pptx
Modern app development with Jetpack Compose.pptxModern app development with Jetpack Compose.pptx
Modern app development with Jetpack Compose.pptx
 
Threading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
Threading Made Easy! A Busy Developer’s Guide to Kotlin CoroutinesThreading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
Threading Made Easy! A Busy Developer’s Guide to Kotlin Coroutines
 
Jetpack Compose.pdf
Jetpack Compose.pdfJetpack Compose.pdf
Jetpack Compose.pdf
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Angular - Chapter 7 - HTTP Services
Angular - Chapter 7 - HTTP ServicesAngular - Chapter 7 - HTTP Services
Angular - Chapter 7 - HTTP Services
 
Coroutines in Kotlin
Coroutines in KotlinCoroutines in Kotlin
Coroutines in Kotlin
 
Routing & Navigating Pages in Angular 2
Routing & Navigating Pages in Angular 2Routing & Navigating Pages in Angular 2
Routing & Navigating Pages in Angular 2
 
KMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and SwiftKMM survival guide: how to tackle struggles between Kotlin and Swift
KMM survival guide: how to tackle struggles between Kotlin and Swift
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Reactive state management with Jetpack Components
Reactive state management with Jetpack ComponentsReactive state management with Jetpack Components
Reactive state management with Jetpack Components
 
Understanding iOS from an Android perspective
Understanding iOS from an Android perspectiveUnderstanding iOS from an Android perspective
Understanding iOS from an Android perspective
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of Signals
 
Angular 6 Form Validation with Material
Angular 6 Form Validation with MaterialAngular 6 Form Validation with Material
Angular 6 Form Validation with Material
 
Angular 14.pptx
Angular 14.pptxAngular 14.pptx
Angular 14.pptx
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
 

Similar to Android Jetpack Compose - Turkey 2021

compose_speaker_session.pdf
compose_speaker_session.pdfcompose_speaker_session.pdf
compose_speaker_session.pdf
AnkurAgarwal151093
 
Avoiding Pitfalls with Internationalization & Localization
Avoiding Pitfalls with Internationalization & LocalizationAvoiding Pitfalls with Internationalization & Localization
Avoiding Pitfalls with Internationalization & Localization
Logan Gauthier
 
Software Language Design & Engineering
Software Language Design & EngineeringSoftware Language Design & Engineering
Software Language Design & Engineering
Eelco Visser
 
Diving deep in compose.pdf
Diving deep in compose.pdfDiving deep in compose.pdf
Diving deep in compose.pdf
AnkurAgarwal151093
 
Jetpack Compose - Hands-on February 2020
Jetpack Compose - Hands-on February 2020Jetpack Compose - Hands-on February 2020
Jetpack Compose - Hands-on February 2020
Pedro Veloso
 
Notes netbeans
Notes netbeansNotes netbeans
Notes netbeans
poonamchopra7975
 
Js lw melbourne
Js lw melbourneJs lw melbourne
Js lw melbourne
Juliette Chevalier
 
Mobile Application Development class 007
Mobile Application Development class 007Mobile Application Development class 007
Mobile Application Development class 007
Dr. Mazin Mohamed alkathiri
 
Theme and style in Flutter
Theme and style in FlutterTheme and style in Flutter
Theme and style in Flutter
Cleveroad
 
Inside Flutter: Widgets, Elements, and RenderObjects
Inside Flutter: Widgets, Elements, and RenderObjectsInside Flutter: Widgets, Elements, and RenderObjects
Inside Flutter: Widgets, Elements, and RenderObjects
Hansol Lee
 
Software Language Design & Engineering: Mobl & Spoofax
Software Language Design & Engineering: Mobl & SpoofaxSoftware Language Design & Engineering: Mobl & Spoofax
Software Language Design & Engineering: Mobl & Spoofax
Eelco Visser
 
tL19 awt
tL19 awttL19 awt
tL19 awt
teach4uin
 
Hadoop MapReduce framework - Module 3
Hadoop MapReduce framework - Module 3Hadoop MapReduce framework - Module 3
Hadoop MapReduce framework - Module 3
Rohit Agrawal
 
JavaScript - Chapter 12 - Document Object Model
  JavaScript - Chapter 12 - Document Object Model  JavaScript - Chapter 12 - Document Object Model
JavaScript - Chapter 12 - Document Object Model
WebStackAcademy
 
05.Blend Expression, Transformation & Animation
05.Blend Expression, Transformation & Animation05.Blend Expression, Transformation & Animation
05.Blend Expression, Transformation & Animation
Nguyen Tuan
 
20230721_OKC_Meetup_MuleSoft.pptx
20230721_OKC_Meetup_MuleSoft.pptx20230721_OKC_Meetup_MuleSoft.pptx
20230721_OKC_Meetup_MuleSoft.pptx
DianeKesler1
 
WEB DEVELOPMENT
WEB DEVELOPMENTWEB DEVELOPMENT
WEB DEVELOPMENT
Gourav Kaushik
 
Compose Camp Day 3 PPT.pptx.pdf
Compose Camp Day 3 PPT.pptx.pdfCompose Camp Day 3 PPT.pptx.pdf
Compose Camp Day 3 PPT.pptx.pdf
METDSC
 
Windows phone and azure
Windows phone and azureWindows phone and azure
Windows phone and azure
★ Dovydas Navickas
 
What's great in Appcelerator Titanium 0.8
What's great in Appcelerator Titanium 0.8What's great in Appcelerator Titanium 0.8
What's great in Appcelerator Titanium 0.8
Jeff Haynie
 

Similar to Android Jetpack Compose - Turkey 2021 (20)

compose_speaker_session.pdf
compose_speaker_session.pdfcompose_speaker_session.pdf
compose_speaker_session.pdf
 
Avoiding Pitfalls with Internationalization & Localization
Avoiding Pitfalls with Internationalization & LocalizationAvoiding Pitfalls with Internationalization & Localization
Avoiding Pitfalls with Internationalization & Localization
 
Software Language Design & Engineering
Software Language Design & EngineeringSoftware Language Design & Engineering
Software Language Design & Engineering
 
Diving deep in compose.pdf
Diving deep in compose.pdfDiving deep in compose.pdf
Diving deep in compose.pdf
 
Jetpack Compose - Hands-on February 2020
Jetpack Compose - Hands-on February 2020Jetpack Compose - Hands-on February 2020
Jetpack Compose - Hands-on February 2020
 
Notes netbeans
Notes netbeansNotes netbeans
Notes netbeans
 
Js lw melbourne
Js lw melbourneJs lw melbourne
Js lw melbourne
 
Mobile Application Development class 007
Mobile Application Development class 007Mobile Application Development class 007
Mobile Application Development class 007
 
Theme and style in Flutter
Theme and style in FlutterTheme and style in Flutter
Theme and style in Flutter
 
Inside Flutter: Widgets, Elements, and RenderObjects
Inside Flutter: Widgets, Elements, and RenderObjectsInside Flutter: Widgets, Elements, and RenderObjects
Inside Flutter: Widgets, Elements, and RenderObjects
 
Software Language Design & Engineering: Mobl & Spoofax
Software Language Design & Engineering: Mobl & SpoofaxSoftware Language Design & Engineering: Mobl & Spoofax
Software Language Design & Engineering: Mobl & Spoofax
 
tL19 awt
tL19 awttL19 awt
tL19 awt
 
Hadoop MapReduce framework - Module 3
Hadoop MapReduce framework - Module 3Hadoop MapReduce framework - Module 3
Hadoop MapReduce framework - Module 3
 
JavaScript - Chapter 12 - Document Object Model
  JavaScript - Chapter 12 - Document Object Model  JavaScript - Chapter 12 - Document Object Model
JavaScript - Chapter 12 - Document Object Model
 
05.Blend Expression, Transformation & Animation
05.Blend Expression, Transformation & Animation05.Blend Expression, Transformation & Animation
05.Blend Expression, Transformation & Animation
 
20230721_OKC_Meetup_MuleSoft.pptx
20230721_OKC_Meetup_MuleSoft.pptx20230721_OKC_Meetup_MuleSoft.pptx
20230721_OKC_Meetup_MuleSoft.pptx
 
WEB DEVELOPMENT
WEB DEVELOPMENTWEB DEVELOPMENT
WEB DEVELOPMENT
 
Compose Camp Day 3 PPT.pptx.pdf
Compose Camp Day 3 PPT.pptx.pdfCompose Camp Day 3 PPT.pptx.pdf
Compose Camp Day 3 PPT.pptx.pdf
 
Windows phone and azure
Windows phone and azureWindows phone and azure
Windows phone and azure
 
What's great in Appcelerator Titanium 0.8
What's great in Appcelerator Titanium 0.8What's great in Appcelerator Titanium 0.8
What's great in Appcelerator Titanium 0.8
 

More from Nelson Glauber Leal

Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
Nelson Glauber Leal
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
Nelson Glauber Leal
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
Nelson Glauber Leal
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
Nelson Glauber Leal
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
Nelson Glauber Leal
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
Nelson Glauber Leal
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Aplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e JetpackAplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e Jetpack
Nelson Glauber Leal
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
Nelson Glauber Leal
 
Aplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & JetpackAplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & Jetpack
Nelson Glauber Leal
 
Introdução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinIntrodução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com Kotlin
Nelson Glauber Leal
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
Nelson Glauber Leal
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
Nelson Glauber Leal
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
Nelson Glauber Leal
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
Nelson Glauber Leal
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
Nelson Glauber Leal
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
Nelson Glauber Leal
 

More from Nelson Glauber Leal (20)

Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
 
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & JetpackAplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
Aplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e JetpackAplicações Assíncronas no Android com Coroutines e Jetpack
Aplicações Assíncronas no Android com Coroutines e Jetpack
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
Aplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & JetpackAplicações assíncronas no Android com Coroutines & Jetpack
Aplicações assíncronas no Android com Coroutines & Jetpack
 
Introdução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com KotlinIntrodução ao Desenvolvimento Android com Kotlin
Introdução ao Desenvolvimento Android com Kotlin
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
 

Recently uploaded

Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
908dutch
 
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
87tomato
 
How To Fill Timesheet in TaskSprint: Quick Guide 2024
How To Fill Timesheet in TaskSprint: Quick Guide 2024How To Fill Timesheet in TaskSprint: Quick Guide 2024
How To Fill Timesheet in TaskSprint: Quick Guide 2024
TaskSprint | Employee Efficiency Software
 
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
shanihomely
 
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
Srinivas Dukka
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
neshakor5152
 
Hotel Management Software Development Company
Hotel Management Software Development CompanyHotel Management Software Development Company
Hotel Management Software Development Company
XongoLab Technologies LLP
 
Attendance Tracking From Paper To Digital
Attendance Tracking From Paper To DigitalAttendance Tracking From Paper To Digital
Attendance Tracking From Paper To Digital
Task Tracker
 
GT degree offer diploma Transcript
GT degree offer diploma TranscriptGT degree offer diploma Transcript
GT degree offer diploma Transcript
attueb
 
Artificial intelligence in customer services or chatbots
Artificial intelligence  in customer services or chatbotsArtificial intelligence  in customer services or chatbots
Artificial intelligence in customer services or chatbots
kayash1656
 
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
norina2645
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Aardwolf Security
 
Google ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learningGoogle ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learning
VishrutGoyani1
 
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Deliverybangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
sunilverma7884
 
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
josephinedrea942
 
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a seriesFolding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a series
Philip Schwarz
 
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to KnowThe Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
onemonitarsoftware
 
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
kiara pandey
 
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
902basic
 
Tour and travel website management in odoo,
Tour and travel website management in odoo,Tour and travel website management in odoo,
Tour and travel website management in odoo,
Axis Technolabs
 

Recently uploaded (20)

Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
 
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
 
How To Fill Timesheet in TaskSprint: Quick Guide 2024
How To Fill Timesheet in TaskSprint: Quick Guide 2024How To Fill Timesheet in TaskSprint: Quick Guide 2024
How To Fill Timesheet in TaskSprint: Quick Guide 2024
 
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
 
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
AWS DevOps-Tutorial CHANAKYA SRIYAN DUKKA.
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
 
Hotel Management Software Development Company
Hotel Management Software Development CompanyHotel Management Software Development Company
Hotel Management Software Development Company
 
Attendance Tracking From Paper To Digital
Attendance Tracking From Paper To DigitalAttendance Tracking From Paper To Digital
Attendance Tracking From Paper To Digital
 
GT degree offer diploma Transcript
GT degree offer diploma TranscriptGT degree offer diploma Transcript
GT degree offer diploma Transcript
 
Artificial intelligence in customer services or chatbots
Artificial intelligence  in customer services or chatbotsArtificial intelligence  in customer services or chatbots
Artificial intelligence in customer services or chatbots
 
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
Celebrity Girls Call Mumbai 🛵🚡9910780858 💃 Choose Best And Top Girl Service A...
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
 
Google ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learningGoogle ML-Kit - Understanding on-device machine learning
Google ML-Kit - Understanding on-device machine learning
 
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Deliverybangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
 
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
HIRE A HACKER FOR CHEATING HUSBAND/WIFE)
 
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a seriesFolding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #7 - seventh in a series
 
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to KnowThe Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
 
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
 
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
Private Girls Call Navi Mumbai 🛵🚡9820252231 💃 Choose Best And Top Girl Servic...
 
Tour and travel website management in odoo,
Tour and travel website management in odoo,Tour and travel website management in odoo,
Tour and travel website management in odoo,
 

Android Jetpack Compose - Turkey 2021

  • 1. Jetpack Compose a new way to implement UI on Android Nelson Glaube r @nglauber
  • 2. Jetpack Compose is a modern declarative UI Toolkit to simplify and accelerate native Android UI development with less code, powe rf ul tools, and intuitive Kotlin APIs.
  • 3. Imperative UI x Declarative UI • In Imperative UI, an UI entity is fully de fi ned and then it is updated using public methods and/or prope rt ies (e.g: Android View class). • In Declarative UI, the UI and its state is de fi ned together and a framework has the responsibility to update this state (which will cause the UI re fl ects the changes automatically).
  • 4. Motivation • It’s not easy (or simple) to create a custom view… • Current toolkit was created in 2008, but UIs are much more complex nowadays… • Declarative UI approach becomes popular among mobile developers thanks to frameworks like React Native, Swi ft UI and Flu tt er.
  • 5. Jetpack Compose • A new way of thinking the UI development: components over screens. • Compatible with existing Android apps, so you can adopt it progressively. • ⚠︎ Currently in Beta stage! Don’t use it in production (yet)!
  • 9. setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState ) setContent { MyAppTheme { Surface(color = MaterialTheme.colors.background) { Greeting("Android" ) } } } } } @Composabl e fun Greeting(name: String) { Text(text = "Hello $name!" ) }
  • 10. setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState ) setContent { MyAppTheme { Surface(color = MaterialTheme.colors.background) { Greeting("Android" ) } } } } } @Composabl e fun Greeting(name: String) { Text(text = "Hello $name!" ) }
  • 11. setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState ) setContent { MyAppTheme { Surface(color = MaterialTheme.colors.background) { Greeting("Android" ) } } } } } @Composabl e fun Greeting(name: String) { Text(text = "Hello $name!" ) }
  • 12. setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState ) setContent { MyAppTheme { Surface(color = MaterialTheme.colors.background) { Greeting("Android" ) } } } } } @Composabl e fun Greeting(name: String) { Text(text = "Hello $name!" ) }
  • 13. setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState ) setContent { MyAppTheme { Surface(color = MaterialTheme.colors.background) { Greeting("Android" ) } } } } } @Composabl e fun Greeting(name: String) { Text(stringResource(R.string.hello, name) ) }
  • 14. Material Theme • De fi ne application’s theme with its respective colors, fonts, shapes, … • O ft en is the root element of the screen (but you can nested themes). setContent { MyAppTheme { Greeting("Android") } }
  • 15. Material Theme @Composable fun MyAppTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { val colors = if (darkTheme) { DarkColorPalette } else { LightColorPalette } MaterialTheme( colors = colors, typography = Typography, shapes = Shapes, content = content ) } private val DarkColorPalette = darkColors( primary = Purple200, primaryVariant = Purple700, secondary = Teal200 ) private val LightColorPalette = lightColors( primary = Purple500, primaryVariant = Purple700, secondary = Teal200 )
  • 16. Modi fi ers • Decorate an element • Provide layout parameters • Assign behavior • They’re chained and the order is signi fi cant!
  • 17. val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp) Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 18. val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp) Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 19. val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp) Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 20. val shape = CutCornerShape(topStart = 16.dp, bottomEnd = 16.dp) Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 21. val shape = RoundedCornerShape(8.dp) Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 22. val shape = CircleShape Text( text = "Text 1", style = TextStyle( color = Color.White, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center), modifier = Modifier.fillMaxWidth() .padding(16.dp) .border(2.dp, MaterialTheme.colors.secondary, shape) .padding(1.dp) .background(MaterialTheme.colors.primary, shape) .clickable(onClick = { // Click event }) .padding(16.dp) )
  • 23. Layouts Column Row Box Constraint 
 Layout
  • 24. Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier .padding(16.dp) .fillMaxWidth() ) { Text("Column Text 1") Text("Column Text 2") Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { Text(text = "Row Text 1") Text(text = "Row Text 2") } } Text( "Stack Text", modifier = Modifier .align(Alignment.TopEnd) .padding(end = 16.dp, top = 16.dp) ) }
  • 25. Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier .padding(16.dp) .fillMaxWidth() ) { Text("Column Text 1") Text("Column Text 2") Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { Text(text = "Row Text 1") Text(text = "Row Text 2") } } Text( "Stack Text", modifier = Modifier .align(Alignment.TopEnd) .padding(end = 16.dp, top = 16.dp) ) }
  • 26. Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier .padding(16.dp) .fillMaxWidth() ) { Text("Column Text 1") Text("Column Text 2") Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { Text(text = "Row Text 1") Text(text = "Row Text 2") } } Text( "Stack Text", modifier = Modifier .align(Alignment.TopEnd) .padding(end = 16.dp, top = 16.dp) ) }
  • 27. Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier .padding(16.dp) .fillMaxWidth() ) { Text("Column Text 1") Text("Column Text 2") Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { Text(text = "Row Text 1") Text(text = "Row Text 2") } } Text( "Stack Text", modifier = Modifier .align(Alignment.TopEnd) .padding(end = 16.dp, top = 16.dp) ) }
  • 29. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) }
  • 30. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) }
  • 31. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) } 👇
  • 32. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) } 👇
  • 33. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) } 👇
  • 34. ConstraintLayout(modifier = Modifier.fillMaxSize().padding(16.dp)) { val (text1Ref, edit1Ref, btn1Ref, btn2Ref) = createRefs() Text("User registration", modifier = Modifier.constrainAs(text1Ref) { top.linkTo(parent.top) centerHorizontallyTo(parent) }) TextField(modifier = Modifier.padding(top = 8.dp) .constrainAs(edit1Ref) { start.linkTo(parent.start) end.linkTo(parent.end) top.linkTo(text1Ref.bottom) }) Button(onClick = {}, modifier = Modifier.padding(top = 8.dp) .constrainAs(btn1Ref) { end.linkTo(edit1Ref.end) top.linkTo(edit1Ref.bottom) } ) TextButton(onClick = {}, modifier = Modifier.padding(end = 8.dp) .constrainAs(btn2Ref) { end.linkTo(btn1Ref.start) baseline.linkTo(btn1Ref.baseline) } ) } 👇
  • 36. Bu tt on Button(onClick = {}) { Text("Button") } OutlinedButton(onClick = {}) { Text("OutlinedButton") } TextButton(onClick = {}) { Text("TextButton") }
  • 37. Bu tt on Button(onClick = {}) { if (isLoading) { CircularProgressIndicator(color = Color.White ) } else { Text("Button" ) } }
  • 38. Image Image ( painterResource(R.drawable.recife) , contentDescription = null , contentScale = ContentScale.FillHeigh t ) Image ( painterResource(R.drawable.ic_android_orange) , contentDescription = null , contentScale = ContentScale.Fit , colorFilter = ColorFilter.tint(Color.Cyan ) )
  • 39. • Window Insets • System UI (status and navigation bars colors) • AppCompat Theme Adapter • ViewPager like • Flexbox layout • Swipe to refresh • Image loading (Glide and Coil) https://github.com/google/accompanist
  • 40. Image from the network Image ( rememberCoilPainter ( request = "https://img.com/img.jpg” , ) , contentDescription = null , modifier = Modifier.size(50.dp, 50.dp ) ) Image ( rememberGlidePainter ( request = "https://img.com/img.jpg” , ) , contentDescription = null , modifier = Modifier.size(50.dp, 50.dp ) )
  • 41. Column + Scroll Column(modifier = Modifie r .verticalScroll(rememberScrollState() ) ) { for (i in 0..200) { Text ( "Item: $i" , modifier = Modifie r .padding(8.dp ) .fillMaxWidth( ) ) } }
  • 42. Row + Scroll Row(modifier = Modifie r .horizontalScroll(rememberScrollState() ) ) { for (i in 0..200) { Text ( "Item: $i" , modifier = Modifie r .padding(8.dp ) ) } }
  • 43. Lists in current toolkit • De fi ne a layout fi le for each item of the list • Create an adapter subclass (view holder, get count, in fl ate view, …) • Declare a RecyclerView/ListView in the screen’s XML fi le • Set up everything in your activity/fragment • What about you need a header and/or a footer? 🤦
  • 44. List in Compose @Composabl e fun UserListScreen(users: List<User>) { LazyColumn ( modifier = Modifier.fillMaxSize()) { item { Text("Header" , Modifier.fillMaxWidth().padding(8.dp ) ) } items(users) { user - > Text("${user.name} - ${user.age}" , Modifier.fillMaxWidth().padding(8.dp ) ) } } }
  • 45. List in Compose (with index) @Composabl e fun UserListScreen(users: List<User>) { LazyColumn ( modifier = Modifier.fillMaxSize()) { item { Text("Header" , Modifier.fillMaxWidth().padding(8.dp ) ) } itemsIndexed(users) { index, user - > Text("${user.name} - ${user.age}" , Modifier.fillMaxWidth().padding(8.dp ) ) } } }
  • 46. Sca ff old Scaffold( topBar = {...}, floatingActionButton = {...}, bottomBar = {...} ) {...}
  • 47. TopAppBar ( title = { Text(text = "Compose") } , backgroundColor = MaterialTheme.colors.primary , contentColor = Color.Yellow , actions = { IconButton(onClick = {}) { Icon(Icons.Default.Search, "Search" ) } IconButton ( onClick = { … } ) { Icon(Icons.Filled.MoreVert, "More" ) DropdownMenu(… ) } } )
  • 48. FloatingActionButton ( onClick = { … } , backgroundColor = Color.Red , contentColor = Color.Whit e ) { Icon(Icons.Filled.Add, "Add" ) }
  • 49. BottomAppBar( backgroundColor = MaterialTheme.colors.primary, content = { BottomNavigationItem( icon = { Icon(Icons.Filled.Home) }, selected = selectedTab == 0, onClick = { selectedTab = 0 }, selectedContentColor = Color.White, unselectedContentColor = Color.DarkGray, label = { Text(text = "Home") } ) BottomNavigationItem(…) } )
  • 50. BottomAppBar( backgroundColor = MaterialTheme.colors.primary, content = { BottomNavigationItem( icon = { Icon(Icons.Filled.Home) }, selected = selectedTab == 0, onClick = { selectedTab = 0 }, selectedContentColor = Color.White, unselectedContentColor = Color.DarkGray, label = { Text(text = "Home") } ) BottomNavigationItem(…) } )
  • 51. State • State in an app is any value that can change over time.  • Component is updated when state has changed var nameState by remember { mutableStateOf("") } TextField ( value = nameState , label = { Text("Name") } , onValueChange = { s: String - > nameState = s } )
  • 52. State data class Score ( var team: String , var score: In t )
  • 53. State class Score ( team: String , score: In t ) { var team by mutableStateOf(team ) var score by mutableStateOf(score) }
  • 54. class Score ( team: String , score: In t ) { var team by mutableStateOf(team ) var score by mutableStateOf(score) }
  • 55. @Composabl e fun TeamScore(score: Score) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text = score.team, style = MaterialTheme.typography.h6 ) Button ( content = { Text("+") } , onClick = { score.score += 1 } ) Text(text = score.score.toString(), style = MaterialTheme.typography.h5 ) Button ( content = { Text("-") } , onClick = { score.score = max(score.score - 1, 0) } ) } }
  • 56. @Composabl e fun ScoreScreen(homeScore: Score, visitorScore: Score) { Column ( modifier = Modifier.fillMaxSize() , verticalArrangement = Arrangement.Center , horizontalAlignment = Alignment.CenterHorizontall y ) { Row { TeamScore(score = homeScore ) Text(text = "x" , modifier = Modifier.padding(horizontal = 8.dp) , style = MaterialTheme.typography.h6 ) TeamScore(score = visitorScore ) } OutlinedButton ( modifier = Modifier.padding(top = 16.dp) , content = { Text("Reset") } , onClick = { homeScore.score = 0 visitorScore.score = 0 } ) } }
  • 58. Observing state • LiveData.observeAsState • Flow.collectAsState • Observable.subscribeAsState View Model UI state event
  • 59. LiveData @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { val users by usersLiveData.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> onSaveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = onDeleteUser ) } }
  • 60. LiveData @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { val users by usersLiveData.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> onSaveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = onDeleteUser ) } }
  • 61. LiveData @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { val users by usersLiveData.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> onSaveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = onDeleteUser ) } }
  • 62. LiveData @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { val users by usersLiveData.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> onSaveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = onDeleteUser ) } }
  • 63. LiveData @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { val users by usersLiveData.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> onSaveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = onDeleteUser ) } }
  • 64. LiveData UserScreen ( usersLiveData = viewModel.allUsers , onSaveUser = { user -> viewModel.saveUser(user ) } , onDeleteUser = { user - > viewModel.deleteUser(user ) } ) @Composabl e fun UserScreen ( usersLiveData: LiveData<List<UserBinding>> , onSaveUser: (UserBinding) -> Unit , onDeleteUser: (UserBinding) -> Uni t ) { … }
  • 65. ViewModel + LiveData + Compose @Composabl e fun UserScreen ( viewModel: UsersViewMode l ) { val users by viewModel.allUsers.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> viewModel.saveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = { user - > viewModel.deleteUser(user ) } ) } }
  • 66. ViewModel + LiveData + Compose @Composabl e fun UserScreen() { val viewModel: UsersViewModel = viewModel() val users by viewModel.allUsers.observeAsState( ) Column(modifier = Modifier.fillMaxSize()) { InputPanel(currentUser, onInsertUser = { user -> viewModel.saveUser(user ) } ) UserList ( users = users ?: emptyList() , onDeleteUser = { user - > viewModel.deleteUser(user ) } ) } } implementation "androidx.lifecycle:lifecycle-viewmodel-compose:<version> "
  • 68. In fragments… class MyFragment: Fragment() { override fun onCreateView ( inflater: LayoutInflater , container: ViewGroup? , savedInstanceState: Bundle ? ): View? { return ComposeView(requireContext()).apply { setContent { AppTheme { YourComposable( ) } } } } }
  • 69. In fragments… class MyFragment: Fragment() { override fun onCreateView ( inflater: LayoutInflater , container: ViewGroup? , savedInstanceState: Bundle ? ): View? { return ComposeView(requireContext()).apply { setContent { AppTheme { YourComposable( ) } } } } }
  • 71. ComposeView class MyComposeVie w @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : AbstractComposeView(context, attrs) { @Composabl e override fun Content() { MyComposableFunction( ) } } <br.com.nglauber.MyComposeVie w android:layout_width="match_parent " android:layout_height="match_parent"/ >
  • 72. @Composabl e fun MyCalendar(onDateUpdate: (Date) -> Unit) { AndroidView ( factory = { context: Context - > val view = LayoutInflater.from(context).inflate(R.layout.my_layout, null, false ) val textView = view.findViewById<TextView>(R.id.txtDate ) val calendarView = view.findViewById<CalendarView>(R.id.calendarView ) calendarView?.setOnDateChangeListener { cv, year, month, day - > val date = Calendar.getInstance().apply { set(year, month, day ) }.tim e textView?.text = date.toString( ) onDateUpdate(date ) } vie w } , update = { view - > // Update vie w } ) }
  • 73. @Composabl e fun MyCalendar(onDateUpdate: (Date) -> Unit) { AndroidView( factory = { context: Context - > val view = LayoutInflater.from(context).inflate(R.layout.my_layout, null, false ) val textView = view.findViewById<TextView>(R.id.txtDate ) val calendarView = view.findViewById<CalendarView>(R.id.calendarView ) calendarView?.setOnDateChangeListener { cv, year, month, day - > val date = Calendar.getInstance().apply { set(year, month, day ) }.tim e textView?.text = date.toString( ) onDateUpdate(date ) } vie w } , update = { view - > // Update vie w } ) }
  • 74. @Composabl e fun MyCalendar(onDateUpdate: (Date) -> Unit) { AndroidView ( factory = { context: Context - > val view = LayoutInflater.from(context).inflate(R.layout.my_layout, null, false ) val textView = view.findViewById<TextView>(R.id.txtDate ) val calendarView = view.findViewById<CalendarView>(R.id.calendarView ) calendarView?.setOnDateChangeListener { cv, year, month, day - > val date = Calendar.getInstance().apply { set(year, month, day ) }.tim e textView?.text = date.toString( ) onDateUpdate(date ) } vie w }, update = { view - > // Update vie w } ) }
  • 75. AndroidViewBinding android { .. . viewBinding { enabled = tru e } } implementation "androidx.compose.ui:ui-viewbinding:$compose_version" AndroidViewBinding(factory = MyBindingLayoutBinding::inflate) { textView.text = "My Text " seekBar.progress = 5 0 }
  • 77. On con fi g changes… Unlike the current UI toolkit, the state is not saved automatically across con fi guration changes. var state by rememberSaveable { mutableStateOf("Compose!!!" ) }
  • 79. E ff ects • LaunchedE ff ect • DisposableE ff ect LaunchedEffect(someKey) { // do something on launc h } DisposableEffect(someKey) { // do something on launc h onDispose { // Cleanu p } }
  • 80. Coroutines LaunchedEffect launch a coroutine when the composition is added and it is automatically cancelled when the execution leaves the composition. @Composabl e fun MyComposable() { val welcomeMsg = remember { mutableStateOf("Initial") } LaunchedEffect(welcomeMsg) { val s = withContext(Dispatchers.IO) { delay(5_000 ) "Hello Compose! " } welcomeMsg.value = s } Text(text = welcomeMsg.value ) }
  • 81. Coroutines rememberCoroutineScope returns the associated CoroutineScope to a given position of the composition. It should be used to launch coroutines as response of callback events @Composabl e fun MyComposable() { val scope = rememberCoroutineScope( ) val count = remember { mutableStateOf(0) } Text(text = "Current count: ${count.value}" ) Button(onClick = { scope.launch { for (i in 1..10) { withContext(Dispatchers.IO) { delay(1_000 ) } count.value = i } } }, content = { Text("Start!") } ) }
  • 82. Learn more… • Samples (goo.gle/compose-samples) • Codelabs (goo.gle/compose-codelabs) • Documentation (goo.gle/compose-docs) • Issue Tracker (goo.gle/compose-feedback) • Slack Channel (goo.gle/compose-slack)
  • 83. Wrap up • The way of Compose works seems very interesting, once it is following the same modern paradigm of other UI toolkits. • Compose is also available for desktop apps (alpha) and now for web (preview)! • Jetpack Compose is in beta stage (beta-06), so DON’T USE IN PRODUCTION! • Be prepared, because declarative is the new standard 😉