Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
I/O extended 2021 double S Compose 시작하기
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Veronikapj
June 30, 2021
Programming
310
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
What's New in Android 2026
veronikapj
0
350
Google I/O 요약만 봤다고? AI가 못 보는 진짜 이야기
veronikapj
0
100
The Know-how of Seniors in the Age of AI
veronikapj
0
150
Gemini in Android Studio I/O extended 2024
veronikapj
0
470
How to use Macrobenchmark
veronikapj
0
410
앱 성능 영혼까지 끌어올리기
veronikapj
0
1.2k
Software Productivity - Devfest Songdo 2023
veronikapj
0
1.1k
파이어베이스로 서비스 품질 올리기
veronikapj
0
430
What's new in Android IO23 Daejeon
veronikapj
1
360
Other Decks in Programming
See All in Programming
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
340
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
510
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
360
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
450
wkhtmltopdfの次どうするか問題2026
willnet
2
1.8k
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
150
mrbgem 三角測量 開発
ogom
0
140
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
260
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
730
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
590
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
Workers Cache を知る
syumai
0
310
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
460
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
250
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
The untapped power of vector embeddings
frankvandijk
2
1.9k
WENDY [Excerpt]
tessaabrams
14
39k
Building an army of robots
kneath
307
47k
A Modern Web Designer's Workflow
chriscoyier
699
190k
A designer walks into a library…
pauljervisheath
211
25k
How to Ace a Technical Interview
jacobian
280
24k
Un-Boring Meetings
codingconduct
0
430
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
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