Slide 1

Slide 1 text

Márton Braun @zsmb13 Developer Relations Engineer Google Composing an API with Kotlin VOL.2

Slide 2

Slide 2 text

Previously… goo.gle/composing-an-api-talk

Slide 3

Slide 3 text

Jetpack Compose is Android’s modern toolkit for building native UI. d.android.com/compose

Slide 4

Slide 4 text

Disclaimer Some of the code shown on these slides is simplified so that it fits. Check the implementation yourself!

Slide 5

Slide 5 text

goo.gle/code-search-compose

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Default arguments

Slide 8

Slide 8 text

Default arguments fun RoundedCornerShape( topStart: Dp = 0.dp, topEnd: Dp = 0.dp, bottomEnd: Dp = 0.dp, bottomStart: Dp = 0.dp )

Slide 9

Slide 9 text

Default arguments fun RoundedCornerShape( topStart: Dp = 0.dp, topEnd: Dp = 0.dp, bottomEnd: Dp = 0.dp, bottomStart: Dp = 0.dp ) @Stable inline val Int.dp: Dp get() = Dp(value = this.toFloat())

Slide 10

Slide 10 text

Default arguments fun RoundedCornerShape( topStart: Dp = 0.dp, topEnd: Dp = 0.dp, bottomEnd: Dp = 0.dp, bottomStart: Dp = 0.dp ) RoundedCornerShape( topEnd = 16.dp, )

Slide 11

Slide 11 text

Default arguments fun RoundedCornerShape( topStart: Dp = 0.dp, topEnd: Dp = 0.dp, bottomEnd: Dp = 0.dp, bottomStart: Dp = 0.dp ) RoundedCornerShape( topEnd = 16.dp, bottomStart = 32.dp, )

Slide 12

Slide 12 text

Default arguments @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 13

Slide 13 text

Default arguments @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 14

Slide 14 text

Default arguments Text("Hello Compose!") @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 15

Slide 15 text

Default arguments Hello Compose! Text("Hello Compose!") @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 16

Slide 16 text

) Default arguments Text( text = "Hello Compose!", fontSize = 10.sp, Hello Compose! @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 17

Slide 17 text

Text( text = "Hello Compose!", Default arguments Hello Compose! @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) fontSize = 10.sp, fontWeight = FontWeight.Bold, )

Slide 18

Slide 18 text

modifier = Modifier.width(50.dp), Text( text = "Hello Compose!", Default arguments @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) Hello Compose! 50.dp fontSize = 10.sp, fontWeight = FontWeight.Bold, )

Slide 19

Slide 19 text

Default arguments modifier = Modifier.width(50.dp), fontSize = 10.sp, fontWeight = FontWeight.Bold, ) Hello 50.dp @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) maxLines = 1, Text( text = "Hello Compose!",

Slide 20

Slide 20 text

Default arguments Hello 50.dp @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) modifier = Modifier.width(50.dp), fontSize = 10.sp, fontWeight = FontWeight.Bold, ) maxLines = 1, Text( text = "Hello Compose!",

Slide 21

Slide 21 text

modifier = Modifier.width(50.dp), fontSize = 10.sp, fontWeight = FontWeight.Bold, ) maxLines = 1, Text( text = "Hello Compose!", overflow = TextOverflow.Ellipsis, Default arguments Hello Co... 50.dp @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current )

Slide 22

Slide 22 text

