ݺߣ

ݺߣShare a Scribd company logo
Pedro Veloso
Twitter &&
Instagram: @pedronveloso
Hands-On
Jetpack Compose
KotlinMeetup2020|NYC2020
Pedro Veloso
Twitter &&
Instagram: @pedronveloso
Hands-On
Jetpack Compose
KotlinMeetup2020|NYC2020
Jetpack
Compose
Jetpack Compose
simplifies and
accelerates UI
development on
Android. Quickly bring
your app to life with
less code, powerful
tools, and intuitive
Kotlin APIs.
Source: https://developer.android.com/jetpack/compose
Why and How?
? Android Developers Backstage Episode 131 :
? https://androidbackstage.blogspot.com/2020/01/episode-131-jetpack-compose-and.html
? Understanding Compose (Dev Summit):
? https://www.youtube.com/watch?v=Q9MtlmmN4Q0
? Offitial Website
? https://developer.android.com/jetpack/compose
? Not Stable
? Not in RC
? Not in Beta
? Not in Alpha
? THIS IS A DEV PREVIEW!
? Dont use in production !
Using
Jetpack Compose
H a n d s - O n V e r s i o n
TheHOW|YetAnotherWeatherApplication
? Display Current temperature, max and min
? 2nd Screen with the forecast
? Style the App
? Forecast list must be scrollable
Compose Weather
Layouts
C o l u m n
R o w
ArrangementAxis
A r r a n g e m e n t A x i s
Flex
F l e x i n g
A
0.3 Flex
A
LayoutFlexible(0.3f)
Flex
F l e x i n g
A
0.3 Flex
A
CC
LayoutFlexible(0.3f)
Flex
F l e x i n g
A
0.3 Flex
A
CC
LayoutFlexible(0.3f)
0.2 Flex LayoutFlexible(0.2f)
Basic Elements
T e x t
3 7 4 L O C
I m a g e
1 0 0 L O C
S p a c e r
L a y o u t W i d t h
L a y o u t H e i g h t
C a r d
5 5 L O C
Text
/**
* Simplified version of [Text] component with minimal set of
customizations.
*/
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier.None,
style: TextStyle? = null,
softWrap: Boolean = DefaultSoftWrap,
overflow: TextOverflow = DefaultOverflow,
maxLines: Int = DefaultMaxLines
)
Show us the
Code!
@Composable
private fun MainScreen(){
Column {
DrawBackground()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
MainScreen()
}
}
}
@Composable
fun DrawBackground() {
DrawImage(image =
imageResource(R.drawable.nyc_night_1))
}
B a c k g r o u n d
These arent the
Droids youre
looking for.
BONSAI|PRESENTATION
data class CurrentWeather(
val locationName: String,
val curTemperature: Temperature,
val forecast: WeatherForecast
)
class Temperature(val celcius: Double)
data class WeatherForecast(
val maxTemperature: Temperature,
val minTemperature: Temperature,
val state: WeatherState
)
enum class WeatherState(@DrawableRes val iconResId: Int,
@StringRes val descriptionResId: Int) {
SUNNY(R.drawable.ic_sunny, R.string.state_sunny),
RAINY(R.drawable.ic_rainy, R.string.state_rainy),
PARTLY_CLOUDY(R.drawable.ic_p_cloudy, R.string.state_p_cloudy),
SNOWY(R.drawable.ic_snowy, R.string.state_snowy)
}
<string name="state_sunny">Sunny</string>
<string name="state_rainy">Rainy</string>

