Upgrade to Pro — share decks privately, control downloads, hide ads and more …

I/O extended 2021 double S Compose 시작하기

I/O extended 2021 double S Compose 시작하기

6/30 Compose 시작하기

82aa6e293e94bf37796f4ae50f583f6c?s=128

Veronikapj

June 30, 2021
Tweet

Transcript

  1. ߓ೙઱ - Android Engineer, Coupan g veronikapj Compose द੘ೞӝ Android

    1
  2. 2 @Composable fun JetpackCompose() { Card { var expanded by

    remember { mutableStateOf(false) } Column(Modifier.clickable { expanded = !expanded}) { Image(painterResource(R.drawable.jetpack_compose)) AnimatedVisibility(expanded) { Text( text = "Jetpack Compose" style = MaterialTheme.typography.h2 ) } } } }
  3. 3 ௏٘ хࣗ ੸਷ ࣻ੄ ௏٘۽ ؊ ݆਷ ੘সਸ ೞҊ

    ੹୓ ߡӒ ௿ېझܳ ߑ૑ೡ ࣻ ੓ਵ޲۽ ௏٘о рױೞݴ ਬ૑ ҙܻೞӝ औणפ׮. ૒ҙ੸ UI݅ ࢸݺೞݶ աݠ૑ח Composeীࢲ ୊ ܻ೤פ׮. জ ࢚కо ߸҃غݶ UIо ੗زਵ ۽ সؘ੉౟ؾפ׮. ࡅܲ ѐߊ җ੿ ӝઓ੄ ݽٚ ௏٘৬ ഐജغ޲۽ ঱ઁ য٣ࢲ ٚ ਗೞח ؀۽ ࢎਊೡ ࣻ ੓णפ׮. पदр ޷ܻࠁӝ ߂ ৮੹ೠ Android झౚ٣য় ૑ਗ ਵ۽ ࡅܰѱ ߈ࠂೡ ࣻ ੓णפ׮. ъ۱ೠ ࢿמ Android ೒ۖಬ APIী ૒੽ ঘࣁझೞҊ ݠ ౭ܻ঴ ٣੗ੋ, যف਍ ప݃, গפݫ੉࣌ ١ ਸ ӝࠄ੸ਵ۽ ૑ਗೞח ݧ૓ জਸ ٜ݅ ࣻ ੓णפ׮. https://developer.android.com/jetpack/compose
  4. 4 layout? XML?

  5. 5 <TextVie w android:id="@+id/textview_first " android:layout_width=“. . . ” android:layout_height=“.

    . . ” android:text="Hello, Android " / > @Composabl e fun Greeting() { Text(text = “Hello, Android!") }
  6. 6 <TextVie w android:id="@+id/textview_first " android:layout_width=“. . . ” android:layout_height=“.

    . . ” android:text="Hello, Android " / > @Composabl e fun Greeting() { Text(text = “Hello, Android!") } ৵ ߄Բѱ غ঻ਸө? Declarative UI Patterns ( i/o 19 ) https://youtu.be/VsStyq4Lzxo
  7. 7 Android Studio New Project > Minimum SDK UI toolkit

    ী ࢜۽਍ ӝמਸ ઁҕ ೡ ٸ ݃׮ ӝࠄ API ߡ੹ਸ ৢ۰ঠ ೞӝ ٸޙী ৮੹൤ ઁҕ غ۰ݶ য় ے दр੉ ೙ਃ೤פ׮.
  8. 8 UI toolkitী ؀ೠ ࣻ੿ࢎ೦ب ߄۽ ੸ਊ https://developer.android.com/jetpack “Jetpack” Composeੋ

    ੉ਬ?
  9. 9 ӝઓ View ٣੗ੋী ؀ೠ ѐࢶ ӝઓ API

  10. 10 public class Button extends TextView { } ӝઓ API

  11. 11 public class Button extends TextView { } ߡౡীࢲ ೞҊ

    र਷ ੘সࠁ׮ ؊ ݆਷ Ѧ ೡ ࣻ ੓׮. ӝઓ API
  12. 12 Custom View ܳ ੘ࢿೞӝ ਤ೧ Ҋ޹ೡ Ѫٜ public class

    MyCustomView extends View { } 1. xml layout ࢤࢿ - ViewGroup ژח View ܳ ࢎਊ 2. attr.xml ా೧ Custom attribute ࢸ੿ 3. TypedArrayܳ CustomView class ীࢲ ௏٘ܳ ా೧ ੸ਊ 4. ೙ਃೠ ҃਋ View lifecycleী ٮۄ ੌࠗ ݫࣗ٘ܳ ੤੿੄ onDraw(), onMeasure() https://developer.android.com/guide/topics/ui/custom-components ӝઓ API
  13. 13 MyFragment.kt my_fragment.xml attr.xml style.xml value.xml زੌೠ ҳࢿ ਃࣗܳ ਤೠ

    ցޖ ݆਷ ௏٘੄ ࠙࢑
  14. 14 TextView Button LinearLayout xml layout ইఃఫ୊ী ؀ೠ Ҋ޹

  15. 15 TextView Button LinearLayout findViewById() tv.text b.visibility vg.addView() xml layout

    Acitvity / Fragment Ѿ೤بо ֫׮ ইఃఫ୊ী ؀ೠ Ҋ޹
  16. 16 Compose Function Paradigm ࢶ঱ഋ ಁ۞׮੐੄ ੹ജ

  17. 17 Declarative (ࢶ঱ഋ) vs Imperative (ݺ۸ഋ) ஠਍౟о 99ѐ ੉࢚੉ݶ ࠛ੉

    ࠁ੉ѱ ೞҊ ژ ஠਍౟о 0ѐ ੉࢚੉ݶ ઙ੉о ࠁ੉ѱ ೞҊ ஠਍౟о 0ѐ ੉࢚੉ݶ Ӓ ஠਍౟ ं੗੄ ߓ૑о ࠁ੉ѱ ೞ੗ ݫੌ জী ੍૑ ঋ਷ ݫद૑ ই੉௑ਸ ಴दೞח UI Understanding Compose (summit 19) https://youtu.be/Q9MtlmmN4Q0
  18. 18 fun updateCount(count: Int) { if (count > 0 &&

    !hasBadge()) { addBadge() } else if (count == 0 && hasBadge()) { removeBadge() } if (count > 99 && !hasFire()) { addFire() setBadgeText("99+") } else if (count <= 99 && hasFire()) { removeFire() } if (count > 0 && !hasPaper()) { removePaper() } else if (count ==0 && hasPaper()) { addPaper() } if (count <= 99) { setBadgeText("$count") } } Imperative (ݺ۸ഋ)
  19. 19 fun updateCount(count: Int) { if (count > 0 &&

    !hasBadge()) { addBadge() } else if (count == 0 && hasBadge()) { removeBadge() } if (count > 99 && !hasFire()) { addFire() setBadgeText("99+") } else if (count <= 99 && hasFire()) { removeFire() } if (count > 0 && !hasPaper()) { removePaper() } else if (count ==0 && hasPaper()) { addPaper() } if (count <= 99) { setBadgeText("$count") } } ஠਍౟о 99ѐ ੉࢚੉ݶ ࠛ੉ ࠁ੉ѱ ೞҊ ژ ஠਍౟о 0ѐ ੉࢚੉ݶ ઙ੉о ࠁ੉ѱ ೞҊ ஠਍౟о 0ѐ ੉࢚੉ݶ Ӓ ஠਍౟ ं੗੄ ߓ૑о ࠁ੉ѱ ೞ੗ Imperative (ݺ۸ഋ)
  20. 20 @Composable fun BadgeEnvelope(count: Int) { Envelope(fire=count>99, paper=count > 0)

    { if (count > 0) { Badge(text="$count") } } } Declarative (ࢶ঱ഋ)
  21. 21 @Composable fun BadgeEnvelope(count: Int) { Envelope(fire=count>99, paper=count > 0)

    { if (count > 0) { Badge(text="$count") } } } View.Visibility?
  22. 22 @Composable fun Greetings(name: String) { Text (text = "Hello

    $name!") } ݻ о૑ ౠ૚ ׮ܲ Composable ೣࣻ ߧਤ ղীࢲ݅ ഐ୹ @Composable য֢ప੉࣌ ୶о return? ইޖ Ѫب ߈ജೞ૑ ঋ਺ زੌೠ ੋࣻ۽ ৈ۞ ߣ ഐ୹ ؼ ٸ زੌೠ ߑधਵ۽ ੘ز ੹৉ ߸ࣻ ژח random() ഐ୹ ࢎਊ X Composable ೣࣻח
  23. 23

  24. 24 Compose Project द੘ೞӝ Compose UIܳ ૊द ޷ܻ ࠅ ࣻ

    ੓ח ӝמ ߂ ࢜ ೐۽ં౟ మ೒݁җ э਷ झ݃౟ ಞ૘ӝ ӝמਸ ࢎਊ
  25. 25 EmptyComposeActivity Compose Project द੘ೞӝ ӝࠄ Compose ѐߊജ҃੉ ҳࢿػ ೐۽ં౟ܳ

    द੘ೡ ࣻ ੓׮
  26. 26 plugins { id 'org.jetbrains.kotlin.android' version '1.4.32' } android {

    buildFeatures { compose true } } dependencies { implementation 'androidx.compose.ui:ui:1.0.0-beta07' // Tooling support (Previews, etc.) implementation 'androidx.compose.ui:ui-tooling:1.0.0-beta07' // Foundation (Border, Background, Box, Image, shapes, animations, etc.) implementation 'androidx.compose.foundation:foundation:1.0.0-beta07' ... } build.gradle https://developer.android.com/jetpack/compose/setup Compose Project द੘ೞӝ
  27. 27 @Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago")

    } Compose੄ Layout
  28. 28 Vertica l LinearLayout Horizonta l LinearLayout FrameLayout ӝࠄ ۨ੉ইਓ

  29. 29 @Composable fun ArtistCard(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) {

    Image(/*...*/) Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
  30. XML Attribute 30 @Composable fun ArtistCard(/*...*/) { val padding =

    16.dp Column( Modifier .clickable() .padding(padding) .fillMaxWidth() ) { // rest of the implementation } } Composable ੄ ௼ӝ, ۨ੉ইਓ, ز੘ ߂ ݽন ߸҃ ੽Ӕࢿ ۄ߰җ э਷ ੿ࠁ ୶о ࢎਊ੗ ੑ۱ ୊ܻ ਃࣗܳ ௿ܼ оמ, झ௼܀ оמ, ٘ېӒ оמ ژח ഛ؀/୷ࣗ оמೞѱ ݅٘ח Ѫҗ э਷ ֫਷ ࣻળ੄ ࢚ഐ੘ਊ ୶о Modifier
  31. 31 Row( modifier .padding(16.dp) .background(backgroundColor) ) { // content }

  32. 32 Row( modifier .background(backgroundColor) .padding(16.dp) ) { // content }

    Row(
  33. 33 Row(

  34. 34 Button( text = "Button", icon: Icon? = myIcon, textStyle

    = TextStyle(...), spacingBetweenIconAndText = 4.dp, ... ) Slot API
  35. 35 Button( Row { MyImage() Spacer(4.dp) Text("Button") } } Slot

    API
  36. 36 Button { Row { MyImage() Spacer(4.dp) Text("Button") } }

    @Composable fun Button( modifier: Modifier = Modifier.None, onClick: (() -> Unit)? = null, ... content: @Composable () -> Unit } Slot API
  37. 37 TopAppBar

  38. 38 TopAppBar( title = { Text(text = "Page title", maxLines

    = 2) }, navigationIcon = { Icon(myNavIcon) } ) TopAppBar
  39. 39 @Composable fun Scaffold( // .. topBar: @Composable (() ->

    Unit)? = null, bottomBar: @Composable (() -> Unit)? = null, // .. bodyContent: @Composable (PaddingValues) -> Unit ) { } https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#Scaffold Scaffold
  40. 40 @Composable fun ConstraintLayoutContent() { ConstraintLayout { val (button, text)

    = createRefs() Button( 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) }) } } ConstraintLayout
  41. 41 @Composable fun ConstraintLayoutContent() { ConstraintLayout { val (button, text)

    = createRefs() Button( 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) }) } } ConstraintLayout
  42. 42 @Composable fun ConstraintLayoutContent() { ConstraintLayout { val (button, text)

    = createRefs() Button( 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) }) } } ConstraintLayout
  43. 43 Custom View ܳ ੘ࢿೞӝ ਤ೧ Ҋ޹ೡ Ѫٜ public class

    MyCustomView extends View { } 1. xml layout ࢤࢿ - ViewGroup ژח View ܳ ࢎਊ 2. attr.xml ా೧ Custom attribute ࢸ੿ 3. TypedArrayܳ CustomView class ীࢲ ௏٘ܳ ా೧ ੸ਊ 4. ೙ਃೠ ҃਋ View lifecycleী ٮۄ ੌࠗ ݫࣗ٘ܳ ੤੿੄ onDraw(), onMeasure() https://developer.android.com/guide/topics/ui/custom-components
  44. 44 @Composable fun Layout( childrun: @Composable () -> Unit, //

    child ߓ஖ modifier: Modifier = Modifier, // ੸ਊೡ Modifier measureBlock: MeasureBlock // ࢎਊ੗ custom behavior ҳഅ ) { } 1. measure each item : п ೦ݾਸ ஏ੿ 2. call layout() : ۨ੉ইਓ ݫࣗ٘ ഐ୹ 3. place each item : п ೦ݾਸ ߓ஖ Custom Layout
  45. 45 Principles of layout in Compose No multi-pass measurement, ׮઺

    ಁझ ஏ੿ਸ ೲਊೞ૑ ঋणפ׮. ف ߣ ੉࢚ ೞਤ ೦ݾਸ ஏ੿ೡ ࣻ হणפ׮. ف ߣ ஏ੿ೞѱ غݶ ۠ఋ੐ ৘৻о ߊࢤ೤פ׮.
  46. 46 val radius = animate(if (selected) 28.dp else 0.dp) Surface(

    shape = RoundedCornerShape) topStart = radius ) ) { ... } Animation
  47. 47 Theme

  48. 48 <!--Base theme, all common styling here--> <style name="Base.Owl" parent="@style/Theme.MaterialComponents.DayNight.NoActionBar">

    <!--Material shape attributes--> <item name=“shapeAppearanceSmallComponent”>@style/…</item> <!--Material type attributes--> <item name="textAppearanceHeadline1">@style/TextAppearance.Owl.Headline1</item> <item name="textAppearanceBody1">@style/TextAppearance.Owl.Body1</item> </style> <style name="Owl" parent="@style/Base.Owl"/> <style name="Owl.Yellow"> <item name="colorPrimary">@color/owl_yellow_500</item> ... </style> theme.xml MaterialTheme( colors = ... typography = ... shapes = ... ) { //content } Theme.kt Theme
  49. 49 @Composable fun YellowTheme( content: @Composable () -> Unit )

    { MaterialTheme( colors = YellowLightColors, typography = OwlTypography, shapes = OwlShapes, content = content ) } Theme.kt Theme
  50. 50 @Composable fun Onboarding(...) { YellowTheme { Scaffold(...) { ...

    } } } MainScreen.kt Theme
  51. 51 @Composable fun Onboarding(...) { YellowTheme { Scaffold(...) { BlueTheme

    { Button(...) } } } } MainScreen.kt Theme
  52. 52 Migration

  53. 53

  54. 54 <TextView android:id="@+id/plant_detail_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_small" android:layout_marginEnd="@dimen/margin_small" android:gravity="center_horizontal" android:text="@{viewModel.plant.name}" android:textAppearance="?attr/textAppearanceHeadline5"

    app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="Apple" /> XML Compose
  55. 55 @Composable private fun PlantName(name: String) { Text( text =

    name, style = MaterialTheme.typography.h5, modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } XML Compose
  56. 56 @Composable private fun PlantName(name: String) { Text( text =

    name, style = MaterialTheme.typography.h5, modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } android:textAppearance="?attr/textAppearanceHeadline5" xml Compose XML Compose
  57. 57 @Composable private fun PlantName(name: String) { Text( text =

    name, style = MaterialTheme.typography.h5, modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } android:layout_width=“match_parent” xml Compose XML Compose
  58. 58 @Composable private fun PlantName(name: String) { Text( . .

    . modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } android:layout_marginStart="@dimen/margin_small" android:layout_marginEnd="@dimen/margin_small" android:gravity="center_horizontal" xml Compose XML Compose
  59. 59 fragment_example.xml <CoordinatorLayout ...> <AppBarLayout ...> <ConstraintLayout ...> <TextView ...>

    <TextView ...> </ConstraintLayout> </CoordinatorLayout> xml Compose Compose in Views
  60. 60 fragment_example.xml <ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <CoordinatorLayout ...> <AppBarLayout ...>

    <ConstraintLayout ...> <TextView ...> <TextView ...> </ConstraintLayout> </CoordinatorLayout> ConstraintLayoutਸ ComposeView۽ ؀୓ xml Compose Compose in Views
  61. 61 class ExampleFragment : Fragment() { override fun onCreateView(...): View?

    { return inflater.inflate( R.layout.fragment_example, container, false ).apply { ... findViewById<ComposeView>(R.id.compose_view).setContent { MaterialTheme { Surface { Text("Hello Compose") //PlantName("ComposeTree!") } } } } } }
  62. 62 class ExampleFragment : Fragment() { override fun onCreateView(...): View?

    { return inflater.inflate( R.layout.fragment_example, container, false ).apply { ... findViewById<ComposeView>(R.id.compose_view).setContent { MaterialTheme { Surface { Text("Hello Compose") //PlantName("ComposeTree!") } } } } } } Compose world!
  63. 63 class ExampleFragment : Fragment() { override fun onCreateView(...): View?

    = ComposeView(requireContext()).apply { setContent { MaterialTheme { Surface { Text("Hello Compose") } } } } }
  64. 64 class ExampleFragment : Fragment() { override fun onCreateView(...): View?

    = LinearLayout(...).apply { addView(ComposeView(...).apply { id = R.id.compose_view_x ... }) addView(TextView(...)) addView(ComposeView(...).apply { id = R.id.compose_view_y }) } }
  65. 65 Android View in Compose @Composable fun <T : View>

    AndroidView( viewBlock: (Context) -> T, modifier: Modifier = Modifier, update: (T) -> Unit = NoOpUpdate ) { ... } @Composable private fun MapViewContainer(...) { val mapView = rememberMapView() AndroidView({ mapView }) { map -> map.getMapAsync { ... } }
  66. 66 github.com/android/compose-samples Varied UI Light & dark themes Resource loading

    UI testing Design Theme Resource Loading Back button Handling Architecture Components Animation UI Testing Samples
  67. 67 github.com/android/compose-samples Custom design System Custom layouts Animation Material Theme

    Light/Dark Theme Custom Layout Animation Samples
  68. 68 github.com/android/compose-samples Dynamic Theming Courtines Local storage with Room Draggable

    UI elements Android Views Inside Compose UI state handling UI tests Samples
  69. 69 github.com/android/compose-samples

  70. Thank you! developer.android.com/ jetpack/compos e Declarative UI Patterns(io19 ) Understanding

    Compose(summit 19 ) Jetpack Compose ࢎਊೞӝ (android 11 ) What’s new in Jetpack Compose(io 21 ) github.com/android/ compose-samples Resources 70 ߓ೙઱ - Android Engineer, Coupan g veronikapj