Default & named arguments Hello Co... @Composable fun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, fontSize: TextUnit = TextUnit.Unspecified, fontStyle: FontStyle? = null, fontWeight: FontWeight? = null, fontFamily: FontFamily? = null, letterSpacing: TextUnit = TextUnit.Unspecified, textDecoration: TextDecoration? = null, textAlign: TextAlign? = null, lineHeight: TextUnit = TextUnit.Unspecified, overflow: TextOverflow = TextOverflow.Clip, softWrap: Boolean = true, maxLines: Int = Int.MAX_VALUE, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current ) modifier = Modifier.width(50.dp), fontSize = 10.sp, fontWeight = FontWeight.Bold, ) maxLines = 1, Text( text = "Hello Compose!", overflow = TextOverflow.Ellipsis, 50.dp

Slide 23

Slide 23 text

Default & named arguments @Composable fun Button( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, shape: Shape = ButtonDefaults.shape, colors: ButtonColors = ButtonDefaults.buttonColors(), elevation: ButtonElevation? = ButtonDefaults.buttonElevation(), border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, content: @Composable RowScope.() -> Unit )

Slide 24

Slide 24 text

Default & named arguments @Composable fun Button( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, shape: Shape = ButtonDefaults.shape, colors: ButtonColors = ButtonDefaults.buttonColors(), elevation: ButtonElevation? = ButtonDefaults.buttonElevation(), border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, content: @Composable RowScope.() -> Unit )

Slide 25

Slide 25 text

Function types modifier: Modifier = Modifier, enabled: Boolean = true, shape: Shape = ButtonDefaults.shape, colors: ButtonColors = ButtonDefaults.buttonColors(), elevation: ButtonElevation? = ButtonDefaults.buttonElevation(), border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, content: @Composable RowScope.() -> Unit ) @Composable fun Button( onClick: () -> Unit, ...,

Slide 26

Slide 26 text

m o d i f i e r : M o d i f i e r = M o d i f i e r , e n a b l e d : B o o l e a n = t r u e , s h a p e : S h a p e = B u t t o n D e f a u l t s . s h a p e , c o l o r s : B u t t o n C o l o r s = B u t t o n D e f a u l t s . b u t t o n C o l o r s ( ) , e l e v a t i o n : B u t t o n E l e v a t i o n ? = B u t t o n D e f a u l t s . b u t t o n E l e v a t i o n ( ) , b o r d e r : B o r d e r S t r o k e ? = n u l l , c o n t e n t P a d d i n g : P a d d i n g V a l u e s = B u t t o n D e f a u l t s . C o n t e n t P a d d i n g , i n t e r a c t i o n S o u r c e : M u t a b l e I n t e r a c t i o n S o u r c e = r e m e m b e r { M u t a b l e I n t e r a c t i o n S o u r c e ( ) } , Function types Button(onClick = { onBackClick(screenId) }) { Icon( imageVector = Icons.Rounded.ArrowBack, contentDescription = stringResource(R.string.back) ) } @Composable fun Button( onClick: () -> Unit, content: @Composable RowScope.() -> Unit ) ...,

Slide 27

Slide 27 text

Function types @Composable fun Button( onClick: () -> Unit, ..., content: @Composable RowScope.() -> Unit ) Button(onClick = { onBackClick(screenId) }) { Icon( imageVector = Icons.Rounded.ArrowBack, contentDescription = stringResource(R.string.back) ) }

Slide 28

Slide 28 text

Function types @Composable fun Button( onClick: () -> Unit, ..., content: @Composable RowScope.() -> Unit ) Button(onClick = { onBackClick(screenId) }) { Icon( imageVector = Icons.Rounded.ArrowBack, contentDescription = stringResource(R.string.back) ) }

Slide 29

Slide 29 text

Function types @Composable fun Button( onClick: () -> Unit, ..., content: @Composable RowScope.() -> Unit ) Button(onClick = { onBackClick(screenId) }) { Icon( imageVector = Icons.Rounded.ArrowBack, contentDescription = stringResource(R.string.back) ) }

Slide 30

Slide 30 text

Function types @Composable fun Button( onClick: () -> Unit, ..., content: @Composable RowScope.() -> Unit ) Button(onClick = { onBackClick(screenId) }) { Icon( imageVector = Icons.Rounded.ArrowBack, contentDescription = ) } stringResource(R.string.back)

Slide 31

Slide 31 text

Function types @Composable fun Button( onClick: () -> Unit, ..., content: @Composable RowScope.() -> Unit ) Button(onClick = { onBackClick(screenId) }) { Text( ) } stringResource(R.string.back)

Slide 32

Slide 32 text

Function types

Slide 33

Slide 33 text

Function types @Composable fun Title(snack: Snack, scroll: Int) { val offset = (maxOffset - scroll).coerceAtLeast(minOffset) Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, scroll.value)

Slide 34

Slide 34 text

Function types @Composable fun Title(snack: Snack, scroll: Int) { val offset = (maxOffset - scroll).coerceAtLeast(minOffset) Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, scroll.value)

Slide 35

Slide 35 text

Function types @Composable fun Title(snack: Snack, scroll: Int) { val offset = (maxOffset - scroll).coerceAtLeast(minOffset) Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, scroll.value)

Slide 36

Slide 36 text

Function types @Composable fun Title(snack: Snack, scroll: Int) { val offset = (maxOffset – scroll Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, scroll.value) ).coerceAtLeast(minOffset)

Slide 37

Slide 37 text

@Composable fun Title(snack: Snack, scrollProvider: () -> Int) { val offset = (maxOffset – scrollProvider() Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value } Function types ) ).coerceAtLeast(minOffset)