D a t a M o d e l s
@Composable
fun Title(currentWeather: CurrentWeather) {
Text(text = currentWeather.locationName,
style = MaterialTheme.typography().h2
.copy(color = Color.White,
fontWeight = FontWeight.W200,
fontFamily = FontFamily("sans-
serif-thin")))
}
}
T i t l e
Theming
val weatherTypography =
Typography(
h1 = TextStyle(
fontWeight =
FontWeight.W200,
fontSize = 54.sp,
color = Color.White
),
subtitle1 = 
val weatherThemeColors =
lightColorPalette(
primary = Color(0xFF116a9c),
primaryVariant = Color(0xFF1e5371),
onPrimary = Color.White,

@Composable
fun WeatherTheme(children: @Composable() () -> Unit) {
MaterialTheme(colors = weatherThemeColors, typography = weatherTypography,
children = children)
}
A p p l y T h e m e
setContent {
WeatherTheme {
Column {
DrawBackground()
Title(currentWeather)
}
}
}
@Composable
private fun Title(cur: CurrentWeather) {
Text(
text = cur.locationName,
style = MaterialTheme.typography().h2
)
}
@Composable
fun Title(cur: CurrentWeather) {
Row(modifier = LayoutWidth.Fill,
arrangement = Arrangement.Center) {
Spacer(LayoutHeight(16.dp))
Text(text = currentWeather.locationName,
style = MaterialTheme.typography().h2)
}
}
C e n t e r
Column {
DrawBackground()
Title(currentWeather)
}
T o d a y  s
S t a t eRow(
modifier = LayoutWidth.Fill,
arrangement = Arrangement.Center) {
Container(width = 32.dp, height = 32.dp) {
DrawImage(image = imageResource(
currentWeather.forecast.state.iconResId))
}
// Empty Space.
Spacer(LayoutWidth(8.dp)
Text(
text = stringResource(
currentWeather.forecast.state.descriptionResId),
style = MaterialTheme.typography().body2)
}
T o d a y  s
F o r e c a s t
@Composable
fun CurrentWeatherBlock(
current: CurrentWeather) {
Column(modifier =
LayoutWidth.Fill ,
arrangement =
Arrangement.Center) {
}
}
WeatherState(current)
CurrentTemperature(current)
MinMaxTemperatures(current)
L a y o u t
A d j u s t
Column {
DrawBackground()
Title(currentWeather = cur)
Spacer(modifier = LayoutFlexible(0.7f))
CurrentWeatherBlock(currentWeather = cur)
Spacer(modifier = LayoutFlexible(0.3f))
}
L i s t E l e m e n t
fun WeatherForecastRow
Row {

}
Card(color = cardBackgroundColor, elevation = 8.dp) {
Padding(left = 8.dp, right = 8.dp, top = 16.dp, bottom = 16.dp) {
WeatherForecastRow(forecast)
}
}
for (forecast in forecasts) {
}
Column {
DrawBackground()
Title(currentWeather)
CurrentWeatherBlock(currentWeather)
VerticalScroller {
Column(modifier = LayoutPadding(16.dp))
{
WeatherForecastList(forecasts)
}
}
}
S e c o n d
S c r e e n
Navigation
Between
Screens
Compose Models
sealed class Screen {
object MainScreen : Screen()
object WeatherForecastScreen : Screen()
}
@Model
object GlobalState {
var currentScreen : Screen = Screen.MainScreen
var currentWeather : CurrentWeather? = null
var predictions: List<DayForecast> = emptyList()
}
fun navigateTo(screen: Screen){
GlobalState.currentScreen = screen
}
Single Activity
setContent {
Crossfade(GlobalState.currentScreen) { screen ->
Surface {
when (screen) {
is Screen.MainScreen -> MainScreen()
is Screen.WeatherForecastScreen -> WeatherListScreen()
}
}
}
}
override fun onBackPressed() {
if (GlobalState.currentScreen == Screen.WeatherForecastScreen) {
navigateTo(Screen.MainScreen)
} else {
super.onBackPressed()
}
}
AppBar
TopAppBar(
title = {
Text(text =
stringResource(R.string.app_name))
}
)
TopAppBar(
title = { Text(text =
stringResource(R.string.app_name)) },
navigationIcon = {
VectorImageButton(R.drawable.ic_back) {
navigateTo(Screen.MainScreen)
}
}
)
Add a Button
Button(text = stringResource(R.string.load_forecasts),
onClick = { navigateTo(Screen.WeatherForecastScreen)
})
Thank You
Pedr o V elo s o
@ p e d r o n v e l o s o
Q& A?
O r f i nd m e a f te rwa rd s :)

More Related Content

Jetpack Compose - Hands-on February 2020

  • 1. Pedro Veloso Twitter && Instagram: @pedronveloso Hands-On Jetpack Compose KotlinMeetup2020|NYC2020 Pedro Veloso Twitter && Instagram: @pedronveloso Hands-On Jetpack Compose KotlinMeetup2020|NYC2020
  • 2. Jetpack Compose Jetpack Compose simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs. Source: https://developer.android.com/jetpack/compose
  • 3. Why and How? ? Android Developers Backstage Episode 131 : ? https://androidbackstage.blogspot.com/2020/01/episode-131-jetpack-compose-and.html ? Understanding Compose (Dev Summit): ? https://www.youtube.com/watch?v=Q9MtlmmN4Q0 ? Offitial Website ? https://developer.android.com/jetpack/compose
  • 4. ? Not Stable ? Not in RC ? Not in Beta ? Not in Alpha ? THIS IS A DEV PREVIEW! ? Dont use in production !
  • 5. Using Jetpack Compose H a n d s - O n V e r s i o n
  • 6. TheHOW|YetAnotherWeatherApplication ? Display Current temperature, max and min ? 2nd Screen with the forecast ? Style the App ? Forecast list must be scrollable Compose Weather
  • 7. Layouts C o l u m n R o w ArrangementAxis A r r a n g e m e n t A x i s
  • 8. Flex F l e x i n g A 0.3 Flex A LayoutFlexible(0.3f)
  • 9. Flex F l e x i n g A 0.3 Flex A CC LayoutFlexible(0.3f)
  • 10. Flex F l e x i n g A 0.3 Flex A CC LayoutFlexible(0.3f) 0.2 Flex LayoutFlexible(0.2f)
  • 11. Basic Elements T e x t 3 7 4 L O C I m a g e 1 0 0 L O C S p a c e r L a y o u t W i d t h L a y o u t H e i g h t C a r d 5 5 L O C
  • 12. Text /** * Simplified version of [Text] component with minimal set of customizations. */ @Composable fun Text( text: String, modifier: Modifier = Modifier.None, style: TextStyle? = null, softWrap: Boolean = DefaultSoftWrap, overflow: TextOverflow = DefaultOverflow, maxLines: Int = DefaultMaxLines )
  • 14. @Composable private fun MainScreen(){ Column { DrawBackground() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MaterialTheme { MainScreen() } } } @Composable fun DrawBackground() { DrawImage(image = imageResource(R.drawable.nyc_night_1)) } B a c k g r o u n d
  • 15. These arent the Droids youre looking for.
  • 16. BONSAI|PRESENTATION data class CurrentWeather( val locationName: String, val curTemperature: Temperature, val forecast: WeatherForecast ) class Temperature(val celcius: Double) data class WeatherForecast( val maxTemperature: Temperature, val minTemperature: Temperature, val state: WeatherState ) enum class WeatherState(@DrawableRes val iconResId: Int, @StringRes val descriptionResId: Int) { SUNNY(R.drawable.ic_sunny, R.string.state_sunny), RAINY(R.drawable.ic_rainy, R.string.state_rainy), PARTLY_CLOUDY(R.drawable.ic_p_cloudy, R.string.state_p_cloudy), SNOWY(R.drawable.ic_snowy, R.string.state_snowy) } <string name="state_sunny">Sunny</string> <string name="state_rainy">Rainy</string> D a t a M o d e l s
  • 17. @Composable fun Title(currentWeather: CurrentWeather) { Text(text = currentWeather.locationName, style = MaterialTheme.typography().h2 .copy(color = Color.White, fontWeight = FontWeight.W200, fontFamily = FontFamily("sans- serif-thin"))) } } T i t l e
  • 18. Theming val weatherTypography = Typography( h1 = TextStyle( fontWeight = FontWeight.W200, fontSize = 54.sp, color = Color.White ), subtitle1 = val weatherThemeColors = lightColorPalette( primary = Color(0xFF116a9c), primaryVariant = Color(0xFF1e5371), onPrimary = Color.White, @Composable fun WeatherTheme(children: @Composable() () -> Unit) { MaterialTheme(colors = weatherThemeColors, typography = weatherTypography, children = children) }
  • 19. A p p l y T h e m e setContent { WeatherTheme { Column { DrawBackground() Title(currentWeather) } } } @Composable private fun Title(cur: CurrentWeather) { Text( text = cur.locationName, style = MaterialTheme.typography().h2 ) }
  • 20. @Composable fun Title(cur: CurrentWeather) { Row(modifier = LayoutWidth.Fill, arrangement = Arrangement.Center) { Spacer(LayoutHeight(16.dp)) Text(text = currentWeather.locationName, style = MaterialTheme.typography().h2) } } C e n t e r Column { DrawBackground() Title(currentWeather) }
  • 21. T o d a y s S t a t eRow( modifier = LayoutWidth.Fill, arrangement = Arrangement.Center) { Container(width = 32.dp, height = 32.dp) { DrawImage(image = imageResource( currentWeather.forecast.state.iconResId)) } // Empty Space. Spacer(LayoutWidth(8.dp) Text( text = stringResource( currentWeather.forecast.state.descriptionResId), style = MaterialTheme.typography().body2) }
  • 22. T o d a y s F o r e c a s t @Composable fun CurrentWeatherBlock( current: CurrentWeather) { Column(modifier = LayoutWidth.Fill , arrangement = Arrangement.Center) { } } WeatherState(current) CurrentTemperature(current) MinMaxTemperatures(current)
  • 23. L a y o u t A d j u s t Column { DrawBackground() Title(currentWeather = cur) Spacer(modifier = LayoutFlexible(0.7f)) CurrentWeatherBlock(currentWeather = cur) Spacer(modifier = LayoutFlexible(0.3f)) }
  • 24. L i s t E l e m e n t fun WeatherForecastRow Row { } Card(color = cardBackgroundColor, elevation = 8.dp) { Padding(left = 8.dp, right = 8.dp, top = 16.dp, bottom = 16.dp) { WeatherForecastRow(forecast) } } for (forecast in forecasts) { }
  • 25. Column { DrawBackground() Title(currentWeather) CurrentWeatherBlock(currentWeather) VerticalScroller { Column(modifier = LayoutPadding(16.dp)) { WeatherForecastList(forecasts) } } } S e c o n d S c r e e n
  • 27. Compose Models sealed class Screen { object MainScreen : Screen() object WeatherForecastScreen : Screen() } @Model object GlobalState { var currentScreen : Screen = Screen.MainScreen var currentWeather : CurrentWeather? = null var predictions: List<DayForecast> = emptyList() } fun navigateTo(screen: Screen){ GlobalState.currentScreen = screen }
  • 28. Single Activity setContent { Crossfade(GlobalState.currentScreen) { screen -> Surface { when (screen) { is Screen.MainScreen -> MainScreen() is Screen.WeatherForecastScreen -> WeatherListScreen() } } } } override fun onBackPressed() { if (GlobalState.currentScreen == Screen.WeatherForecastScreen) { navigateTo(Screen.MainScreen) } else { super.onBackPressed() } }
  • 29. AppBar TopAppBar( title = { Text(text = stringResource(R.string.app_name)) } ) TopAppBar( title = { Text(text = stringResource(R.string.app_name)) }, navigationIcon = { VectorImageButton(R.drawable.ic_back) { navigateTo(Screen.MainScreen) } } )
  • 30. Add a Button Button(text = stringResource(R.string.load_forecasts), onClick = { navigateTo(Screen.WeatherForecastScreen) })
  • 31. Thank You Pedr o V elo s o @ p e d r o n v e l o s o Q& A? O r f i nd m e a f te rwa rd s :)