luca_nicolett
JETPACK COMPOSE
EXPLORING A PRE-ALPHA
Slide 2
Slide 2 text
luca_nicolett
JETPACK COMPOSE
๏ Luca Nicoletti
๏ Italian
๏ Android Engineer
๏ Based in London
๏ Babylon Health
Slide 3
Slide 3 text
luca_nicolett
JETPACK COMPOSE
EXPLORING A PRE-ALPHA
Slide 4
Slide 4 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
Android Dev
Summit
Oct 2019
Slide 5
Slide 5 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
Slide 6
Slide 6 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
Android Dev
Summit
Oct 2019
Slide 7
Slide 7 text
luca_nicolett
JETPACK COMPOSE
Android Dev
Summit
Oct 2019
Slide 8
Slide 8 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
Android Dev
Summit
Oct 2019
5 months time
Slide 9
Slide 9 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
Android Dev
Summit
Oct 2019
5 months time
!
Slide 10
Slide 10 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
2-3 weeks
after
Generic blogposts
about all the things
announced
Slide 11
Slide 11 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
2-3 weeks
after
Generic blogposts
about all the things
announced
Generic blogpost
about what is
Jetpack Compose
Slide 12
Slide 12 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
2-3 weeks
after
Generic blogposts
about all the things
announced
Generic blogpost
about what is
Jetpack Compose
Specific blogpost
about Jetpack
Compose
Slide 13
Slide 13 text
luca_nicolett
JETPACK COMPOSE
Google I/O
May 2019
2-3 weeks
after
Generic blogposts
about all the things
announced
Generic blogpost
about what is
Jetpack Compose
Specific blogpost
about Jetpack
Compose
End of the excitement
around Jetpack
Compose
Slide 14
Slide 14 text
luca_nicolett
JETPACK COMPOSE
Android Dev
Summit
Oct 2019
2-3 weeks
after
Slide 15
Slide 15 text
luca_nicolett
JETPACK COMPOSE
Android Dev
Summit
Oct 2019
2-3 weeks
after
Some conversations on the
kotlinlang slack channel
luca_nicolett
Declarative → describe what you would like
Imperative → describe how to achieve it
JETPACK COMPOSE
Declarative
A tower of 3 blocks.
Imperative
1. Put down first block
2. Put down second block
3. Put down third block
luca_nicolett
mkdir androidx-master-dev
cd androidx-master-dev
repo init -u https://android.googlesource.com/platform/manifest
-b androidx-master-dev
repo sync -j8 -c
Download the code (and grab a coffee while we pull down 6GB)
JETPACK COMPOSE
Slide 35
Slide 35 text
luca_nicolett
cd path/to/checkout/frameworks/support/
./studiow
JETPACK COMPOSE
Slide 36
Slide 36 text
luca_nicolett
class MyActivity: Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyComposableFunction()
}
}
}
JETPACK COMPOSE
Slide 37
Slide 37 text
luca_nicolett
class MyActivity: Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyComposableFunction()
}
}
}
JETPACK COMPOSE
luca_nicolett
/**
* A [FileEditor] that displays a preview of composable
* elements defined in the given [psiFile].
*
* The editor will display previews for all declared
* `@Composable` functions that also use the `@Preview`
* (see [PREVIEW_ANNOTATION_FQN])annotation.
* For every preview element a small XML is generated
* that allows Layoutlib to render a `@Composable` functions.
*
* @param psiFile [PsiFile] pointing to the Kotlin source
* containing the code to preview.
* @param previewProvider call to obtain the [PreviewElement]s
* from the file.
*/
JETPACK COMPOSE
Slide 49
Slide 49 text
luca_nicolett
@Composable
fun Text(/* ... */) {
/* ... */
Draw { canvas, _ ->
internalSelection.value?.let {
textDelegate.paintBackground(
it.min, it.max, selectionColor, canvas
)
}
textDelegate.paint(canvas)
// Paints the text onto the given canvas.
}
/* ... */
}
JETPACK COMPOSE
Slide 50
Slide 50 text
luca_nicolett
@Composable
fun Text(/* ... */) {
/* ... */
Draw { canvas, _ ->
internalSelection.value?.let {
textDelegate.paintBackground(
it.min, it.max, selectionColor, canvas
)
}
textDelegate.paint(canvas)
// Paints the text onto the given canvas.
}
/* ... */
}
JETPACK COMPOSE
Slide 51
Slide 51 text
luca_nicolett
@Composable
fun Text(/* ... */) {
/* ... */
Draw { canvas, _ ->
internalSelection.value?.let {
textDelegate.paintBackground(
it.min, it.max, selectionColor, canvas
)
}
textDelegate.paint(canvas)
// Paints the text onto the given canvas.
}
/* ... */
}
JETPACK COMPOSE
Slide 52
Slide 52 text
luca_nicolett
JETPACK COMPOSE
Slide 53
Slide 53 text
luca_nicolett
JETPACK COMPOSE
Slide 54
Slide 54 text
luca_nicolett
JETPACK COMPOSE
Slide 55
Slide 55 text
luca_nicolett
@Composable
fun TextField(/* ... */) {
// States
val hasFocus = +state { false }
val coords = +state { null }
val inputSession = +state { NO_SESSION }
/* ... */
}
JETPACK COMPOSE
luca_nicolett
/**
* The State class is an @Model class meant to
* wrap around a single value.
* It is used in the `+state` and `+stateFor` effects.
*/
@Model
class State @PublishedApi internal constructor(value: T)
: Framed {}
JETPACK COMPOSE
luca_nicolett
@Composable
fun Counter() {
var count by +state { 0 }
Text(text = "You clicked $count times")
Button("Click me",{ count = count + 1 })
}
JETPACK COMPOSE
Slide 60
Slide 60 text
luca_nicolett
@Composable
fun Counter() {
var count by +state { 0 }
Text(text = "You clicked $count times")
Button("Click me",{ count = count + 1 })
}
JETPACK COMPOSE
Slide 61
Slide 61 text
luca_nicolett
@Composable
fun Counter() {
var count by +state { 0 }
Text(text = "You clicked $count times")
Button("Click me",{ count = count + 1 })
}
JETPACK COMPOSE
Slide 62
Slide 62 text
luca_nicolett
@Composable
fun Counter() {
var count by +state { 0 }
Text(text = "You clicked $count times")
Button("Click me",{ count = count + 1 })
}
JETPACK COMPOSE
Slide 63
Slide 63 text
luca_nicolett
/**
* [Model] can be applied to a class which represents your
* application's data model, and will cause instances of the
* class to become observable, such that a read of a property
* of an instance of this class during the invocation of a
* composable function will cause that component to be
* "subscribed" to mutations of that instance. Composable
* functions which directly or indirectly read properties
* of the model class, the composables will be recomposed
* whenever any properties of the the model are written to.
*/
JETPACK COMPOSE
Slide 64
Slide 64 text
luca_nicolett
@Model
data class TaskModel(
var isDone: Boolean,
val description: String
)
JETPACK COMPOSE
Slide 65
Slide 65 text
luca_nicolett
@Model
data class TaskModel(
var isDone: Boolean,
val description: String
): BaseModel()
JETPACK COMPOSE
Slide 66
Slide 66 text
luca_nicolett
@Model
data class TaskModel(
var isDone: Boolean,
val description: String
): BaseModel()
TaskModel.kt: (14, 3): Model objects do not support inheritance
JETPACK COMPOSE
Slide 67
Slide 67 text
luca_nicolett
JETPACK COMPOSE
Slide 68
Slide 68 text
luca_nicolett
RawDragGestureDetector(DragObserver { distance ->
//update animation value
}) {
PressGestureDetector({ position ->
// animate to position
}) {
Container(60.dp, expanded = true) {
DrawSeekBar(animValue.value)
}
}
}
JETPACK COMPOSE
Slide 69
Slide 69 text
luca_nicolett
RawDragGestureDetector(DragObserver { distance ->
//update animation value
}) {
PressGestureDetector({ position ->
// animate to position
}) {
Container(60.dp, expanded = true) {
DrawSeekBar(animValue.value)
}
}
}
JETPACK COMPOSE
Slide 70
Slide 70 text
luca_nicolett
RawDragGestureDetector(DragObserver { distance ->
//update animation value
}) {
PressGestureDetector({ position ->
// animate to position
}) {
Container(60.dp, expanded = true) {
DrawSeekBar(animValue.value)
}
}
}
JETPACK COMPOSE
Slide 71
Slide 71 text
luca_nicolett
RawDragGestureDetector(DragObserver { distance ->
//update animation value
}) {
PressGestureDetector({ position ->
// animate to position
}) {
Container(60.dp, expanded = true) {
DrawSeekBar(animValue.value)
}
}
}
JETPACK COMPOSE
luca_nicolett
JETPACK COMPOSE
@Composable
fun RippleRectFromState(state: TransitionState) {
// TODO: file bug for when "down" is not a
// file level val, it's not memoized correctly
val x = down.x
val y = down.y
val paint =
Paint().apply {
color = Color(
alpha = getAlpha(),
red = 0,
green = 235,
Slide 80
Slide 80 text
luca_nicolett
JETPACK COMPOSE
// file level val, it's not memoized correctly
val x = down.x
val y = down.y
val paint =
Paint().apply {
color = Color(
alpha = getAlpha(),
red = 0,
green = 235,
blue = 224
)
}
val radius = state[radius]
Draw { canvas, _ ->
Slide 81
Slide 81 text
luca_nicolett
JETPACK COMPOSE
red = 0,
green = 235,
blue = 224
)
}
val radius = state[radius]
Draw { canvas, _ ->
canvas.drawCircle(
Offset(x, y),
radius,
paint
)
}
}
Slide 82
Slide 82 text
luca_nicolett
JETPACK COMPOSE
Slide 83
Slide 83 text
luca_nicolett
JETPACK COMPOSE
@Composable
fun AlertDialog(
onCloseRequest: () -> Unit,
title: (@Composable() () -> Unit)? = null,
text: (@Composable() () -> Unit),
buttons: @Composable() () -> Unit
) {
val currentColors = +ambient(Colors)
val currentTypography = +ambient(Typography)
Dialog(onCloseRequest = onCloseRequest) {
/* ... */
}
}
Slide 84
Slide 84 text
luca_nicolett
JETPACK COMPOSE
@Composable
fun Dialog(
onCloseRequest: () -> Unit,
children: @Composable() () -> Unit
) {
val context = +ambient(ContextAmbient)
val dialog = +memo {
DialogWrapper(context, onCloseRequest)
}
+onActive {
dialog.show()
Slide 85
Slide 85 text
luca_nicolett
JETPACK COMPOSE
@Composable
fun Dialog(
onCloseRequest: () -> Unit,
children: @Composable() () -> Unit
) {
val context = +ambient(ContextAmbient)
val dialog = +memo {
DialogWrapper(context, onCloseRequest)
}
+onActive {
dialog.show()
luca_nicolett
data class PaddingModifier(
val left: IntPx = 0.ipx,
val top: IntPx = 0.ipx,
val right: IntPx = 0.ipx,
val bottom: IntPx = 0.ipx
) : LayoutModifier {
/* ... */
}
JETPACK COMPOSE
Slide 95
Slide 95 text
luca_nicolett
/**
* An immutable chain of [modifier elements][Modifier.Element]
* for use with Composables. A Composable that has a `Modifier`
* can be considered decorated or wrapped by that `Modifier`.
*
* Composables that accept a [Modifier] as a parameter to be
* applied to the whole component represented by the composable
* function should name the parameter `modifier` and assign the
* parameter a default value of [Modifier.None]
*/
JETPACK COMPOSE
Slide 96
Slide 96 text
luca_nicolett
data class PaddingModifier()
Text(
text = "Hello ",
modifier = PaddingModifier(16.dp)
)
JETPACK COMPOSE
Slide 97
Slide 97 text
luca_nicolett
Text(
text = "Hello ",
modifier = PaddingModifier(16.dp)
)
JETPACK COMPOSE
Padding(16.dp) {
Text("Hello ")
}
VS