Slide 1

Slide 1 text

Songdo, Incheon NAVER Map in Jetpack Compose Sungyong An 
 Android GDE, NAVER WEBTOON

Slide 2

Slide 2 text

Sungyong An NAVER WEBTOON Android GDE @fornewid Link: h tt ps://github.com/fornewid

Slide 3

Slide 3 text

Sungyong An NAVER WEBTOON Android GDE @fornewid Link: h tt ps://github.com/fornewid Slide Template ठۄ੉٘ ೞױী ݂௼о ੓णפ׮.

Slide 4

Slide 4 text

Code Template View Compose ਋ஏ ࢚ױী যڃ ௏٘ੋ૑ ই੉௑ਸ ಴द೤פ׮. Compose ௏٘݅ ઝஏী ֣࢝ ߄ܳ ಴द೤פ׮.

Slide 5

Slide 5 text

Link: h tt ps://developersonair.withgoogle.com/events/composecamp_22kr Jetpack Compose ೟ण੉ ೙ਃೠ ࠙਷ Compose Camp ೯ࢎী ଵৈ೧ࠁࣁਃ!

Slide 6

Slide 6 text

Link: h tt ps://developer.android.com/develop/ui/views/layout/declaring-layout View System അসীࢲח View Systemਵ۽ ѐߊೞח Ѫ੉ ੊ࣼೡ Ѫ эणפ׮. ୊਺ উ٘۽੉٘ ѐߊਸ ੽ೡ ٸب ࠁా Layout XMLࠗఠ द੘ೞભ.

Slide 7

Slide 7 text

Link: h tt ps://developer.android.com/jetpack/compose Jetpack Compose (Modern Android Development ) ਃ્ীח Jetpack Composeо ݆੉ ࣗѐغҊ ੓ҳਃ. ࢜۽਍ ࣗध ੺߈਷ Composeੌ ੿ب۽ ҙबਸ ߉Ҋ ੓णפ׮.

Slide 8

Slide 8 text

Link: h tt ps://developer.android.com/jetpack/compose/interop/migration-strategy Migrate from View to Compose 🤔 Ӓ۞׮ࠁפ ݆਷ ٜ࠙੉ Viewܳ Compose۽ ੹ജೞҊ ੓Ѣա, ੹ജਸ Ҋ۰ೞҊ ੓ਸѢۄ ࢤп೤פ׮.

Slide 9

Slide 9 text

Toy Project Link: h tt ps://github.com/Moop-App/Moop-Android য়ט਷ അসীࢲ ੸ਊೠ ղਊ਷ ইפҊ, ష੉ ೐۽ં౟ী ؀ೠ ղਊੑפ׮.

Slide 10

Slide 10 text

Link: h tt ps://github.com/navermaps/android-map-sdk Official SDK based on View 🤔 ֎੉ߡ૑ب SDKח View Systemਵ۽ ҳഅغয ੓णפ׮. Ӓېࢲ ੉Ѧ ஹನૉীࢲ যڌѱ ॶ ࣻ ੓ਸ૑ Ҋ޹೮ભ.

Slide 11

Slide 11 text

How to use in Jetpack Compose? -(1) ݽٚ ௏٘ܳ Compose۽ ׮द ੘ࢿೠ׮ -(2) ೨ब ௏٘ܳ ܻ࠙ೞৈ Composeীࢲ ੤ഝਊೠ׮ -(3) ࢚ഐ ਍ਊࢿ APIܳ ࢎਊೞৈ ӝઓ ௏٘ܳ ېೝೠ׮ ݢ੷ ݽٚ ௏٘ܳ Compose۽ ৮੹൤ ࢜۽ ҳഅೞח ߑߨ੉ ੓णפ׮. ׮਺ਵ۽ ೨ब ௏٘ܳ ܻ࠙ೞৈ, ੌࠗ࠙ ࠗ࠙݅ Compose۽ ੘ࢿೞח ߑߨ੉ ੓णפ׮. ݃૑݄ਵ۽ ࢚ഐ਍ਊࢿ APIܳ ੉ਊೞৈ, ӝઓ ௏٘ܳ ېೝೞח ߑߨب ੓णפ׮.

Slide 12

Slide 12 text

How to use in Jetpack Compose? -(1) ݽٚ ௏٘ܳ Compose۽ ׮द ੘ࢿೠ׮ (X) -(2) ೨ब ௏٘ܳ ܻ࠙ೞৈ Composeীࢲ ੤ഝਊೠ׮ (X) -(3) ࢚ഐ ਍ਊࢿ APIܳ ࢎਊೞৈ ӝઓ ௏٘ܳ ېೝೠ׮ ✅ NAVER Map SDK != Open Source Project ইऔѱب ֎੉ߡ૑ب SDKח য়೑ࣗझо ইפۄࢲ ࣻ੿ೡ ߑߨ੉ হणפ׮. Ӓېࢲ ݃૑݄ ߑߨੋ ӝઓ ௏٘ܳ ېೝೞח ߑधਵ۽ ૓೯೮णפ׮.

Slide 13

Slide 13 text

Link: h tt ps://github.com/Moop-App/Moop-Android/pull/120 (1) Migrate using Compose API ୊਺ীח Compose APIܳ ੉ਊ೧ࢲ 
 ష੉ ೐۽ં౟ী ࢤ૞۽ ٸ۰߅ח(?) ੘সਸ ೮णפ׮.

Slide 14

Slide 14 text

Link: h tt ps://github.com/fornewid/naver-map-compose (2) For Jetpack Compose Unofficial wrapper library Ӓ ׮਺ীח ખ ؊ ҕਊചػ ਬૉா੉झী ݏ୾ 
 Compose wrapper ۄ੉࠳۞ܻܳ ٜ݅঻णפ׮.

Slide 15

Slide 15 text

Jetpack Composeীࢲ ֎੉ߡ૑ب SDK ࢎਊೞӝ ݾ಴ ࠂ੟ೠ Widgetਸ Composeীࢲ ੤ഝਊೞח ߑߨ

Slide 16

Slide 16 text

Toy Project੄ UseCase ҳഅೞӝ Link: h tt ps://github.com/Moop-App/Moop-Android/pull/120 ݢ੷ ష੉ ೐۽ં౟ী ҳഅೠ 5о૑ ਬૉா੉झܳ ࢓ಝࠁѷणפ׮.

Slide 17

Slide 17 text

Use Case 1: ૑ب ࠁৈ઱ӝ

Slide 18

Slide 18 text

MapView View Stystemীࢲח ۨ੉ইਓ XMLী MapViewܳ ࢶ঱ೞҊ

Slide 19

Slide 19 text

MapView class MapViewActivity : AppCompatActivity() { private var mapView: MapView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_map_view) mapView = findViewById(R.id.map_view) } } Activityীࢲ ࢸ੿೧઱ݶ ؾפ׮

Slide 20

Slide 20 text