Slide 38

Slide 38 text

Function types @Composable fun Title(snack: Snack, scrollProvider: () -> Int) { val offset = (maxOffset – scrollProvider()).coerceAtLeast(minOffset) Column( modifier = Modifier.graphicsLayer(translationY = offset) ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value })

Slide 39

Slide 39 text

Function types @Composable fun Title(snack: Snack, scrollProvider: () -> Int) { val offset = (maxOffset – scrollProvider()) Column( modifier = Modifier.graphicsLayer( ) ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value }) translationY = offset .coerceAtLeast(minOffset)

Slide 40

Slide 40 text

Function types @Composable fun Title(snack: Snack, scrollProvider: () -> Int) { Column( modifier = Modifier.graphicsLayer { } ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value }) translationY = offset .coerceAtLeast(minOffset) val offset = (maxOffset - scrollProvider())

Slide 41

Slide 41 text

Function types @Composable fun Title(snack: Snack, scrollProvider: () -> Int) { Column( modifier = Modifier.graphicsLayer { translationY = offset } ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value }) .coerceAtLeast(minOffset) val offset = (maxOffset - scrollProvider())

Slide 42

Slide 42 text

Function types @Composable fun Title(snack: Snack, scrollProvider: () -> Int) { Column( modifier = Modifier.graphicsLayer { translationY = offset } ) { Text(...) Text(...) Text(...) } } Title(snack, { scroll.value }) .coerceAtLeast(minOffset) val offset = (maxOffset - scrollProvider())

Slide 43

Slide 43 text

Function types checkNotNull(inputStream) { "Stream must be opened before reading" } require(offset >= 0) { "Offset must not be negative (was $offset)" } map.getOrElse(key) { fetchDefaultValue() }

Slide 44

Slide 44 text

Delegates

Slide 45

Slide 45 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) }

Slide 46

Slide 46 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) }

Slide 47

Slide 47 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) } I really like 3.14159264498239 Twice the pi, double the flavour: 6.28318528996478 operator fun getValue(thisRef: T, property: KProperty<*>): V

Slide 48

Slide 48 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) } operator fun getValue(thisRef: T, property: KProperty<*>): V

Slide 49

Slide 49 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) } operator fun getValue(thisRef: T, property: KProperty<*>): V operator fun setValue(thisRef: T, property: KProperty<*>, value: V)

Slide 50

Slide 50 text

Delegates val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } fun main() { println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) } operator fun getValue(thisRef: T, property: KProperty<*>): V operator fun setValue(thisRef: T, property: KProperty<*>, value: V)

Slide 51

Slide 51 text

Delegates fun main() { val pi by lazy { sqrt(6 * (1..1_000_000_000).sumOf { 1.0 / it / it }) } println("I really like $pi") println("Twice the pi, double the flavour:") println(pi * 2) } operator fun getValue(thisRef: T, property: KProperty<*>): V operator fun setValue(thisRef: T, property: KProperty<*>, value: V)

Slide 52

Slide 52 text

