$30 off During Our Annual Pro Sale. View Details »

NAVER Map in Jetpack Compose

Sungyong An
November 19, 2022

NAVER Map in Jetpack Compose

11/19 (토) DevFest 2022 - GDG Songdo, Incheon & GDSC Inha, TUKorea 행사에서 발표한 자료입니다.
https://festa.io/events/2758

아래 오픈소스 라이브러리에 대한 내용입니다.
https://github.com/fornewid/naver-map-compose

Sungyong An

November 19, 2022
Tweet

More Decks by Sungyong An

Other Decks in Programming

Transcript

  1. Songdo, Incheon NAVER Map in Jetpack Compose Sungyong An 


    Android GDE, NAVER WEBTOON
  2. Sungyong An NAVER WEBTOON Android GDE @fornewid Link: h tt

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

    ps://github.com/fornewid Slide Template ठۄ੉٘ ೞױী ݂௼о ੓णפ׮.
  4. Code Template View Compose ਋ஏ ࢚ױী যڃ ௏٘ੋ૑ ই੉௑ਸ ಴द೤פ׮.

    Compose ௏٘݅ ઝஏী ֣࢝ ߄ܳ ಴द೤פ׮.
  5. Link: h tt ps://developersonair.withgoogle.com/events/composecamp_22kr Jetpack Compose ೟ण੉ ೙ਃೠ ࠙਷ Compose

    Camp ೯ࢎী ଵৈ೧ࠁࣁਃ!
  6. Link: h tt ps://developer.android.com/develop/ui/views/layout/declaring-layout <?xml version="1.0" encoding="utf-8"?> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout> View System അসীࢲח View Systemਵ۽ ѐߊೞח Ѫ੉ ੊ࣼೡ Ѫ эणפ׮. ୊਺ উ٘۽੉٘ ѐߊਸ ੽ೡ ٸب ࠁా Layout XMLࠗఠ द੘ೞભ.
  7. Link: h tt ps://developer.android.com/jetpack/compose Jetpack Compose (Modern Android Development )

    ਃ્ীח Jetpack Composeо ݆੉ ࣗѐغҊ ੓ҳਃ. ࢜۽਍ ࣗध ੺߈਷ Composeੌ ੿ب۽ ҙबਸ ߉Ҋ ੓णפ׮.
  8. Link: h tt ps://developer.android.com/jetpack/compose/interop/migration-strategy Migrate from View to Compose 🤔

    Ӓ۞׮ࠁפ ݆਷ ٜ࠙੉ Viewܳ Compose۽ ੹ജೞҊ ੓Ѣա, ੹ജਸ Ҋ۰ೞҊ ੓ਸѢۄ ࢤп೤פ׮.
  9. Toy Project Link: h tt ps://github.com/Moop-App/Moop-Android য়ט਷ അসীࢲ ੸ਊೠ ղਊ਷

    ইפҊ, ష੉ ೐۽ં౟ী ؀ೠ ղਊੑפ׮.
  10. Link: h tt ps://github.com/navermaps/android-map-sdk Official SDK based on View 🤔

    ֎੉ߡ૑ب SDKח View Systemਵ۽ ҳഅغয ੓णפ׮. Ӓېࢲ ੉Ѧ ஹನૉীࢲ যڌѱ ॶ ࣻ ੓ਸ૑ Ҋ޹೮ભ.
  11. How to use in Jetpack Compose? -(1) ݽٚ ௏٘ܳ Compose۽

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

    ׮द ੘ࢿೠ׮ (X) -(2) ೨ब ௏٘ܳ ܻ࠙ೞৈ Composeীࢲ ੤ഝਊೠ׮ (X) -(3) ࢚ഐ ਍ਊࢿ APIܳ ࢎਊೞৈ ӝઓ ௏٘ܳ ېೝೠ׮ ✅ NAVER Map SDK != Open Source Project ইऔѱب ֎੉ߡ૑ب SDKח য়೑ࣗझо ইפۄࢲ ࣻ੿ೡ ߑߨ੉ হणפ׮. Ӓېࢲ ݃૑݄ ߑߨੋ ӝઓ ௏٘ܳ ېೝೞח ߑधਵ۽ ૓೯೮णפ׮.
  13. Link: h tt ps://github.com/Moop-App/Moop-Android/pull/120 (1) Migrate using Compose API ୊਺ীח

    Compose APIܳ ੉ਊ೧ࢲ 
 ష੉ ೐۽ં౟ী ࢤ૞۽ ٸ۰߅ח(?) ੘সਸ ೮णפ׮.
  14. Link: h tt ps://github.com/fornewid/naver-map-compose (2) For Jetpack Compose Unofficial wrapper

    library Ӓ ׮਺ীח ખ ؊ ҕਊചػ ਬૉா੉झী ݏ୾ 
 Compose wrapper ۄ੉࠳۞ܻܳ ٜ݅঻णפ׮.
  15. Jetpack Composeীࢲ ֎੉ߡ૑ب SDK ࢎਊೞӝ ݾ಴ ࠂ੟ೠ Widgetਸ Composeীࢲ ੤ഝਊೞח

    ߑߨ
  16. Toy Project੄ UseCase ҳഅೞӝ Link: h tt ps://github.com/Moop-App/Moop-Android/pull/120 ݢ੷ ష੉

    ೐۽ં౟ী ҳഅೠ 5о૑ ਬૉா੉झܳ ࢓ಝࠁѷणפ׮.
  17. Use Case 1: ૑ب ࠁৈ઱ӝ

  18. MapView <com.naver.maps.map.MapView android:id="@+id/map_view" android:layout_width="match_parent" android:layout_height="match_parent" /> View Stystemীࢲח ۨ੉ইਓ XMLী

    MapViewܳ ࢶ঱ೞҊ
  19. 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ীࢲ ࢸ੿೧઱ݶ ؾפ׮
  20. 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ਸ ੹׳ೞݶ ؾפ׮
  21. 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ܳ ૒੽ ࢤࢿೞݶ ؾפ׮
  22. Link: h tt ps://developer.android.com/guide/components/activities/activity-lifecycle Lifecycle Ӓۧ૑݅ Lifecycleী ؀೧ ઑӘ ؊

    ׮ܞঠೞח ࠗ࠙੉ ੓णפ׮
  23. 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ীࢲח ੉۠ ഋక۽ ഐ୹ೞҊ ੓঻ਸ ѩפ׮
  24. MapView Lifecycle val context = LocalContext.current AndroidView(factory = { context

    -> MapView(context) }) ׮द ੉੹ ௏٘۽ جইоࠁѷणפ׮
  25. 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ܳ ܻ࠙೧յ ѩפ׮
  26. Link: h tt ps://developer.android.com/jetpack/compose/lifecycle remember Recompositionীࢲ ੉੹ ࢚కܳ ਬ૑ೠ׮. ઺р઺р

    ੉ۧѱ Compose APIܳ ࢸݺೞח ठۄ੉٘о ੓णפ׮
  27. 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ܳ ׮द ࢤࢿೞ޲۽ ઱੄೧ঠ ೤פ׮
  28. 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ܳ ֍૑ ঋणפ׮
  29. 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ਸ ୊ܻ೧ࠅөਃ?
  30. 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੄ ೣࣻܳ ഐ୹೧સפ׮
  31. 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ী োѾ/೧ઁ೧઱ח ௏٘ܳ ੘ࢿೞݶ ؾפ׮
  32. 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੄ োѾҗ ೧ઁ द੼ਸ ੿੄೧઱ݶ غחؘਃ
  33. Compositionਸ ઙܐೠ റ, ੿ܻ೧ঠ ೡ ٸ ࢎਊೠ׮. Source: h tt

    ps://medium.com/mobile-app-development-publication/a4867f876928 DisposableEffect
  34. ഐ୹೧ঠ ೞח Lifecycle ೣࣻо ই૒ թই੓׮. Lifecycle Link: h tt

    ps://navermaps.github.io/android-map-sdk/guide-ko/2-1.html
  35. 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ীࢲ ೣࣻܳ ഐ୹೧઱ݶ غ঻ҳਃ
  36. 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۽ ੷੢೤פ׮
  37. Recomposition, Configuration Changesীࢲ ੉੹ ࢚కܳ ਬ૑ೠ׮. Link: h tt ps://developer.android.com/jetpack/compose/state#restore-ui-state

    rememberSaveable Configuration Changes
  38. 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 ё୓ܳ ੹׳೧઱ݶ ৮ܐؾפ׮
  39. SavedInstanceState private fun getMapLifecycleObserver( mapView: MapView, savedInstanceState: Bundle? ) =

    LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_CREATE -> mapView.onCreate(savedInstanceState) ... } } LifecycleEventObserverীࢲب োѾ೧઱ݶ غѷભ
  40. onLowMemory override fun onLowMemory() { super.onLowMemory() mapView?.onLowMemory() } ݃૑݄ਵ۽ onLowMemory

    ੑפ׮ Viewীࢲח ೣࣻо ઁҕغҊ ੓যࢲ рױೠؘਃ
  41. onLowMemory fun MapView.componentCallbacks(): ComponentCallbacks { return object : ComponentCallbacks {

    override fun onConfigurationChanged(config: Configuration) {} override fun onLowMemory() { this@componentCallbacks.onLowMemory() } } } Composeীࢲח LifecycleObserver୊ۢ 
 ComponentCallbacksܳ ٜ݅যࢲ ഐ୹ೞݶ ؾפ׮
  42. 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 } ١۾/೧ઁೞח ࠗ࠙਷ খࢶ җ੿җ زੌ೤פ׮
  43. MapViewח View ৉ೡ݅ਸ ׸׼ೠ׮. APIܳ ഐ୹ೞ۰ݶ ੋఠಕ੉झ ৉ೡਸ ೞח NaverMap

    ё୓о ೙ਃೞ׮. OnMapReadyCallback Link: h tt ps://navermaps.github.io/android-map-sdk/guide-ko/2-1.html MapView۽ ૑ب ࠁৈ઱ח ੘স਷ ՘լ૑݅ খਵ۽ ૑بܳ ஶ౟܀ೞח ੘সٜ੉ ೙ਃ೤פ׮
  44. OnMapReadyCallback private val callback = object : OnMapReadyCallback { override

    fun onMapReady(naverMap: NaverMap) { ... } } mapView?.getMapAsync(callback) NaverMap ё୓ܳ ঳ਵ۰ݶ, OnMapReadyCallbackਸ ࢎਊೞৈ Callback ഋక۽ оઉয়ݶ ؾפ׮
  45. 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 ё୓ܳ оઉৢ ࣻ ੓णפ׮
  46. Compositionਸ ઙܐೠ റ ੗زਵ۽ ஂࣗغب۾ ߧਤо ૑੿ػ ௏ܖ౯ਸ प೯ೠ׮. Source:

    h tt ps://medium.com/mobile-app-development-publication/a4867f876928 rememberCoroutineScope
  47. 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 ё୓ܳ оઉয়ח ؘө૑ ޖࢎ൤ ݃ଢ଼णפ׮
  48. Use Case 2: ૑ب ২࣌

  49. ૑ب ২࣌ mapView.getMapAsync { naverMap -> if (isDarkTheme) { naverMap.mapType

    = NaverMap.MapType.Navi naverMap.isNightModeEnabled = true } else { naverMap.mapType = NaverMap.MapType.Basic naverMap.isNightModeEnabled = false } } ঠрݽ٘ա ૑ب੄ ఋੑ ١ਸ ߸҃ೞҊ र׮ݶ, NaverMap ё୓ী׮о ૒੽ mapType ١ਸ ࢸ੿೧઱ݶ ؾפ׮
  50. ૑ب ২࣌ 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ীࢲب Ѣ੄ زੌೠ ௏٘ܳ Ӓ؀۽ ࢎਊೞݶ غѷणפ׮
  51. ૑ب ࣘࢿ <com.naver.maps.map.MapView android:id="@+id/map_view" android:layout_width="match_parent" android:layout_height="match_parent" app:navermap_extent="31.43,122.37,44.35,132" app:navermap_locationButtonEnabled="true" app:navermap_scaleBarEnabled="false" app:navermap_minZoom="6"

    app:navermap_zoom="12" /> ׮਺ਵ۽ Layout XMLীࢲ ݻ о૑ ӝࠄ੸ੋ ࣘࢿਸ ੿੄ೡ ࣻ ੓঻חؘਃ
  52. ૑ب ࣘࢿ 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 ࢤࢿ੗ী ੹׳ೞݶ ؾפ׮ ل ׮ ࠺तೠ ௏٘о ٜ݅য઎ભ?
  53. Use Case 3: ૑ب ੉߮౟

  54. ૑ب ੉߮౟ mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _

    -> /* Do domething*/ } } NaverMapী Click Listenerܳ ١۾ೞח ௏٘ੑפ׮
  55. ૑ب ੉߮౟ AndroidView(factory = { mapView.apply { coroutineScope.launch { val

    naverMap = awaitMap() naverMap.setOnMapClickListener { _, _ -> /* Do domething*/ } } } }) Composeীࢲب زੌೠ ௏٘ܳ ੘ࢿೞݶ ؾפ׮
  56. Use Case 4: ݃ழ ࠁৈ઱ӝ

  57. ݃ழ val marker = Marker().apply { captionText = "caption" position

    = LatLng(..., ...) icon = OverlayImage.fromResource(R.drawable.marker_icon) setOnClickListener { ... true } } Viewٚ Composeٚ ࢚ҙহ੉ ݃ழܳ ੉ۧѱ ࢤࢿ೤פ׮
  58. Example: ӓ੢ ݃ழ ҙܻೞӝ var markers = listOf<Marker>() fun render(theaters:

    List<TheaterMarkerUiModel>) { markers.forEach { it.map = null } markers = theaters.map { theater -> Marker().apply { ... map = naverMap } } } ӓ੢ ݾ۾ਸ ݃ழ۽ ಴दೞח ৘ઁ ௏٘ੑפ׮ Markerী NaverMapਸ ࢸ੿ೞҊ, null۽ ೧ઁ೧ঠ ೤פ׮
  59. Example: ӓ੢ ݃ழ ҙܻೞӝ var markers by remember { mutableStateOf<List<Marker>>(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੉ ߄Չ ٸ݅ ݃ழܳ ׮द Ӓܻب۾ ೮णפ׮
  60. Composable ߧਤীࢲ suspend funܳ ഐ୹ೡ ٸ ࢎਊೠ׮. Composition द੼ ژח

    keyо ߸҃ؼ ٸ݃׮ ׮द ഐ୹ػ׮. LaunchedEffect Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928
  61. Use Case 5: ஠ݫۄ ੉ز

  62. ஠ݫۄ ੉ز // 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੄ ޙࢲܳ ଵҊೞݶ ب਑ؼ Ѫ эणפ׮
  63. Example: ݃ழ ࢶఖೞӝ Marker().apply { setOnClickListener { /* Marker Selected

    */ naverMap.moveCamera(...) } } mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _ -> /* Marker Unselected */ naverMap.moveCamera(...) } } ݃ழ৬ ૑بܳ ௿ܼೞݶ ஠ݫۄܳ ੉زೞח ৘ઁ ௏٘ੑפ׮
  64. Example: ݃ழ ࢶఖೞӝ var selectedTheater by remember { mutableStateOf<TheaterMarkerUiModel?>)(null) }

    Marker().apply { setOnClickListener { /* Marker Selected */ selectedTheater = theater } } mapView.getMapAsync { naverMap -> naverMap.setOnMapClickListener { _, _ -> /* Marker Unselected */ selectedTheater = null } } Composeীࢲب زੌೞѱ ೡ ࣻ ੓૑݅, ࢶఖػ ӓ੢ਸ ࢚క۽ ੿੄೧فҊ ࢚కо ߸҃ؼ ٸ ஠ݫۄܳ ੉زೞח ߑߨਸ ࢎਊ೮णפ׮
  65. Composeীࢲ ҙ଴ೡ ࣻ ੓ח MutableState<T>ܳ ࢤࢿೞח ೣࣻ. valueо ߸҃غݶ, valueܳ

    ੍ח Composable ೣࣻ੄ Recomposition੉ ৘ডػ׮. mutableStateOf Link: h tt ps://developer.android.com/jetpack/compose/state#state-in-composables interface MutableState<T> : State<T> { override var value: T } var value by remember { mutableStateOf(default) } Recompositionীࢲ ੉੹ valueܳ ਬ૑ೞ۰ݶ rememberܳ ࢎਊ೧ঠ ೠ׮.
  66. Example: ݃ழ ࢶఖೞӝ var selectedTheater by remember { mutableStateOf<TheaterMarkerUiModel?>)(null) }

    LaunchedEffect(selectedTheater) { val naverMap = mapView.awaitMap() if (selectedTheater != null) { naverMap.moveCamera(...) } else { naverMap.moveCamera(...) } } LaunchedEffectܳ ੉ਊೞৈ, ࢶఖػ ӓ੢ ч੉ ߸҃ؼ ٸ݃׮ ੸׼ೠ ਤ஖۽ ஠ݫۄܳ ੉زೡ ࣻ ੓ѷणפ׮
  67. ৈӝࢲ ਫ਼Ӭ! 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 
 ࢚కח ইې۽ ੉زೞҊ ੉߮౟ח ਤ۽ ੉زೞח ٣੗ੋ ಁఢ.
  68. 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ী ੸೤ೞѱ ҳഅغ঻ח૑ ࢤп೧ࠇद׮
  69. @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ਸ ٜ݅ ࣻ ੓णפ׮
  70. @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ܳ ҳഅ೮׮Ҋ ೡ ࣻ ੓ਸөਃ?
  71. @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ܳ ݅٘ח ޙઁ.
  72. Library۽ ҕਊചೞӝ Link: h tt ps://github.com/fornewid/naver-map-compose ૑Әө૑ ੘ࢿೠ ௏٘ח ೞա੄

    জীࢲ ࢎਊೞӝীח ୽࠙೮૑݅, ۄ੉࠳۞ܻ۽ ٜ݅ٸח ҕਊചػ ਬૉா੉झী ݏ୾ࢲ ੘ࢿ೧ঠѷભ? Ӓېࢲ ੉ߣীח খীࢲ ҳഅ೮؍ 5о૑ ਬૉா੉झܳ ѐࢶ೧ࠁ۰Ҋ ೤פ׮
  73. Use Case 1: ૑ب ࠁৈ઱ӝ

  74. ૑ب ࠁৈ઱ӝ ✅ NaverMap(...) ੉ ࠗ࠙਷ ௼ѱ Ҋச ࠗ࠙੉ হ੉

    ইө ੘ࢿ೮؍ ௏ٜ٘ਸ Ӓ؀۽ ࢎਊೞݶ ؾפ׮
  75. Use Case 2: ૑ب ২࣌

  76. ૑ب ২࣌ @Composable fun NaverMap(properties: MapProperties = ...) { ...

    AndroidView(factory = { mapView.apply { coroutineScope.launch { val naverMap = awaitMap() naverMap.mapType = properties.mapType naverMap.isNightModeEnabled = properties.isNightModeEnabled } } }) ইө ੘ࢿ೮؍ NaverMap ё୓ী mapType ١ਸ ࢸ੿ೞח ௏٘ੑפ׮
  77. ૑ب ২࣌ @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ীࢲח ׮द ࢸ੿غ૑ ঋѷભ
  78. ૑ب ২࣌ @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о ߸҃غযب ߈৔غ૑ ঋח ޙઁо ࢤӤפ׮
  79. ૑ب ২࣌ @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ী ੽Ӕೡ ࣻ ੓णפ׮
  80. rememberUpdatedState ч੉ ߸҃غযب ੤द੘ೞ૑ ঋইঠ ೞח ബҗ੄ чਸ ଵઑೡ ٸ

    ࢎਊೠ׮. Source: h tt ps://medium.com/mobile-app-development-publication/a4867f876928
  81. ૑ب ২࣌ val currentProperties by rememberUpdatedState(properties) LaunchedEffect(Unit) { val naverMap

    = mapView.awaitMap() naverMap.mapType = currentProperties.mapType naverMap.isNightModeEnabled = currentProperties.isNightModeEnabled } ௏٘۽ ׮द جইоࠇद׮ ੉ ௏٘ীࢲ side-effectо ߊࢤೞח द੼੉ হભ?
  82. ૑ب ২࣌ 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() } } ࣁࠗ੸ੋ ࠗ࠙੉ ࡅ઎חؘ, पઁ۽ח ੉ۧѱ ੘ࢿ೮णפ׮
  83. ૑ب ২࣌ 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ܳ ഐ୹೤פ׮
  84. ૑ب ২࣌ 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ܳ ֍णפ׮
  85. MapApplierח Composition ઺ী MapNode ౟ܻܳ ҙܻೞח ৉ೡ. MapUpdaterח ૑ب ࣘࢿਸ

    ҙܻೞח ComposeNodeܳ ࢤࢿೠ׮. MapUpdater NaverMap MapApplier, MapUpdater MapApplier MapPropertiesNode Listeners getMap() MapNode MapNode MapNode = ComposeNode NaverMap @Composable @Composable
  86. MapApplier class MapApplier( val map: NaverMap, ) : AbstractApplier<MapNode>(MapNodeRoot) {

    private val decorations = mutableListOf<MapNode>() ... } interface MapNode object MapRootNode : MapNode class MapPropertiesNode(val map: NaverMap) : MapNode MapApplierীࢲ MapNode Listܳ ҙܻೞҊ, MapNode ҳഅ୓ ઺ী MapPropertiesNodeо ੓णפ׮
  87. MapUpdater @Composable fun MapUpdater(mapProperties: MapProperties) { val map = (currentComposer.applier

    as MapApplier).map ComposeNode<MapPropertiesNode, MapApplier>( 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ীࢲ јन೧઱ח ഋక۽ غয ੓णפ׮
  88. 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ਸ хऱח ഋక۽ غয ੓חؘਃ
  89. 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ਸ ઴ੌ ࣻ ੓णפ׮
  90. ૑ب ২࣌ ✅ NaverMap( ... mapProperties = MapProperties( mapType =

    NaverMap.MapType.Navi, isNightModeEnabled = true, ), ... ) ૑ب ২࣌ਸ ࢚క۽ ੹׳ೞח ࠗ࠙ਸ ৮ࢿ೮णפ׮
  91. Use Case 3: ૑ب ੉߮౟ ੉ઁ ૑ب ੉߮౟۽ ֈযоࠁѷणפ׮

  92. ૑ب ২࣌ @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ܳ ੹׳೧઱ח ࠗ࠙ਸ ੘ࢿ೮חؘਃ
  93. ૑ب ੉߮౟ @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੉ۄח ۈ׮ܳ ੹׳೤פ׮
  94. ૑ب ੉߮౟ @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۽ ӝর೧સפ׮
  95. ૑ب ੉߮౟ @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 ղࠗীࢲ ੉߮౟о ߊࢤೞݶ ੉۠ ࣽࢲ۽ ੉߮౟о ࢚ਤ۽ ੹౵ؾפ׮
  96. // Composition ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode<MapPropertiesNode,

    MapApplier>( 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ܳ ੹׳೧઱Ҋ
  97. // Recomposition ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode<MapPropertiesNode,

    MapApplier>( 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ܳ ׮द Ү୓೧સפ׮
  98. ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode<MapPropertiesNode, MapApplier>( 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ܳ ١۾೤פ׮
  99. ૑ب ੉߮౟ @Composable fun MapUpdater(clickListeners: MapClickListeners) { ComposeNode<MapPropertiesNode, MapApplier>( 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) } } ֎੉ߡ૑بীࢲ ੉߮౟о ߊࢤೞݶ ੉۠ ࣽਵ۽ ࢚ਤ۽ ੹౵ؾפ׮
  100. ૑ب ੉߮౟ ✅ NaverMap( ... onMapClick = { _, _

    -> /* Do domething*/ } ... ) ੉ۧѱ ֎੉ߡ૑بীࢲ ੉߮౟ܳ ׮ܖח ࠗ࠙ب ҳഅ೧ࠌणפ׮
  101. Use Case 4: ݃ழ ࠁৈ઱ӝ ݃ழܳ ࠁৈ઱ח ࠗ࠙ਸ ׮द ࢓ಝࠁѷणפ׮

  102. // State ݃ழ val marker = Marker().apply { captionText =

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

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

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

    = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) Composeীࢲח ੉۠ ഋక۽ ࢎਊೡ ࣻ ੓ѱ ٜ݅঻णפ׮
  106. ݃ழ 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ਸ ٜ݅ݶ ؾפ׮
  107. 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
  108. ݃ழ Marker( captionText = "caption", position = LatLng(..., ...), icon

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

    ...), icon = OverlayImage.fromResource(R.drawable.marker_icon), onClick = { ... true }, ) } ੉ۧѱ NaverMap Composable ղࠗী Child Composable۽ ࢶ঱೧઱ݶ ؾפ׮
  110. Example: ӓ੢ ݃ழ ҙܻೞӝ var markers by remember { mutableStateOf<List<Marker>>(emptyList())

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

    Marker( ... ) } } ੉ઁ ખ ؊ ࢶ঱ഋ UIী оӰѱ ݃ழܳ ಴दೡ ࣻ ੓णפ׮
  112. ݃ழ ࠁৈ઱ӝ ✅ NaverMap { Marker( position = LatLng(..., ...),

    ... onClick = { /* Do domething*/ true }, ) }
  113. Use Case 5: ஠ݫۄ ੉ز ࢎਊ੗о ૑بܳ झ௼܀೧ࢲ ஠ݫۄ ਤ஖ܳ

    ੉زೠ ׮਺
  114. Use Case 5: ஠ݫۄ ੉ز ചݶਸ ഥ੹ೞݶ

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

    ޙઁ!
  116. Use Case 5: ஠ݫۄ ੉ز Con fi g Changes द੼ী

    ࢚కܳ ਬ૑ೡ ࣻ হਸө? rememberSaveable
  117. ஠ݫۄী ؀ೠ ࢚క, ੉߮౟ܳ ҙܻೞח State Holder. MapUpdater CameraPositionState NaverMap

    MapPropertiesNode CameraPositionState CameraPosition NaverMap Listeners Composition only State Holder Event New CameraPosition @Composable Compositionীࢲ݅ ݃૑݄ী ੷੢ೠ ਤ஖۽ ஠ݫۄܳ ੉ز೤פ׮
  118. ࢚క ҙܻ: State Holder Link: h tt ps://developer.android.com/jetpack/compose/state#state-holder-source-of-truth ࠂ੟ೠ UI੄

    ࢚క৬ UI ۽૒ਸ ನೣೞח ௿ېझ. Composable੄ ࠂ੟ࢿਸ ઴ৈળ׮.
  119. 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 ௏٘ܳ ࢓ಝࠇद׮
  120. 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ਸ সؘ੉౟ ೧સפ׮
  121. 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ਵ۽ ౸ױೞҊ, ݃૑݄ ਤ஖۽ ੉زदெ઱ח ୊ܻо ٜযо ੓णפ׮
  122. @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<CameraPositionState, CameraPosition> = 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 द੼ী ݃૑݄ ࢚కܳ ੷੢/ࠂҳ ೧સפ׮
  123. 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ܳ ੹׳೧઱Ҋ ੉زೡ ٸח ௏ܖ౯ਸ ੉ਊೞৈ গפݫ੉࣌ ୊ܻܳ ೡ ࣻ ੓णפ׮
  124. • 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
  125. ೙ਃೠ ӝמ੉ ੓ਵݶ, ੉गܳ ١۾೧઱ࣁਃ! 👆

  126. Q & A хࢎ೤פ׮!