MapView class MapComposeActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ... } } } Link: h tt ps://developer.android.com/jetpack/compose/interop/interop-apis#compose-in-views Composeীࢲח Layout XML ؀न setContentী Composableਸ ੹׳ೞݶ ؾפ׮

Slide 21

Slide 21 text

MapView val context = LocalContext.current AndroidView(factory = { context -> MapView(context) }) Link: h tt ps://developer.android.com/jetpack/compose/interop/interop-apis#views-in-compose ੉ۧѱ AndroidViewۄח APIо ઁҕغҊ ੓যࢲ 
 factoryীࢲ MapViewܳ ૒੽ ࢤࢿೞݶ ؾפ׮

Slide 22

Slide 22 text

Link: h tt ps://developer.android.com/guide/components/activities/activity-lifecycle Lifecycle Ӓۧ૑݅ Lifecycleী ؀೧ ઑӘ ؊ ׮ܞঠೞח ࠗ࠙੉ ੓णפ׮

Slide 23

Slide 23 text

MapView Lifecycle override fun onCreate(...) { super.onCreate(...) mapView?.onCreate(...) } override fun onStart() { super.onStart() mapView?.onStart() } override fun onResume() { super.onResume() mapView?.onResume() } override fun onPause() { super.onPause() mapView?.onPause() } override fun onStop() { super.onStop() mapView?.onStop() } override fun onDestroy() { super.onDestroy() mapView?.onDestroy() } 🤔 View Systemীࢲח ੉۠ ഋక۽ ഐ୹ೞҊ ੓঻ਸ ѩפ׮

Slide 24

Slide 24 text

MapView Lifecycle val context = LocalContext.current AndroidView(factory = { context -> MapView(context) }) ׮द ੉੹ ௏٘۽ جইоࠁѷणפ׮

Slide 25

Slide 25 text

MapView Lifecycle val context = LocalContext.current val mapView = remember { MapView(context) } AndroidView(factory = { mapView }) Link: h tt ps://developer.android.com/jetpack/compose/pe rf ormance/bestpractices#use-remember MapView੄ ೣࣻܳ ഐ୹೧ঠ ೞפө, ݢ੷ remember ೣࣻܳ ੉ਊ೧ࢲ MapViewܳ ܻ࠙೧յ ѩפ׮

Slide 26

Slide 26 text

Link: h tt ps://developer.android.com/jetpack/compose/lifecycle remember Recompositionীࢲ ੉੹ ࢚కܳ ਬ૑ೠ׮. ઺р઺р ੉ۧѱ Compose APIܳ ࢸݺೞח ठۄ੉٘о ੓णפ׮

Slide 27

Slide 27 text

MapView Lifecycle val context = LocalContext.current val mapView = remember(context){ MapView(context) } // (X) AndroidView(factory = { mapView }) Link: h tt ps://developer.android.com/jetpack/compose/pe rf ormance/bestpractices#use-remember ੉ ٸ remember ೣࣻী keyܳ ֍ਵݶ, keyо ߸҃ؼ ٸ݃׮ MapViewܳ ׮द ࢤࢿೞ޲۽ ઱੄೧ঠ ೤פ׮

Slide 28

Slide 28 text

MapView Lifecycle val context = LocalContext.current val mapView = remember { MapView(context) } AndroidView(factory = { mapView }) Link: h tt ps://developer.android.com/jetpack/compose/pe rf ormance/bestpractices#use-remember ৈӝࢲח MapViewо Compositionীࢲ݅ ೠߣ ࢤࢿغب۾ keyܳ ֍૑ ঋणפ׮

Slide 29

Slide 29 text

MapView Lifecycle val mapView = rememberMapViewWithLifecycle() AndroidView(factory = { mapView }) @Composable fun rememberMapViewWithLifecycle(): MapView { val context = LocalContext.current val mapView = remember { MapView(context) } ... return mapView } MapViewܳ ܻ࠙೮ਵפ, ੉ઁח Lifecycleਸ ୊ܻ೧ࠅөਃ?

Slide 30

Slide 30 text

MapView Lifecycle private fun getMapLifecycleObserver( mapView: MapView, savedInstanceState: Bundle? ) = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_CREATE -> mapView.onCreate(savedInstanceState) Lifecycle.Event.ON_START -> mapView.onStart() Lifecycle.Event.ON_RESUME -> mapView.onResume() Lifecycle.Event.ON_PAUSE -> mapView.onPause() Lifecycle.Event.ON_STOP -> mapView.onStop() Lifecycle.Event.ON_DESTROY -> mapView.onDestroy() else -> throw IllegalStateException() } } LifecycleEventObserverܳ ੉ਊ೧ࢲ пп੄ ੉߮౟݃׮ MapView੄ ೣࣻܳ ഐ୹೧સפ׮

Slide 31

Slide 31 text

MapView Lifecycle fun rememberMapViewWithLifecycle(): MapView { ... val lifecycle = LocalLifecycleOwner.current.lifecycle DisposableEffect(lifecycle, mapView) { val lifecycleObserver = getMapLifecycleObserver(mapView, null) lifecycle.addObserver(lifecycleObserver) onDispose { lifecycle.removeObserver(lifecycleObserver) } } return mapView } ӒܻҊ Observerܳ Lifecycleী োѾ/೧ઁ೧઱ח ௏٘ܳ ੘ࢿೞݶ ؾפ׮

Slide 32

Slide 32 text

MapView Lifecycle fun rememberMapViewWithLifecycle(): MapView { ... val lifecycle = LocalLifecycleOwner.current.lifecycle DisposableEffect(lifecycle, mapView) { val lifecycleObserver = getMapLifecycleObserver(mapView, null) lifecycle.addObserver(lifecycleObserver) onDispose { lifecycle.removeObserver(lifecycleObserver) } } return mapView } Link: h tt ps://developer.android.com/jetpack/compose/side-e ff ects#disposablee ff ect ੉ ٸ, DisposableEffect৬ onDisposeۄח Ѫਸ ੉ਊ೧ࢲ Observer੄ োѾҗ ೧ઁ द੼ਸ ੿੄೧઱ݶ غחؘਃ

Slide 33

Slide 33 text

Compositionਸ ઙܐೠ റ, ੿ܻ೧ঠ ೡ ٸ ࢎਊೠ׮. Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928 DisposableEffect

Slide 34

Slide 34 text

ഐ୹೧ঠ ೞח Lifecycle ೣࣻо ই૒ թই੓׮. Lifecycle Link: h tt ps://navermaps.github.io/android-map-sdk/guide-ko/2-1.html

Slide 35

Slide 35 text

SavedInstanceState class MapViewActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { ... mapView?.onCreate(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) mapView?.onSaveInstanceState(outState) } } View Systemীࢲח onCreate৬ onSaveInstanceStateীࢲ ೣࣻܳ ഐ୹೧઱ݶ غ঻ҳਃ

Slide 36

Slide 36 text