Delegates @Composable fun NameInput() { val name = remember { mutableStateOf("") } OutlinedTextField( value = name.value, onValueChange = { name.value = it }, label = { Text("Name") } ) }

Slide 53

Slide 53 text

@Composable fun NameInput() { val name = remember { mutableStateOf("") } OutlinedTextField( value = name.value, onValueChange = { name.value = it }, label = { Text("Name") } ) } Delegates MutableState

Slide 54

Slide 54 text

@Composable fun NameInput() { val name = remember { mutableStateOf("") } OutlinedTextField( value = name.value, onValueChange = { name.value = it }, label = { Text("Name") } ) } Delegates MutableState

Slide 55

Slide 55 text

Delegates @Composable fun NameInput() { var name: String by remember { mutableStateOf("") } OutlinedTextField( value = name.value, onValueChange = { name.value = it }, label = { Text("Name") } ) } MutableState

Slide 56

Slide 56 text

Delegates @Composable fun NameInput() { var name: String by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) } MutableState

Slide 57

Slide 57 text

Delegates interface State { val value: T } interface MutableState : State { override var value: T ... }

Slide 58

Slide 58 text

Delegates interface State { val value: T } interface MutableState : State { override var value: T ... }

Slide 59

Slide 59 text

Delegates interface MutableState : State { override var value: T ... } interface State { val value: T }

Slide 60

Slide 60 text

... Delegates ) { this.value = value } interface MutableState : State { override var value: T ... } inline operator fun State.getValue( ): T = value inline operator fun MutableState.setValue( interface State { val value: T } value: T ...,

Slide 61

Slide 61 text

..., ... thisObj: Any?, property: KProperty<*> thisObj: Any?, property: KProperty<*>, ) { this.value = value } Delegates inline operator fun State.getValue( ): T = value inline operator fun MutableState.setValue( value: T

Slide 62

Slide 62 text

Delegates val map = mutableMapOf() var name by map name = "Compose" println(map) // {name=Compose}

Slide 63

Slide 63 text

Delegates val map = mutableMapOf() var name by map name = "Compose" println(map) // {name=Compose}

Slide 64

Slide 64 text

Destructuring declarations

Slide 65

Slide 65 text

Destructuring declarations val (r, g, b, a) = Color(0x00E97FFF)

Slide 66

Slide 66 text

@JvmInline value class Color(val value: ULong) { ... } Destructuring declarations val (r, g, b, a) = Color(0x00E97FFF)

Slide 67

Slide 67 text

Destructuring declarations val (r, g, b, a) = Color(0x00E97FFF) @JvmInline value class Color(val value: ULong) { val red: Float get() { ... } val green: Float get() { ... } val blue: Float get() { ... } val alpha: Float get() { ... } ... }

Slide 68

Slide 68 text

... Destructuring declarations val (r, g, b, a) = Color(0x00E97FFF) @JvmInline value class Color(val value: ULong) { val red: Float get() { ... } val green: Float get() { ... } val blue: Float get() { ... } val alpha: Float get() { ... } operator fun component1(): Float = red operator fun component2(): Float = green operator fun component3(): Float = blue operator fun component4(): Float = alpha }

Slide 69

Slide 69 text

@Composable fun NameInput() { var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, ) } Destructuring declarations MutableState

Slide 70

Slide 70 text

Destructuring declarations @Composable fun NameInput() { val (name, setName) remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, ) } = MutableState

Slide 71

Slide 71 text

