Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
I/O extended 2021 double S Compose 시작하기
Search
Veronikapj
June 30, 2021
Programming
300
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
I/O extended 2021 double S Compose 시작하기
6/30 Compose 시작하기
Veronikapj
June 30, 2021
More Decks by Veronikapj
See All by Veronikapj
Google I/O 요약만 봤다고? AI가 못 보는 진짜 이야기
veronikapj
0
88
The Know-how of Seniors in the Age of AI
veronikapj
0
130
Gemini in Android Studio I/O extended 2024
veronikapj
0
460
How to use Macrobenchmark
veronikapj
0
390
앱 성능 영혼까지 끌어올리기
veronikapj
0
1.2k
Software Productivity - Devfest Songdo 2023
veronikapj
0
1k
파이어베이스로 서비스 품질 올리기
veronikapj
0
410
What's new in Android IO23 Daejeon
veronikapj
1
340
KC23_Coroutine_Testing
veronikapj
0
190
Other Decks in Programming
See All in Programming
Webフレームワークの ベンチマークについて
yusukebe
0
170
Contextとはなにか
chiroruxx
1
330
Lessons from Spec-Driven Development
simas
PRO
0
210
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
200
Creating Composable Callables in Contemporary C++
rollbear
0
150
AI時代のUIはどこへ行く?その2!
yusukebe
21
7.3k
net-httpのHTTP/2対応について
naruse
0
500
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.3k
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
360
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
250
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
180
AIとASP.NET Coreで雑Webアプリを作った話
mayuki
0
650
Featured
See All Featured
Mind Mapping
helmedeiros
PRO
1
250
The Limits of Empathy - UXLibs8
cassininazir
1
360
Code Reviewing Like a Champion
maltzj
528
40k
WENDY [Excerpt]
tessaabrams
11
38k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
210
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
200
A designer walks into a library…
pauljervisheath
211
24k
Code Review Best Practice
trishagee
74
20k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
HDC tutorial
michielstock
2
720
Speed Design
sergeychernyshev
33
1.9k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
390
Transcript
ߓ - Android Engineer, Coupan g veronikapj Compose दೞӝ Android
1
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 ٘ хࣗ ࣻ ٘۽ ؊ ݆ সਸ ೞҊ
ߡӒ ېझܳ ߑೡ ࣻ ਵ۽ ٘о рױೞݴ ਬ ҙܻೞӝ औणפ. ҙ UI݅ ࢸݺೞݶ աݠח Composeীࢲ ܻפ. জ ࢚కо ߸҃غݶ UIо زਵ ۽ সؘؾפ. ࡅܲ ѐߊ җ ӝઓ ݽٚ ٘৬ ഐജغ۽ ઁ য٣ࢲ ٚ ਗೞח ۽ ࢎਊೡ ࣻ णפ. पदр ܻࠁӝ ߂ ৮ೠ Android झౚ٣য় ਗ ਵ۽ ࡅܰѱ ߈ࠂೡ ࣻ णפ. ъ۱ೠ ࢿמ Android ۖಬ APIী ঘࣁझೞҊ ݠ ౭ܻ ٣ੋ, যف ప݃, গפݫ࣌ ١ ਸ ӝࠄਵ۽ ਗೞח ݧ জਸ ٜ݅ ࣻ णפ. https://developer.android.com/jetpack/compose
4 layout? XML?
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 <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 Android Studio New Project > Minimum SDK UI toolkit
ী ࢜۽ ӝמਸ ઁҕ ೡ ٸ ݃ ӝࠄ API ߡਸ ৢ۰ঠ ೞӝ ٸޙী ৮ ઁҕ غ۰ݶ য় ے दр ਃפ.
8 UI toolkitী ೠ ࣻࢎ೦ب ߄۽ ਊ https://developer.android.com/jetpack “Jetpack” Composeੋ
ਬ?
9 ӝઓ View ٣ੋী ೠ ѐࢶ ӝઓ API
10 public class Button extends TextView { } ӝઓ API
11 public class Button extends TextView { } ߡౡীࢲ ೞҊ
र সࠁ ؊ ݆ Ѧ ೡ ࣻ . ӝઓ API
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 MyFragment.kt my_fragment.xml attr.xml style.xml value.xml زੌೠ ҳࢿ ਃࣗܳ ਤೠ
ցޖ ݆ ٘ ࠙
14 TextView Button LinearLayout xml layout ইఃఫী ೠ Ҋ
15 TextView Button LinearLayout findViewById() tv.text b.visibility vg.addView() xml layout
Acitvity / Fragment Ѿبо ֫ ইఃఫী ೠ Ҋ
16 Compose Function Paradigm ࢶഋ ಁ۞ ജ
17 Declarative (ࢶഋ) vs Imperative (ݺ۸ഋ) о 99ѐ ࢚ݶ ࠛ
ࠁѱ ೞҊ ژ о 0ѐ ࢚ݶ ઙо ࠁѱ ೞҊ о 0ѐ ࢚ݶ Ӓ ं ߓо ࠁѱ ೞ ݫੌ জী ੍ ঋ ݫद ইਸ दೞח UI Understanding Compose (summit 19) https://youtu.be/Q9MtlmmN4Q0
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 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 @Composable fun BadgeEnvelope(count: Int) { Envelope(fire=count>99, paper=count > 0)
{ if (count > 0) { Badge(text="$count") } } } Declarative (ࢶഋ)
21 @Composable fun BadgeEnvelope(count: Int) { Envelope(fire=count>99, paper=count > 0)
{ if (count > 0) { Badge(text="$count") } } } View.Visibility?
22 @Composable fun Greetings(name: String) { Text (text = "Hello
$name!") } ݻ о ౠ ܲ Composable ೣࣻ ߧਤ ղীࢲ݅ ഐ @Composable য֢ప࣌ ୶о return? ইޖ Ѫب ߈ജೞ ঋ زੌೠ ੋࣻ۽ ৈ۞ ߣ ഐ ؼ ٸ زੌೠ ߑधਵ۽ ز ߸ࣻ ژח random() ഐ ࢎਊ X Composable ೣࣻח
23
24 Compose Project दೞӝ Compose UIܳ द ܻ ࠅ ࣻ
ח ӝמ ߂ ࢜ ۽ં మ݁җ э झ݃ ಞӝ ӝמਸ ࢎਊ
25 EmptyComposeActivity Compose Project दೞӝ ӝࠄ Compose ѐߊജ҃ ҳࢿػ ۽ંܳ
दೡ ࣻ
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 @Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago")
} Compose Layout
28 Vertica l LinearLayout Horizonta l LinearLayout FrameLayout ӝࠄ ۨইਓ
29 @Composable fun ArtistCard(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) {
Image(/*...*/) Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
XML Attribute 30 @Composable fun ArtistCard(/*...*/) { val padding =
16.dp Column( Modifier .clickable() .padding(padding) .fillMaxWidth() ) { // rest of the implementation } } Composable ӝ, ۨইਓ, ز ߂ ݽন ߸҃ Ӕࢿ ۄ߰җ э ࠁ ୶о ࢎਊ ੑ۱ ܻ ਃࣗܳ ܼ оמ, झ܀ оמ, ٘ېӒ оמ ژח ഛ/୷ࣗ оמೞѱ ݅٘ח Ѫҗ э ֫ ࣻળ ࢚ഐਊ ୶о Modifier
31 Row( modifier .padding(16.dp) .background(backgroundColor) ) { // content }
32 Row( modifier .background(backgroundColor) .padding(16.dp) ) { // content }
Row(
33 Row(
34 Button( text = "Button", icon: Icon? = myIcon, textStyle
= TextStyle(...), spacingBetweenIconAndText = 4.dp, ... ) Slot API
35 Button( Row { MyImage() Spacer(4.dp) Text("Button") } } Slot
API
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 TopAppBar
38 TopAppBar( title = { Text(text = "Page title", maxLines
= 2) }, navigationIcon = { Icon(myNavIcon) } ) TopAppBar
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 @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 @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 @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 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 @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 Principles of layout in Compose No multi-pass measurement,
ಁझ ஏਸ ೲਊೞ ঋणפ. ف ߣ ࢚ ೞਤ ೦ݾਸ ஏೡ ࣻ হणפ. ف ߣ ஏೞѱ غݶ ۠ఋ ৻о ߊࢤפ.
46 val radius = animate(if (selected) 28.dp else 0.dp) Surface(
shape = RoundedCornerShape) topStart = radius ) ) { ... } Animation
47 Theme
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 @Composable fun YellowTheme( content: @Composable () -> Unit )
{ MaterialTheme( colors = YellowLightColors, typography = OwlTypography, shapes = OwlShapes, content = content ) } Theme.kt Theme
50 @Composable fun Onboarding(...) { YellowTheme { Scaffold(...) { ...
} } } MainScreen.kt Theme
51 @Composable fun Onboarding(...) { YellowTheme { Scaffold(...) { BlueTheme
{ Button(...) } } } } MainScreen.kt Theme
52 Migration
53
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 @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 @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 @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 @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 fragment_example.xml <CoordinatorLayout ...> <AppBarLayout ...> <ConstraintLayout ...> <TextView ...>
<TextView ...> </ConstraintLayout> </CoordinatorLayout> xml Compose Compose in Views
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 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 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 class ExampleFragment : Fragment() { override fun onCreateView(...): View?
= ComposeView(requireContext()).apply { setContent { MaterialTheme { Surface { Text("Hello Compose") } } } } }
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 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 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 github.com/android/compose-samples Custom design System Custom layouts Animation Material Theme
Light/Dark Theme Custom Layout Animation Samples
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 github.com/android/compose-samples
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