SavedInstanceState val savedInstanceState = rememberSavedInstanceState() val mapView = rememberMapViewWithLifecycle(savedInstanceState) AndroidView(factory = { mapView }) @Composable fun rememberSavedInstanceState(): Bundle { return rememberSaveable { Bundle() } // Survives config changes } Composeীࢲח Bundleਸ ૒੽ ҙܻೞח ߑߨਸ ࢎਊೡ ࣻ ੓যਃ ੉ ٸ, Bundleਸ rememberSaveable۽ ੷੢೤פ׮

Slide 37

Slide 37 text

Recomposition, Configuration Changesীࢲ ੉੹ ࢚కܳ ਬ૑ೠ׮. Link: h tt ps://developer.android.com/jetpack/compose/state#restore-ui-state rememberSaveable Configuration Changes

Slide 38

Slide 38 text

SavedInstanceState @Composable fun rememberMapViewWithLifecycle(savedInstanceState: Bundle): MapView { ... DisposableEffect(lifecycle, mapView, savedInstanceState) { val lifecycleObserver = getMapLifecycleObserver( mapView, savedInstanceState.takeUnless { it.isEmpty } ) onDispose { ... mapView.onSaveInstanceState(savedInstanceState) } } return mapView } Ӓېࢲ ૒੽ ҙܻೞח Bundle ё୓ܳ ੹׳೧઱ݶ ৮ܐؾפ׮

Slide 39

Slide 39 text

SavedInstanceState private fun getMapLifecycleObserver( mapView: MapView, savedInstanceState: Bundle? ) = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_CREATE -> mapView.onCreate(savedInstanceState) ... } } LifecycleEventObserverীࢲب োѾ೧઱ݶ غѷભ

Slide 40

Slide 40 text

onLowMemory override fun onLowMemory() { super.onLowMemory() mapView?.onLowMemory() } ݃૑݄ਵ۽ onLowMemory ੑפ׮ Viewীࢲח ೣࣻо ઁҕغҊ ੓যࢲ рױೠؘਃ

Slide 41

Slide 41 text

onLowMemory fun MapView.componentCallbacks(): ComponentCallbacks { return object : ComponentCallbacks { override fun onConfigurationChanged(config: Configuration) {} override fun onLowMemory() { [email protected]() } } } Composeীࢲח LifecycleObserver୊ۢ 
 ComponentCallbacksܳ ٜ݅যࢲ ഐ୹ೞݶ ؾפ׮

Slide 42

Slide 42 text

onLowMemory fun rememberMapViewWithLifecycle(): MapView { ... val lifecycle = LocalLifecycleOwner.current.lifecycle DisposableEffect(lifecycle, mapView) { val callbacks = mapView.componentCallbacks() context.registerComponentCallbacks(callbacks) onDispose { context.unregisterComponentCallbacks(callbacks) } } return mapView } ١۾/೧ઁೞח ࠗ࠙਷ খࢶ җ੿җ زੌ೤פ׮

Slide 43

Slide 43 text

MapViewח View ৉ೡ݅ਸ ׸׼ೠ׮. APIܳ ഐ୹ೞ۰ݶ ੋఠಕ੉झ ৉ೡਸ ೞח NaverMap ё୓о ೙ਃೞ׮. OnMapReadyCallback Link: h tt ps://navermaps.github.io/android-map-sdk/guide-ko/2-1.html MapView۽ ૑ب ࠁৈ઱ח ੘স਷ ՘լ૑݅ খਵ۽ ૑بܳ ஶ౟܀ೞח ੘সٜ੉ ೙ਃ೤פ׮

Slide 44

Slide 44 text

OnMapReadyCallback private val callback = object : OnMapReadyCallback { override fun onMapReady(naverMap: NaverMap) { ... } } mapView?.getMapAsync(callback) NaverMap ё୓ܳ ঳ਵ۰ݶ, OnMapReadyCallbackਸ ࢎਊೞৈ Callback ഋక۽ оઉয়ݶ ؾפ׮

Slide 45

Slide 45 text

OnMapReadyCallback suspend fun MapView.awaitMap(): NaverMap { return suspendCoroutine { continuation -> getMapAsync { continuation.resume(it) } } } val coroutineScope = rememberCoroutineScope() val mapView = rememberMapViewWithLifecycle(...) coroutineScope.launch { val naverMap: NaverMap = mapView.awaitMap() } Link: h tt ps://developer.android.com/jetpack/compose/side-e ff ects#remembercoroutinescope Composeীࢲח ௏ܖ౯ਵ۽ оઉয়ח ೣࣻܳ ٜ݅঻ҳਃ ೙ਃೡ ٸ CoroutineScopeܳ ࢤࢿ೧ NaverMap ё୓ܳ оઉৢ ࣻ ੓णפ׮

Slide 46

Slide 46 text

Compositionਸ ઙܐೠ റ ੗زਵ۽ ஂࣗغب۾ ߧਤо ૑੿ػ ௏ܖ౯ਸ प೯ೠ׮. Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928 rememberCoroutineScope

Slide 47

Slide 47 text

OnMapReadyCallback suspend fun MapView.awaitMap(): NaverMap { return suspendCoroutine { continuation -> getMapAsync { continuation.resume(it) } } } val coroutineScope = rememberCoroutineScope() val mapView = rememberMapViewWithLifecycle(...) coroutineScope.launch { val naverMap: NaverMap = mapView.awaitMap() } ✅ ੉ۧѱ NaverMap ё୓ܳ оઉয়ח ؘө૑ ޖࢎ൤ ݃ଢ଼णפ׮

Slide 48

Slide 48 text

Use Case 2: ૑ب ২࣌

Slide 49

Slide 49 text

૑ب ২࣌ mapView.getMapAsync { naverMap -> if (isDarkTheme) { naverMap.mapType = NaverMap.MapType.Navi naverMap.isNightModeEnabled = true } else { naverMap.mapType = NaverMap.MapType.Basic naverMap.isNightModeEnabled = false } } ঠрݽ٘ա ૑ب੄ ఋੑ ١ਸ ߸҃ೞҊ र׮ݶ, NaverMap ё୓ী׮о ૒੽ mapType ١ਸ ࢸ੿೧઱ݶ ؾפ׮

Slide 50

Slide 50 text

૑ب ২࣌ AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() if (isDarkTheme) { naverMap.mapType = NaverMap.MapType.Navi naverMap.isNightModeEnabled = true } else { naverMap.mapType = NaverMap.MapType.Basic naverMap.isNightModeEnabled = false } } } }) Composeীࢲب Ѣ੄ زੌೠ ௏٘ܳ Ӓ؀۽ ࢎਊೞݶ غѷणפ׮

Slide 51

Slide 51 text

૑ب ࣘࢿ ׮਺ਵ۽ Layout XMLীࢲ ݻ о૑ ӝࠄ੸ੋ ࣘࢿਸ ੿੄ೡ ࣻ ੓঻חؘਃ

Slide 52

Slide 52 text