Destructuring declarations @Composable fun NameInput() { val (name: String, setName: (String) -> Unit) remember { mutableStateO OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") }, ) } MutableState =

Slide 72

Slide 72 text

Destructuring declarations @Composable fun NameInput() { val (name: String, setName: (String) -> Unit) remember { mutableStateO OutlinedTextField( value = name, onValueChange = setName, label = { Text("Name") }, ) } MutableState =

Slide 73

Slide 73 text

Destructuring declarations interface MutableState : State { override var value: T operator fun component1(): T = value operator fun component2(): (T) -> Unit = { value = it } } @Composable fun NameInput() { val (name: String, setName: (String) -> Unit) remember { mutableStateO OutlinedTextField( value = name, onValueChange = setName, label = { Text("Name") }, ) } MutableState =

Slide 74

Slide 74 text

Destructuring declarations interface MutableState : State { override var value: T operator fun component1(): T = value operator fun component2(): (T) -> Unit = { value = it } } @Composable fun NameInput() { val (name: String, setName: (String) -> Unit) remember { mutableStateO OutlinedTextField( value = name, onValueChange = setName, label = { Text("Name") }, ) } MutableState =

Slide 75

Slide 75 text

Destructuring declarations ConstraintLayout { val (button, text) = createRefs() Button( onClick = { /* Do something */ }, modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } Text("Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) }) }

Slide 76

Slide 76 text

ConstraintLayout { val (button, text) = createRefs() Button( onClick = { /* Do something */ }, modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } Text("Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) }) } Destructuring declarations Button(ref = button) Text(ref = text) 16.dp

Slide 77

Slide 77 text

ConstraintLayout { val (button, text) = createRefs() Button( onClick = { /* Do something */ }, modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } Text("Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) }) } Destructuring declarations

Slide 78

Slide 78 text

ConstraintLayout { Button( onClick = { /* Do something */ }, modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } Text("Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) }) } this: ConstraintLayoutScope this: ConstrainScope this: ConstrainScope Destructuring declarations val (button, text) = createRefs()

Slide 79

Slide 79 text

val (button, text) = createRefs()

Slide 80

Slide 80 text

val (button, text) = createRefs() ConstrainedLayoutReference

Slide 81

Slide 81 text

val (button, text) = createRefs() ConstrainedLayoutReferences ConstrainedLayoutReference

Slide 82

Slide 82 text

val (button, text) = createRefs() ConstrainedLayoutReferences ConstrainedLayoutReference @LayoutScopeMarker class ConstraintLayoutScope { fun createRefs() = referencesObject private var referencesObject: ConstrainedLayoutReferences = ... inner class ConstrainedLayoutReferences internal constructor() { operator fun component1() = createRef() operator fun component2() = createRef() operator fun component3() = createRef() operator fun component4() = createRef() ... operator fun component16() = createRef() } fun createRef() = ConstrainedLayoutReference(childId++) ... }

Slide 83

Slide 83 text

val (button, text) = createRefs() ConstrainedLayoutReferences ConstrainedLayoutReference @LayoutScopeMarker class ConstraintLayoutScope { fun createRefs() = referencesObject private var referencesObject: ConstrainedLayoutReferences = ... inner class ConstrainedLayoutReferences internal constructor() { operator fun component1() = createRef() operator fun component2() = createRef() operator fun component3() = createRef() operator fun component4() = createRef() ... operator fun component16() = createRef() } fun createRef() = ConstrainedLayoutReference(childId++) ... }

Slide 84

Slide 84 text

val (button, text) = createRefs() ConstrainedLayoutReferences ConstrainedLayoutReference @LayoutScopeMarker class ConstraintLayoutScope { fun createRefs() = referencesObject private var referencesObject: ConstrainedLayoutReferences = ... inner class ConstrainedLayoutReferences internal constructor() { operator fun component1() = createRef() operator fun component2() = createRef() operator fun component3() = createRef() operator fun component4() = createRef() ... operator fun component16() = createRef() } fun createRef() = ConstrainedLayoutReference(childId++) ... }

Slide 85

Slide 85 text

Strongly typed APIs

Slide 86

Slide 86 text

Strongly typed APIs

Slide 87

Slide 87 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally BottomStart

Slide 88

Slide 88 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally BottomStart Hello Compose!

Slide 89

Slide 89 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally Hello Compose! BottomStart TopCenter CenterEnd ...

Slide 90

Slide 90 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally Hello Compose! Hello Compose! BottomStart TopCenter CenterEnd ...

Slide 91

Slide 91 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally Start End BottomStart TopCenter CenterEnd ... Hello Compose! Hello Compose!

Slide 92

Slide 92 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } CenterHorizontally Start End BottomStart TopCenter CenterEnd ...

Slide 93

Slide 93 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } this: BoxScope this: ColumnScope CenterHorizontally Start End BottomStart TopCenter CenterEnd ...

Slide 94

Slide 94 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } this: BoxScope CenterHorizontally Start End BottomStart TopCenter CenterEnd ... Alignment this: ColumnScope Alignment.Horizontal

Slide 95

Slide 95 text

Strongly typed APIs Box { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } Column { Text( text = "Hello Compose!", modifier = Modifier.align(Alignment. ) ) } this: BoxScope Alignment CenterHorizontally BottomStart Alignment.Horizontal this: ColumnScope

Slide 96

Slide 96 text

... ... @Stable fun interface Alignment { fun align(size: IntSize, space: IntSize, layoutDirection: LayoutDirection): IntOffset @Stable fun align(size: Int, space: Int, layoutDirection: LayoutDirection): Int } @Stable fun align(size: Int, space: Int): Int } } Strongly typed APIs fun interface Horizontal { fun interface Vertical { // 1D Alignment.Horizontals val Start: Horizontal = BiasAlignment.Horizontal(-1f)

Slide 97

Slide 97 text

companion object { // 2D Alignments val TopStart: Alignment = BiasAlignment(-1f, -1f) val TopCenter: Alignment = BiasAlignment(0f, -1f) val TopEnd: Alignment = BiasAlignment(1f, -1f) val CenterStart: Alignment = BiasAlignment(-1f, 0f) val Center: Alignment = BiasAlignment(0f, 0f) val CenterEnd: Alignment = BiasAlignment(1f, 0f) val BottomStart: Alignment = BiasAlignment(-1f, 1f) val BottomCenter: Alignment = BiasAlignment(0f, 1f) val BottomEnd: Alignment = BiasAlignment(1f, 1f) // ... } ... ... // 1D Alignment.Horizontals val Start: Horizontal = BiasAlignment.Horizontal(-1f) fun interface Alignment { } } } Strongly typed APIs fun interface Horizontal { fun interface Vertical {

Slide 98

Slide 98 text

val TopStart: Alignment = BiasAlignment(-1f, -1f) val TopCenter: Alignment = BiasAlignment(0f, -1f) val TopEnd: Alignment = BiasAlignment(1f, -1f) val CenterStart: Alignment = BiasAlignment(-1f, 0f) val Center: Alignment = BiasAlignment(0f, 0f) val CenterEnd: Alignment = BiasAlignment(1f, 0f) val BottomStart: Alignment = BiasAlignment(-1f, 1f) val BottomCenter: Alignment = BiasAlignment(0f, 1f) val BottomEnd: Alignment = BiasAlignment(1f, 1f) fun interface Alignment { fun interface Horizontal { ... } fun interface Vertical { ... } companion object { // 2D Alignments // ... } } Strongly typed APIs // 1D Alignment.Horizontals val Start: Horizontal = BiasAlignment.Horizontal(-1f) val CenterHorizontally: Horizontal = BiasAlignment.Horizontal(0f) val End: Horizontal = BiasAlignment.Horizontal(1f) // 1D Alignment.Verticals val Top: Vertical = BiasAlignment.Vertical(-1f) val CenterVertically: Vertical = BiasAlignment.Vertical(0f) val Bottom: Vertical = BiasAlignment.Vertical(1f)

Slide 99

Slide 99 text

● Composing an API with Kotlin vol. 1 ● Jetpack Compose: Debugging Recomposition ● Code search: Jetpack Compose ● Compose API guidelines ● Kotlin for Jetpack Compose goo.gle/composing-an-api-talk goo.gle/compose-debug-recomposition goo.gle/code-search-compose goo.gle/compose-api-guidelines goo.gle/kotlin-for-compose Resources

Slide 100

Slide 100 text

Thank You! Márton Braun @zsmb13 Composing an API with Kotlin VOL.2