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

New Android Declarative UI patterns - Compose

New Android Declarative UI patterns - Compose

- 2019년 7월 20일 기만콘
- 2019년 6월 30일 Google I/O Extended 2019 서울
에서 발표한 자료입니다.

Google I/O 2019에서 새로운 안드로이드의 선언형 UI Toolkit, Compose가 발표되었습니다. 선언형 UI는 기존과 무엇이 다른지, Compose는 무엇인지, 어떻게 사용할지, 어떤 점이 좋은지 등 Compose를 소개하고 전반적인 내용을 함께 살펴봅니다.

Seungmin 마량

June 30, 2019
Tweet

More Decks by Seungmin 마량

Other Decks in Programming

Transcript

  1. ݾର 1. উ٘۽੉٘ UI੄ ޙઁ੼ 2. ҳӖ੉ ਗೞח ࢜۽਍ UI

    3. What is declarative? 4. Jetpack Compose 5. ੿ܻ
  2. ࠂ੟ೠ View ҳઑ class SquareImageView : AppCompatImageView { constructor(context: Context?)

    : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, widthMeasureSpec) } } ঌইঠ ೡ ࠗݽ੄ Ѫٜ੉ ݆਺
  3. What is data flow? What is the source of truth

    - State Who owns it Who updates it
  4. What is data flow? What is the source of truth

    - State Who owns it Who updates it 3ѐ ݽف Viewীب ઓ੤
  5. What is data flow? onSelectedItemChanged ࢎਊ੗о чਸ ߄Բݶ notify Ӓ۞ա

    ч੉ ߄Ո ‘ٍী’ notify data flowо ܻ࠙ Spinner example
  6. Single data flow Stateח ೞա੄ Owner݅ ыח׮ ೞա੄ Owner݅ Stateܳ

    ߸҃ೠ׮ Ownerо ੉ߕ౟ܳ х૑ೞҊ ߸҃ਸ ઱بೠ׮ => View withOUT State
  7. What is Jetpack Compose? NEW Jetpack UI Widgets - NOT

    in SDK! Declaritive UI Toolkits for Android Kotlin Compile Plugin - Kotlin First! ӝઓ জҗ fully ഐജ SUPER Experimental
  8. fun sumFunctional(arr: List<Int>): Int = arr.reduce { acc, i ->

    acc + arr[i] } ݺ۸ഋ sum fun sumImperative(arr: List<Int>): Int { var result = 0 arr.forEach { result += it } return result } ࢶ঱ഋ sum
  9. fun sumFunctional(arr: List<Int>): Int = arr.reduce { acc, i ->

    acc + arr[i] } ݺ۸ഋ sum fun sumImperative(arr: List<Int>): Int { var result = 0 arr.forEach { result += it } return result } ࢶ঱ഋ sum
  10. • UI as a function (Declaritive) • View ҅கਸ ߈ജೞח

    ೣࣻ Basic Idea @Composable fun Greeting(name: String) { Text("Hello $name") }
  11. Basic Idea @Composable fun Greeting(name: String) { Text("Hello $name") }

    • UI as a function (Declaritive) • View ҅கਸ ߈ജೞח ೣࣻ
  12. Initialize class MainActivity : AppCompatActivity() { public override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting(“World!") ... } } }
  13. ListView @Composable fun Greeting(name: String) { Text("Hello $name") } @Composable

    fun GreetingList(names: List<String>) { for (name in names) { Text("Hello $name") } }
  14. @Composable fun Greeting(name: String) { Text("Hello $name") } Composable in

    Composable /** * Simplified version of [Text] component with minimal set of customizations. */ @Composable fun Text( text: String, style: TextStyle? = null, paragraphStyle: ParagraphStyle? = null, softWrap: Boolean = DefaultSoftWrap, overflow: TextOverflow = DefaultOverflow, textScaleFactor: Float = 1.0f, maxLines: Int? = DefaultMaxLines, selectionColor: Color = DefaultSelectionColor )
  15. Composable in Composable @Composable fun NewsFeed(stories: List<StoryData>) { for (story

    in stories) StoryWidget(story) } @Composable fun StoryWidget(story: StoryData) { Padding(8.dp) { Column { Title(story.title) Image(story.image) Text(story.content) } } }
  16. Composable in Composable @Composable fun NewsFeed(stories: List<StoryData>) { for (story

    in stories) StoryWidget(story) } @Composable fun StoryWidget(story: StoryData) { Padding(8.dp) { Column { Title(story.title) Image(story.image) Text(story.content) } } }
  17. @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) { StoryWidget(it) } }

    @Composable fun <T> ScrollingList( dataList: List<T>, body: @Composable() (T) -> Unit ) { for (data in dataList) body(data) } Composable parameter
  18. @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) { StoryWidget(it) } }

    @Composable fun <T> ScrollingList( dataList: List<T>, body: @Composable() (T) -> Unit ) { for (data in dataList) body(data) } Composable parameter
  19. @Composable fun NewsFeed(stories: LiveData<List<StoryData>>) { stories.observe(owner) { ScrollingList(it) { StoryWidget(it)

    } } } Data Observe data class StoryData( val title: LiveData<String>, val image: LiveData<String>, val content: LiveData<String> )
  20. @Composable fun NewsFeed(stories: LiveData<List<StoryData>>) { stories.observe(owner) { ScrollingList(it) { StoryWidget(it)

    } } } data class StoryData( val title: LiveData<String>, val image: LiveData<String>, val content: LiveData<String> ) Data Observe
  21. @Composable fun NewsFeed(stories: LiveData<List<StoryData>>) { stories.observe(owner) { ScrollingList(it) { StoryWidget(it)

    } } } data class StoryData( val title: LiveData<String>, val image: LiveData<String>, val content: LiveData<String> ) Data Observe
  22. @Composable fun NewsFeed(stories: LiveData<List<StoryData>>) { stories.observe(owner) { ScrollingList(it) { StoryWidget(it)

    } } } data class StoryData( val title: LiveData<String>, val image: LiveData<String>, val content: LiveData<String> ) Data Observe
  23. Event @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) { StoryWidget(it) {

    onSelected(it) } } } @Composable fun StoryWidget(story: StoryData, onClick: () -> Unit) { Clickable(onClick) { Padding(8.dp) { ... } } }
  24. Event @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) { StoryWidget(it) {

    onSelected(it) } } } @Composable fun StoryWidget(story: StoryData, onClick: () -> Unit) { Clickable(onClick) { Padding(8.dp) { ... } } }
  25. Top-down data flow @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) {

    StoryWidget(it) { onSelected(it) } } } @Composable fun StoryWidget(story: StoryData) { Clickable(onClick) { Padding(8.dp) { ... } } } Data
  26. Bottom-up event @Composable fun NewsFeed(stories: List<StoryData>) { ScrollingList(stories) { StoryWidget(it)

    { onSelected(it) } } } @Composable fun StoryWidget(story: StoryData) { Clickable(onClick) { Padding(8.dp) { ... } } } Event
  27. Single data flow • ചݶীࢲ ҙܻೞח ؘ੉ఠܳ ࠭۽ ղܽ׮ •

    ࠭ীࢲ ߊࢤೞח ੉߮౟ܳ ചݶীࢲ ֈѹળ ۈ׮۽ ৢܽ׮
  28. Single data flow • ചݶীࢲ ҙܻೞח ؘ੉ఠܳ ࠭۽ ղܽ׮ •

    ࠭ীࢲ ߊࢤೞח ੉߮౟ܳ ചݶীࢲ ֈѹળ ۈ׮۽ ৢܽ׮ Data flowܳ ചݶਵ۽ ాੌ! (MVPীࢲח Presenter / MVVMীࢲח ViewModel)
  29. Multiple data flow onSelectedItemChanged ࢎਊ੗о чਸ ߄Բݶ notify Ӓ۞ա ч੉

    ߄Ո ‘ٍী’ notify data flowо ܻ࠙ Spinner example
  30. Single data flow Spinner @Composable fun FoodPreferences(data: UserPreferences) { val

    options = listOf(MILK, EGGS, BREAD) Spinner( options = options, selected = data.favoriteFood, onChanged = { selected -> data.favoriteFood = selected } ) }
  31. Single data flow Spinner @Composable fun FoodPreferences(data: UserPreferences) { val

    options = listOf(MILK, EGGS, BREAD) Spinner( options = options, selected = data.favoriteFood, onChanged = { selected -> data.favoriteFood = selected } ) } Notify റ Single data sourceܳ ߸҃
  32. Single data flow Stateח ೞա੄ Owner݅ ыח׮ ೞա੄ Owner݅ Stateܳ

    ߸҃ೠ׮ Ownerо ੉ߕ౟ܳ х૑ೞҊ ߸҃ਸ ઱بೠ׮ => View withOUT State
  33. Basic Idea @Composable fun Greeting(name: String) { Text("Hello $name") }

    • UI as a function (Declaritive) • View ҅கਸ ߈ജೞח ೣࣻ
  34. Reference • Google I/O 2019 ৔࢚ • ҕध о੉٘ •

    @turaש ࠶۽Ӓ • ੿थ਌ש ߊ಴੗ܐ • @pluuloveש ࠶۽Ӓ