૑ب ࣘࢿ val context = LocalContext.current val mapView = remember { MapView(context, naverMapOptions()) } AndroidView(factory = { mapView }) private fun naverMapOptions() = NaverMapOptions() .extent(LatLngBounds.from(LatLng(31.43, 122.37),LatLng(44.35, 132.0))) .locationButtonEnabled(true) .scaleBarEnabled(false) .minZoom(6.0) .camera(CameraPosition(LatLng.INVALID, 12.0)) ੉۠ ٜࠗ࠙ب ௏٘۽ ੿੄ೞҊ, MapView ࢤࢿ੗ী ੹׳ೞݶ ؾפ׮ ل ׮ ࠺तೠ ௏٘о ٜ݅য઎ભ?

Slide 53

Slide 53 text

Use Case 3: ૑ب ੉߮౟

Slide 54

Slide 54 text

૑ب ੉߮౟ mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _ -> /* Do domething*/ } } NaverMapী Click Listenerܳ ١۾ೞח ௏٘ੑפ׮

Slide 55

Slide 55 text

૑ب ੉߮౟ AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.setOnMapClickListener { _, _ -> /* Do domething*/ } } } }) Composeীࢲب زੌೠ ௏٘ܳ ੘ࢿೞݶ ؾפ׮

Slide 56

Slide 56 text

Use Case 4: ݃ழ ࠁৈ઱ӝ

Slide 57

Slide 57 text

݃ழ val marker = Marker().apply { captionText = "caption" position = LatLng(..., ...) icon = OverlayImage.fromResource(R.drawable.marker_icon) setOnClickListener { ... true } } Viewٚ Composeٚ ࢚ҙহ੉ ݃ழܳ ੉ۧѱ ࢤࢿ೤פ׮

Slide 58

Slide 58 text

Example: ӓ੢ ݃ழ ҙܻೞӝ var markers = listOf() fun render(theaters: List) { markers.forEach { it.map = null } markers = theaters.map { theater -> Marker().apply { ... map = naverMap } } } ӓ੢ ݾ۾ਸ ݃ழ۽ ಴दೞח ৘ઁ ௏٘ੑפ׮ Markerী NaverMapਸ ࢸ੿ೞҊ, null۽ ೧ઁ೧ঠ ೤פ׮

Slide 59

Slide 59 text

Example: ӓ੢ ݃ழ ҙܻೞӝ var markers by remember { mutableStateOf>(emptyList()) } LaunchedEffect(theaters) { val naverMap = mapView.awaitMap() markers.forEach { it.map = null } markers = theaters.map { theater -> Marker().apply { ... map = naverMap } } } Link: h tt ps://developer.android.com/jetpack/compose/side-e ff ects#launchede ff ect Composeীࢲب زੌೠ ௏٘ܳ ੘ࢿ೮ҳਃ LaunchedEffectܳ ࢎਊ೧ࢲ theaters੉ ߄Չ ٸ݅ ݃ழܳ ׮द Ӓܻب۾ ೮णפ׮

Slide 60

Slide 60 text

Composable ߧਤীࢲ suspend funܳ ഐ୹ೡ ٸ ࢎਊೠ׮. Composition द੼ ژח keyо ߸҃ؼ ٸ݃׮ ׮द ഐ୹ػ׮. LaunchedEffect Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928

Slide 61

Slide 61 text

Use Case 5: ஠ݫۄ ੉ز

Slide 62

Slide 62 text

஠ݫۄ ੉ز // move naverMap.moveCamera(CameraUpdate.zoomTo(12.0)) // animation naverMap.moveCamera( CameraUpdate .scrollAndZoomTo(LatLng(..., ...), 16.0) .animate(CameraAnimation.Fly) ) Link: h tt ps://navermaps.github.io/android-map-sdk/guide-ko/3-2.html ஠ݫۄܳ ੉زೞח ௏٘۽, গפݫ੉࣌ ৈࠗী ٮۄ ࢎਊߑߨ੉ ઑӘ ׮ܵפ׮ ׮নೠ APIо ੓ਵפ, ֎੉ߡ૑ب SDK੄ ޙࢲܳ ଵҊೞݶ ب਑ؼ Ѫ эणפ׮

Slide 63

Slide 63 text

Example: ݃ழ ࢶఖೞӝ Marker().apply { setOnClickListener { /* Marker Selected */ naverMap.moveCamera(...) } } mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _ -> /* Marker Unselected */ naverMap.moveCamera(...) } } ݃ழ৬ ૑بܳ ௿ܼೞݶ ஠ݫۄܳ ੉زೞח ৘ઁ ௏٘ੑפ׮

Slide 64

Slide 64 text

Example: ݃ழ ࢶఖೞӝ var selectedTheater by remember { mutableStateOf)(null) } Marker().apply { setOnClickListener { /* Marker Selected */ selectedTheater = theater } } mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _ -> /* Marker Unselected */ selectedTheater = null } } Composeীࢲب زੌೞѱ ೡ ࣻ ੓૑݅, ࢶఖػ ӓ੢ਸ ࢚క۽ ੿੄೧فҊ ࢚కо ߸҃ؼ ٸ ஠ݫۄܳ ੉زೞח ߑߨਸ ࢎਊ೮णפ׮

Slide 65

Slide 65 text

Composeীࢲ ҙ଴ೡ ࣻ ੓ח MutableStateܳ ࢤࢿೞח ೣࣻ. valueо ߸҃غݶ, valueܳ ੍ח Composable ೣࣻ੄ Recomposition੉ ৘ডػ׮. mutableStateOf Link: h tt ps://developer.android.com/jetpack/compose/state#state-in-composables interface MutableState : State { override var value: T } var value by remember { mutableStateOf(default) } Recompositionীࢲ ੉੹ valueܳ ਬ૑ೞ۰ݶ rememberܳ ࢎਊ೧ঠ ೠ׮.

Slide 66

Slide 66 text

Example: ݃ழ ࢶఖೞӝ var selectedTheater by remember { mutableStateOf)(null) } LaunchedEffect(selectedTheater) { val naverMap = mapView.awaitMap() if (selectedTheater != null) { naverMap.moveCamera(...) } else { naverMap.moveCamera(...) } } LaunchedEffectܳ ੉ਊೞৈ, ࢶఖػ ӓ੢ ч੉ ߸҃ؼ ٸ݃׮ ੸׼ೠ ਤ஖۽ ஠ݫۄܳ ੉زೡ ࣻ ੓ѷणפ׮

Slide 67

Slide 67 text

ৈӝࢲ ਫ਼Ӭ! Architecture: Unidirectional Data Flow var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } ) Link: h tt ps://developer.android.com/jetpack/compose/architecture 
 ࢚కח ইې۽ ੉زೞҊ ੉߮౟ח ਤ۽ ੉زೞח ٣੗ੋ ಁఢ.

Slide 68

Slide 68 text

val savedInstanceState = rememberSavedInstanceState() val mapView = rememberMapViewWithLifecycle(savedInstanceState, naverMapOptions()) AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = NaverMap.MapType.Navi naverMap.isNightModeEnabled = true naverMap.setOnMapClickListener { _, _ -> /* Do domething*/ } } } }) খীࢲ ੘ࢿ೮؍ ௏٘о ࢶ঱ഋ UIী ੸೤ೞѱ ҳഅغ঻ח૑ ࢤп೧ࠇद׮

Slide 69

Slide 69 text

@Composable fun NaverMap( modifier: Modifier = Modifier, mapOptions: NaverMapOptions = ..., mapProperties: MapProperties = ..., onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }, ) { val savedInstanceState = rememberSavedInstanceState() val mapView = rememberMapViewWithLifecycle(savedInstanceState, mapOptions) AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = mapProperties.mapType naverMap.isNightModeEnabled = mapProperties.isNightModeEnabled naverMap.setOnMapClickListener(onMapClick) } } }) } ੉ ௏٘ܳ хऱࢲ NaverMap੉ۄח Composableਸ ٜ݅ ࣻ ੓णפ׮

Slide 70

Slide 70 text

@Composable fun NaverMap( modifier: Modifier = Modifier, mapOptions: NaverMapOptions = ..., mapProperties: MapProperties = ..., onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }, ) { val savedInstanceState = rememberSavedInstanceState() val mapView = rememberMapViewWithLifecycle(savedInstanceState, mapOptions) AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = mapProperties.mapType naverMap.isNightModeEnabled = mapProperties.isNightModeEnabled naverMap.setOnMapClickListener(onMapClick) } } }) } NaverMap( mapOptions = naverMapOptions(), mapProperties = MapProperties( mapType = NaverMap.MapType.Navi, isNightModeEnabled = true, ), onMapClick = { _, _ -> /* Do domething*/ } ) ࢎਊೞח ௏٘ ৘दੑפ׮ Ӓۢ ࢶ঱ഋ UIܳ ҳഅ೮׮Ҋ ೡ ࣻ ੓ਸөਃ?

Slide 71

Slide 71 text

@Composable fun NaverMap( modifier: Modifier = Modifier, mapOptions: NaverMapOptions = ..., mapProperties: MapProperties = ..., onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }, ) { val savedInstanceState = rememberSavedInstanceState() val mapView = rememberMapViewWithLifecycle(savedInstanceState, mapOptions) AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = mapProperties.mapType naverMap.isNightModeEnabled = mapProperties.isNightModeEnabled naverMap.setOnMapClickListener(onMapClick) } } }) } 🤔 ࢚కо ߸҃ػ׮ݶ? 🫠 Recompositionীࢲ factoryח ׮द ഐ୹غ૑ ঋח׮. updateীࢲ јनೡ ࣻח ੓૑݅, ݒߣ side-e ff ectܳ ݅٘ח ޙઁ.

Slide 72

Slide 72 text

Library۽ ҕਊചೞӝ Link: h tt ps://github.com/fornewid/naver-map-compose ૑Әө૑ ੘ࢿೠ ௏٘ח ೞա੄ জীࢲ ࢎਊೞӝীח ୽࠙೮૑݅, ۄ੉࠳۞ܻ۽ ٜ݅ٸח ҕਊചػ ਬૉா੉झী ݏ୾ࢲ ੘ࢿ೧ঠѷભ? Ӓېࢲ ੉ߣীח খীࢲ ҳഅ೮؍ 5о૑ ਬૉா੉झܳ ѐࢶ೧ࠁ۰Ҋ ೤פ׮

Slide 73

Slide 73 text

Use Case 1: ૑ب ࠁৈ઱ӝ

Slide 74

Slide 74 text

૑ب ࠁৈ઱ӝ ✅ NaverMap(...) ੉ ࠗ࠙਷ ௼ѱ Ҋச ࠗ࠙੉ হ੉ ইө ੘ࢿ೮؍ ௏ٜ٘ਸ Ӓ؀۽ ࢎਊೞݶ ؾפ׮

Slide 75

Slide 75 text

Use Case 2: ૑ب ২࣌

Slide 76

Slide 76 text

૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ... AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = properties.mapType naverMap.isNightModeEnabled = properties.isNightModeEnabled } } }) ইө ੘ࢿ೮؍ NaverMap ё୓ী mapType ١ਸ ࢸ੿ೞח ௏٘ੑפ׮

Slide 77

Slide 77 text

૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ... AndroidView(factory = { mapView }) LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() naverMap.mapType = properties.mapType naverMap.isNightModeEnabled = properties.isNightModeEnabled } } Side-effect APIੋ LaunchedEffectܳ ੉ਊ೧ࢲ Compositionীࢲ݅ ഐ୹غب۾ ߸҃ೡ ࣻ ੓णפ׮ ੉۞ݶ Recompositionীࢲח ׮द ࢸ੿غ૑ ঋѷભ

Slide 78

Slide 78 text

૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ... AndroidView(factory = { mapView }) LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() naverMap.mapType = properties.mapType naverMap.isNightModeEnabled = properties.isNightModeEnabled } } prope rt iesо ߸҃غযب ߈৔غ૑ ঋח ޙઁ. ೞ૑݅ propertiesо ߸҃غযب ߈৔غ૑ ঋח ޙઁо ࢤӤפ׮

Slide 79

Slide 79 text

૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ... AndroidView(factory = { mapView }) val currentProperties by rememberUpdatedState(properties) LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() naverMap.mapType = currentProperties.mapType naverMap.isNightModeEnabled = currentProperties.isNightModeEnabled } } Link: h tt ps://developer.android.com/jetpack/compose/side-e ff ects#rememberupdatedstate rememberUpdatedState۽ propertiesܳ хऱࢲ ੹׳ೞݶ ݃૑݄ী ੹׳߉਷ propertiesী ੽Ӕೡ ࣻ ੓णפ׮

Slide 80

Slide 80 text

rememberUpdatedState ч੉ ߸҃غযب ੤द੘ೞ૑ ঋইঠ ೞח ബҗ੄ чਸ ଵઑೡ ٸ ࢎਊೠ׮. Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928

Slide 81

Slide 81 text

૑ب ২࣌ val currentProperties by rememberUpdatedState(properties) LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() naverMap.mapType = currentProperties.mapType naverMap.isNightModeEnabled = currentProperties.isNightModeEnabled } ௏٘۽ ׮द جইоࠇद׮ ੉ ௏٘ীࢲ side-effectо ߊࢤೞח द੼੉ হભ?

Slide 82

Slide 82 text

૑ب ২࣌ val currentProperties by rememberUpdatedState(properties) val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition(MapApplier(naverMap), parentComposition).apply { setContent { MapUpdater(mapProperties = currentProperties) } } try { awaitCancellation() } finally { composition.dispose() } } ࣁࠗ੸ੋ ࠗ࠙੉ ࡅ઎חؘ, पઁ۽ח ੉ۧѱ ੘ࢿ೮णפ׮

Slide 83

Slide 83 text

૑ب ২࣌ val currentProperties by rememberUpdatedState(properties) val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition(MapApplier(naverMap), parentComposition).apply { setContent { MapUpdater(mapProperties = currentProperties) } } try { awaitCancellation() } finally { composition.dispose() } } Link: h tt ps://developer.android.com/reference/kotlin/androidx/compose/runtime/#Composition ࢜۽਍ Compositionਸ द੘ೞח ߑߨ. rememberCompositionContext۽ parentCompositionਸ ٜ݅Ҋ Compositionਵ۽ child compositionਸ ٜ݅঻णפ׮ setContent উীࢲח Composableਸ ࢶ঱ೡ ࣻ ੓Ҋ, ݽف ՘աݶ disposeܳ ഐ୹೤פ׮

Slide 84

Slide 84 text

૑ب ২࣌ val currentProperties by rememberUpdatedState(properties) val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition(MapApplier(naverMap), parentComposition).apply { setContent { MapUpdater(mapProperties = currentProperties) } } try { awaitCancellation() } finally { composition.dispose() } } Link: h tt ps://developer.android.com/reference/kotlin/androidx/compose/runtime/Applier ૑ب ࣘࢿਸ Composable উীࢲ ҙܻೠ׮. ૑ب ࣘࢿ਷ MapUpdaterۄח Composable উীࢲ ҙܻೞҳਃ Child Compositionਸ ࢤࢿೡ ٸ, Composable Treeܳ ҙܻೞח Applierܳ ֍णפ׮

Slide 85

Slide 85 text

MapApplierח Composition ઺ী MapNode ౟ܻܳ ҙܻೞח ৉ೡ. MapUpdaterח ૑ب ࣘࢿਸ ҙܻೞח ComposeNodeܳ ࢤࢿೠ׮. MapUpdater NaverMap MapApplier, MapUpdater MapApplier MapPropertiesNode Listeners getMap() MapNode MapNode MapNode = ComposeNode NaverMap @Composable @Composable

Slide 86

Slide 86 text

MapApplier class MapApplier( val map: NaverMap, ) : AbstractApplier(MapNodeRoot) { private val decorations = mutableListOf() ... } interface MapNode object MapRootNode : MapNode class MapPropertiesNode(val map: NaverMap) : MapNode MapApplierীࢲ MapNode Listܳ ҙܻೞҊ, MapNode ҳഅ୓ ઺ী MapPropertiesNodeо ੓णפ׮

Slide 87

Slide 87 text

MapUpdater @Composable fun MapUpdater(mapProperties: MapProperties) { val map = (currentComposer.applier as MapApplier).map ComposeNode( factory = { MapPropertiesNode(map = map) }, update = { set(mapProperties.mapType) { map.mapType = it.value } set(mapProperties.isNightModeEnabled) { map.isNightModeEnabled = it } } ) Link: h tt ps://developer.android.com/reference/kotlin/androidx/compose/runtime/#ComposeNode MapPropertiesNodeח MapUpdater Composable ղࠗীࢲ ComposeNode APIܳ ੉ਊ೧ࢲ ࢤࢿೞҳਃ AndroidView API୊ۢ factoryীࢲ ࢤࢿ, updateীࢲ јन೧઱ח ഋక۽ غয ੓णפ׮

Slide 88

Slide 88 text

MapProperties data class MapProperties( public val mapType: MapType = MapType.Basic, public val isNightModeEnabled: Boolean = false, ) @Immutable enum class MapType( public val value: com.naver.maps.map.NaverMap.MapType ) { Basic(com.naver.maps.map.NaverMap.MapType.Basic), ... } Link: h tt ps://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8 MapPropertiesח mapType э਷ ૑ب੄ ࣘࢿҗ ݒடغח data classੑפ׮ ৈӝࢲ MapType਷ ֎੉ߡ૑ب SDK੄ MapTypeਸ хऱח ഋక۽ غয ੓חؘਃ

Slide 89

Slide 89 text

MapProperties data class MapProperties( public val mapType: MapType = MapType.Basic, public val isNightModeEnabled: Boolean = false, ) @Immutable enum class MapType( public val value: com.naver.maps.map.NaverMap.MapType ) { Basic(com.naver.maps.map.NaverMap.MapType.Basic), ... } Link: h tt ps://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8 Compose ஹ౵ੌ۞о प೯غ૑ ঋח ݽٕ੄ ௿ېझח ࠛউ੿ೠ Ѫਵ۽ ୶ۿػ׮. wrapper classী ࠛ߸ਸ ੿੄ೞৈ Recompositionਸ ୭ࣗചೡ ࣻ ੓׮. Ӓ ੉ਬח, ֎੉ߡ૑ب SDKח Compose ஹ౵ੌ۞о प೯غ૑ ঋই Composeীࢲח ੉۠ ௿ېझܳ unstable۽ ୶ۿೞӝ ٸޙੑפ׮ @immutableਸ ୶оೞৈ ࠛ೙ਃೠ recompositionਸ ઴ੌ ࣻ ੓णפ׮

Slide 90

Slide 90 text

૑ب ২࣌ ✅ NaverMap( ... mapProperties = MapProperties( mapType = NaverMap.MapType.Navi, isNightModeEnabled = true, ), ... ) ૑ب ২࣌ਸ ࢚క۽ ੹׳ೞח ࠗ࠙ਸ ৮ࢿ೮णפ׮

Slide 91

Slide 91 text

Use Case 3: ૑ب ੉߮౟ ੉ઁ ૑ب ੉߮౟۽ ֈযоࠁѷणפ׮

Slide 92

Slide 92 text

૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ... val currentProperties by rememberUpdatedState(properties) val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition( MapApplier(naverMap), parentComposition ).apply { setContent { MapUpdater(mapProperties = currentProperties) } } ߑӘө૑ ࠄ ૑ب ২࣌ ௏٘۽, propertiesܳ ੹׳೧઱ח ࠗ࠙ਸ ੘ࢿ೮חؘਃ

Slide 93

Slide 93 text

૑ب ੉߮౟ @Composable fun NaverMap(onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }) { ... val mapClickListeners = remember { MapClickListeners() } .also { it.onMapClick = onMapClick } val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition( MapApplier(naverMap), parentComposition ).apply { setContent { MapUpdater(clickListeners = mapClickListeners) } } ૑ب ੉߮౟ীࢲח onMapClick੉ۄח ۈ׮ܳ ੹׳೤פ׮

Slide 94

Slide 94 text

૑ب ੉߮౟ @Composable fun NaverMap(onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }) { ... val mapClickListeners = remember { MapClickListeners() } .also { it.onMapClick = onMapClick } val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition( MapApplier(naverMap), parentComposition ).apply { setContent { MapUpdater(clickListeners = mapClickListeners) } } class MapClickListeners { var onMapClick: (PointF, LatLng) -> Unit by mutableStateOf({ _, _ -> }) } MapClickListenersח onMapClick ۈ׮ܳ MutableState۽ ҙܻೞҊ, recompositionীࢲ MapClickListenersо ߄Շ૑ ঋب۾ remember۽ ӝর೧સפ׮

Slide 95

Slide 95 text

૑ب ੉߮౟ @Composable fun NaverMap(onMapClick: (PointF, LatLng) -> Unit = { _, _ -> }) { ... val mapClickListeners = remember { MapClickListeners() } .also { it.onMapClick = onMapClick } val parentComposition = rememberCompositionContext() LaunchedEffect(Unit) { val naverMap = mapView.awaitMap() val composition = Composition( MapApplier(naverMap), parentComposition ).apply { setContent { MapUpdater(clickListeners = mapClickListeners) } } Ӓېࢲ MapUpdater ղࠗীࢲ ੉߮౟о ߊࢤೞݶ ੉۠ ࣽࢲ۽ ੉߮౟о ࢚ਤ۽ ੹౵ؾפ׮

Slide 96

Slide 96 text

// Composition ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode( factory = { MapPropertiesNode(clickListeners = clickListeners) }, update = { update(clickListeners) { this.clickListeners = it } }, ) } class MapPropertiesNode( var map: NaverMap, var clickListeners: MapClickListeners, ) : MapNode { override fun onAttached() { map.setOnMapClickListener { point, coord -> clickListeners.onMapClick(point, coord) } } MapUpdaterীࢲח Composition द੼ী clickListenersܳ ੹׳೧઱Ҋ

Slide 97

Slide 97 text

// Recomposition ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode( factory = { MapPropertiesNode(clickListeners = clickListeners) }, update = { update(clickListeners) { this.clickListeners = it } }, ) } class MapPropertiesNode( var map: NaverMap, var clickListeners: MapClickListeners, ) : MapNode { override fun onAttached() { map.setOnMapClickListener { point, coord -> clickListeners.onMapClick(point, coord) } } Recomposition द੼ীח ۈ׮о ߄Շ঻ਸ ࣻ ੓ਵפ MapClickListenersܳ ׮द Ү୓೧સפ׮

Slide 98

Slide 98 text

૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode( factory = { MapPropertiesNode(clickListeners = clickListeners) }, update = { update(clickListeners) { this.clickListeners = it } }, ) } class MapPropertiesNode( var map: NaverMap, var clickListeners: MapClickListeners, ) : MapNode { override fun onAttached() { map.setOnMapClickListener { point, coord -> clickListeners.onMapClick(point, coord) } } MapPropertiesNodeо attachغݶ NaverMapী Listenerܳ ١۾೤פ׮

Slide 99

Slide 99 text

૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode( factory = { MapPropertiesNode(clickListeners = clickListeners) }, update = { update(clickListeners) { this.clickListeners = it } }, ) } class MapPropertiesNode( var map: NaverMap, var clickListeners: MapClickListeners, ) : MapNode { override fun onAttached() { map.setOnMapClickListener { point, coord -> clickListeners.onMapClick(point, coord) } } ֎੉ߡ૑بীࢲ ੉߮౟о ߊࢤೞݶ ੉۠ ࣽਵ۽ ࢚ਤ۽ ੹౵ؾפ׮

Slide 100

Slide 100 text

૑ب ੉߮౟ ✅ NaverMap( ... onMapClick = { _, _ -> /* Do domething*/ } ... ) ੉ۧѱ ֎੉ߡ૑بীࢲ ੉߮౟ܳ ׮ܖח ࠗ࠙ب ҳഅ೧ࠌणפ׮

Slide 101

Slide 101 text

Use Case 4: ݃ழ ࠁৈ઱ӝ ݃ழܳ ࠁৈ઱ח ࠗ࠙ਸ ׮द ࢓ಝࠁѷणפ׮

Slide 102

Slide 102 text

// State ݃ழ val marker = Marker().apply { captionText = "caption" position = LatLng(..., ...) icon = OverlayImage.fromResource(R.drawable.marker_icon) setOnClickListener { ... true } map = naverMap } ੉ۧѱ ࢚కܳ ੿੄ೞח ࠗ࠙੉ ੓Ҋ

Slide 103

Slide 103 text

// Event ݃ழ val marker = Marker().apply { captionText = "caption" position = LatLng(..., ...) icon = OverlayImage.fromResource(R.drawable.marker_icon) setOnClickListener { ... true } map = naverMap } ੉߮౟ী ؀ೠ ࠗ࠙੉ ੓Ҋ

Slide 104

Slide 104 text

// Display ݃ழ val marker = Marker().apply { captionText = "caption" position = LatLng(..., ...) icon = OverlayImage.fromResource(R.drawable.marker_icon) setOnClickListener { ... true } map = naverMap } ֎੉ߡ૑بী ࠁৈ઱ח ࠗ࠙੉ ੓णפ׮

Slide 105

Slide 105 text

݃ழ Marker( captionText = "caption", position = LatLng(..., ...), icon = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) Composeীࢲח ੉۠ ഋక۽ ࢎਊೡ ࣻ ੓ѱ ٜ݅঻णפ׮

Slide 106

Slide 106 text

݃ழ Marker( captionText = "caption", position = LatLng(..., ...), icon = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) @Composable fun Marker( captionText: String? = ..., position: LatLng = ..., icon: OverlayImage = ..., onClick: (Marker) -> Boolean = { false }, ) { ... } ੉੹୊ۢ ComposeNodeܳ ഝਊ೧ࢲ Marker Composableਸ ٜ݅ݶ ؾפ׮

Slide 107

Slide 107 text

ComposeNodeܳ ࢤࢿೞৈ ࢚కܳ সؘ੉౟. MapApplierܳ ా೧ ૑بী ಴दೠ׮. Marker NaverMap Marker ҳઑ MapApplier MarkerNode Marker onClick getMap() MapNode MapNode MapNode = ComposeNode NaverMap @Composable @Composable Link: h tt ps://github.com/fornewid/naver-map-compose/.../com/naver/maps/map/compose/Marker.kt

Slide 108

Slide 108 text

݃ழ Marker( captionText = "caption", position = LatLng(..., ...), icon = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) // map = naverMap ? NaverMapী ಴द೧઱ח ࠗ࠙਷ ௏٘۽ যڌѱ ಴അೞݶ જਸөਃ?

Slide 109

Slide 109 text

݃ழ NaverMap(...) { Marker( captionText = "caption", position = LatLng(..., ...), icon = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) } ੉ۧѱ NaverMap Composable ղࠗী Child Composable۽ ࢶ঱೧઱ݶ ؾפ׮

Slide 110

Slide 110 text

Example: ӓ੢ ݃ழ ҙܻೞӝ var markers by remember { mutableStateOf>(emptyList()) } LaunchedEffect(theaters) { val naverMap = mapView.awaitMap() markers.forEach { it.map = null } markers = theaters.map { theater -> Marker().apply { ... map = naverMap } } } ష੉ ೐۽ં౟ীࢲ ੘ࢿ೮؍ ௏٘ח UIܳ Side-effect۽ ҙܻೞח ו՝੉঻חؘਃ

Slide 111

Slide 111 text

Example: ӓ੢ ݃ழ ҙܻೞӝ NaverMap(...) { theaters.forEach { theater -> Marker( ... ) } } ੉ઁ ખ ؊ ࢶ঱ഋ UIী оӰѱ ݃ழܳ ಴दೡ ࣻ ੓णפ׮

Slide 112

Slide 112 text

݃ழ ࠁৈ઱ӝ ✅ NaverMap { Marker( position = LatLng(..., ...), ... onClick = { /* Do domething*/ true }, ) }

Slide 113

Slide 113 text

Use Case 5: ஠ݫۄ ੉ز ࢎਊ੗о ૑بܳ झ௼܀೧ࢲ ஠ݫۄ ਤ஖ܳ ੉زೠ ׮਺

Slide 114

Slide 114 text

Use Case 5: ஠ݫۄ ੉ز ചݶਸ ഥ੹ೞݶ

Slide 115

Slide 115 text

Use Case 5: ஠ݫۄ ੉ز ഥ੹ द, ஠ݫۄ ਤ஖о ୡӝചغח ޙઁ!

Slide 116

Slide 116 text

Use Case 5: ஠ݫۄ ੉ز Con fi g Changes द੼ী ࢚కܳ ਬ૑ೡ ࣻ হਸө? rememberSaveable

Slide 117

Slide 117 text

஠ݫۄী ؀ೠ ࢚క, ੉߮౟ܳ ҙܻೞח State Holder. MapUpdater CameraPositionState NaverMap MapPropertiesNode CameraPositionState CameraPosition NaverMap Listeners Composition only State Holder Event New CameraPosition @Composable Compositionীࢲ݅ ݃૑݄ী ੷੢ೠ ਤ஖۽ ஠ݫۄܳ ੉ز೤פ׮

Slide 118

Slide 118 text

࢚క ҙܻ: State Holder Link: h tt ps://developer.android.com/jetpack/compose/state#state-holder-source-of-truth ࠂ੟ೠ UI੄ ࢚క৬ UI ۽૒ਸ ನೣೞח ௿ېझ. Composable੄ ࠂ੟ࢿਸ ઴ৈળ׮.

Slide 119

Slide 119 text

internal class MapPropertiesNode( val map: NaverMap, cameraPositionState: CameraPositionState, ) : MapNode { init { cameraPositionState.setMap(map) } private val cameraIdleListener = NaverMap.OnCameraIdleListener { cameraPositionState.rawPosition = map.cameraPosition } private val cameraChangeListener = NaverMap.OnCameraChangeListener { _, _ -> cameraPositionState.rawPosition = map.cameraPosition } override fun onAttached() { map.addOnCameraIdleListener(cameraIdleListener) map.addOnCameraChangeListener(cameraChangeListener) } } MapPropertiesNode ௏٘ܳ ࢓ಝࠇद׮

Slide 120

Slide 120 text

internal class MapPropertiesNode( val map: NaverMap, cameraPositionState: CameraPositionState, ) : MapNode { init { cameraPositionState.setMap(map) } private val cameraIdleListener = NaverMap.OnCameraIdleListener { cameraPositionState.rawPosition = map.cameraPosition } private val cameraChangeListener = NaverMap.OnCameraChangeListener { _, _ -> cameraPositionState.rawPosition = map.cameraPosition } override fun onAttached() { map.addOnCameraIdleListener(cameraIdleListener) map.addOnCameraChangeListener(cameraChangeListener) } } cameraPositionStateী NaverMap ё୓ܳ ࢸ੿೧઱Ҋ Listenerܳ ా೧, ߄Ո ஠ݫۄ ਤ஖о ٜযয়ݶ rawPositionਸ সؘ੉౟ ೧સפ׮

Slide 121

Slide 121 text

public class CameraPositionState(position: CameraPosition = ...) { internal var rawPosition by mutableStateOf(position) public var position: CameraPosition get() = rawPosition set(value) { ... } internal fun setMap(map: NaverMap?) { this.map = map if (map != null) { map.moveCamera(CameraUpdate.toCameraPosition(position)) } } } NaverMap੉ ׮द ࢸ੿غݶ(=Composition), ݃૑݄ ਤ஖۽ ੉زೠ׮. NaverMap੉ ׮द ࢸ੿غݶ Compositionਵ۽ ౸ױೞҊ, ݃૑݄ ਤ஖۽ ੉زदெ઱ח ୊ܻо ٜযо ੓णפ׮

Slide 122

Slide 122 text

@Composable public inline fun rememberCameraPositionState( key: String? = null, crossinline init: CameraPositionState.() -> Unit = {}, ): CameraPositionState = rememberSaveable( key = key, saver = CameraPositionState.Saver ) { CameraPositionState().apply(init) } public val Saver: Saver = Saver( save = { it.position }, restore = { CameraPositionState(it) } ) Con fi g Changes द੼ী ݃૑݄ ࢚కܳ ੷੢೧ળ׮. Link: h tt ps://developer.android.com/jetpack/compose/state#restore-ui-state rememberSaveableܳ ੉ਊ೧ࢲ Config Changes द੼ী ݃૑݄ ࢚కܳ ੷੢/ࠂҳ ೧સפ׮

Slide 123

Slide 123 text

val cameraPositionState = rememberCameraPositionState() NaverMap(cameraPositionState = cameraPositionState) val coroutineScope = rememberCoroutineScope() coroutineScope.launch { cameraPositionState.animate( CameraUpdate.scrollTo(position), animation = CameraAnimation.Fly, durationMs = 1_000 ) } ஠ݫۄ ੉ز ✅ ࢎਊೡ ٸח NaverMap Composableী State Holderܳ ੹׳೧઱Ҋ ੉زೡ ٸח ௏ܖ౯ਸ ੉ਊೞৈ গפݫ੉࣌ ୊ܻܳ ೡ ࣻ ੓णפ׮

Slide 124

Slide 124 text

● Composable Lifecycle - Composition - Recomposition ● Architecture - Unidirectional Data Flow - State Holder ● State - remember - rememberSaveable - mutableStateOf - @Immutable Keywords ● Side-effects - LaunchedEffect - DisposableEffect - rememberCoroutineScope - rememberUpdatedState ● Interoperability APIs - AndroidView - setContent ● Custom Composition - rememberCompositionContext - Composition - Applier, ComposeNode

Slide 125

Slide 125 text

೙ਃೠ ӝמ੉ ੓ਵݶ, ੉गܳ ١۾೧઱ࣁਃ! 👆

Slide 126

Slide 126 text

Q & A хࢎ೤פ׮!