Naver_Maps_Study - boostcampwm-2024/and04-Nature-Album GitHub Wiki
-
MapFragment๋ฅผ Compose๋ก ๋ํํ๋ค
Naver Maps๋
Fragment
๋ก ๊ตฌํํ๋ ๊ฒ์ ๊ถ์ฅํ๊ธฐ ๋๋ฌธ์MapFragment
๋ฅผ ํ์ฉํด ์ง๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.MapFragment
๋ฅผ Compose ๋ด์์ ์ฌ์ฉํ๋๋ก ๋ํํจ์ผ๋ก์จ ํ์ํ ์์น์ ๋ฐฐ์นํ ์ ์์ผ๋ฉฐ, ์ง๋ API์ ๋ชจ๋ ๊ธฐ๋ฅ์ ํ์ฉํ๋ฉด์๋ Compose UI ๊ณ์ธต๊ณผ ํตํฉํ ์ ์๋ค. -
AndroidView๋ฅผ ์ฌ์ฉํ์ฌ MapFragment๋ฅผ ์ฝ์ ํ๋ค
AndroidView
๋ฅผ ์ฌ์ฉํ์ฌMapFragment
๋ฅผ Compose์ ์ฝ์ ํ ์ ์๋ค. ์ด ๋ฐฉ์์ผ๋ก ์ง๋ ๋ทฐ ์์ Compose ์ปดํฌ๋ํธ๋ฅผ ์ค๋ฒ๋ ์ดํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํดBottomSheet
,FloatingActionButton
,Marker
๋ฑ๊ณผ ๊ฐ์ ์ธํฐ๋ ์ ์์๋ฅผ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์๋ค.AndroidView
๋ด์FragmentContainerView
๋ฅผ ๊ฐ์ธ ์ค์ ํ๊ณ Compose ์์์์ ํ์ํ ๋ง์ปค ๋ฐ ์ค๋ฒ๋ ์ด ์์๋ฅผ ๋ฐฐ์นํ๋ค. -
BottomSheet์ Marker๋ฅผ ์ง๋์ ์ค๋ฒ๋ ์ดํ๋ค
Scaffold
๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ฉด์ ๊ตฌ์ฑํ๊ณ ,BottomSheet
๋ฅผ ์ง๋ ์์ ์ค๋ฒ๋ ์ด ํํ๋ก ๋ฐฐ์นํ๋ค. ์ด๋BottomSheetScaffold
๋ฅผ ์ฌ์ฉํด ์ง๋์ ๋ ๋ฆฝ์ ์ธ ์ํ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฉฐ, ์ฌ์ฉ์ ์ ๋ ฅ์ด๋ ์ ๋ณด ํ์์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ง๋์ ๋ณ๋๋ก ์ํํ ์ ์๋ค. -
Compose Navigation์ผ๋ก ํ๋ฉด ์ ํ์ ๊ด๋ฆฌํ๋ค
Compose์
NavHost
์NavController
๋ฅผ ์ฌ์ฉํด ํ๋ฉด ์ ํ์ ๊ด๋ฆฌํ๊ณ , ์ง๋๊ฐ ํฌํจ๋ ํ๋ฉด์ ํ์ํ ์์ ์๋ง ํ์ํ๋๋ก ํ๋ค. ์ด๋ฅผ ํตํด ์ฑ๋ฅ ํจ์จ์ ๋์ด๊ณ ์ง๋๊ฐ ํ์ฑํ๋ ๋๋งMapFragment
๋ฅผ ์ฌ์ฉํ๊ฒ ํ์ฌ ๋ฆฌ์์ค๋ฅผ ์ต์ ํํ ์ ์๋ค.
-
์ง๋ ํผ์ด์ธ์ ์์ ๋ฏผ์ฃผ๋๋ค๊ฐ ๋จผ์ MapFragment ๋์ ์ ์๋ํ๊ณ ์๋ช ์ฃผ๊ธฐ ๋ฌธ์ ๊ฐ ์์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค. ์ฐ๋ฆฌ ํ๋ Naver Maps๋ก XML์ Compose์์ ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค์ ํด๊ฒฐํด๋ณด๊ณ ์๋ช ์ฃผ๊ธฐ์ ๋ง๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ ๋์ ํด๋ณด๋ ๊ฒ์ด ๋ชฉํ์๋ค. ๊ทธ๋์ ๋๋ ๋จผ์ Fragment๋ก ์คํํด๋ณด๋ค๊ฐ ๋ฏผ์ฃผ๋๊ป DM์ผ๋ก ํน์๋ ์๋ช ์ฃผ๊ธฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋์ง ๋จผ์ ์ฌ์ญ์ด๋ณด์๊ณ ์์ง ํด๊ฒฐ๋์ง ์์ ์ฐ๋ฆฌ ํ์ด ํด๊ฒฐ๋๋ฉด ๋งํด๋ฌ๋ผ๊ณ ํ๋ค. ์๋๋ ๋ฏผ์ฃผ๋์ ํตํด ์๊ฒ ๋ ๋ฏผ์ฃผ๋๋ค ์งํ ์ํฉ์ ์ ๋ฆฌํด๋ ๊ฒ์ด๋ค.
-
naver map์ fragment๋ก ํ์ฌ android view ๋ก compose์ ์ฝ์
-
์ด๋ก ์ธํด fragment ์ ๋ง์ปค ๋ฑ์ custom view๋ก ๋ง๋ค์ด fragment์์ ํ๋ ๊ฒ์ฒ๋ผ ์งํํด์ผ ํจ
[[๋ค์ด๋ฒ ์ง๋ API] ๋ง์ปค ์์ด์ฝ ์ปค์คํ ๋ทฐ ๋ง๋ค๊ธฐ](https://www.notion.so/API-13aea5e5fc1780e3a497fb5cdc4e2e9c?pvs=21)
- Fragment ์์ composable์ ๋์์ ํ์ํ๋ ๊ฒ ์คํจํ์ จ๋ค๊ณ ํจ. ์ปค์คํ ๋ทฐ๋ก ์ถฉ๋ถํ ๊ฐ๋ฅํด์ ๊ผญ ์ํด๋ ๋ ๊ฒ ๊ฐ๋ค๊ณ ๋ง์ํ์ฌ. โ ์๊ฐ ๋๋ฉด ์๋ํด๋ณด๊ธฐ
-
Fragment์ Compose ๊ฐ์ ์๋ช ์ฃผ๊ธฐ ๋ฌธ์
https://github.com/boostcampwm-2024/and06-musicroad/pull/85
- ์์ PR ๋ง์ง๋ง Comment ์ฐธ๊ณ
์ ๋ ๋ค๋ฅธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ค๊ฐ ๋์์ค๋ฉด ๋ง์ปค ์์ฑ์ด ์ฌ๋ฌ ๊ฐ๊ฐ ๋๋ ๊ฒ์ ๋ก๊ทธ๋ฅผ ํตํด ์ธ์งํ๊ณ ์์์ต๋๋ค. ๋ค๋ฅธ ํ๋ฉด์ n๋ฒ ๋ค๋ ์ค๋ฉด ์ค์ ๋ฒํผ์ ํ ๋ฒ ํด๋ฆญํ์ ๋ ๋ง์ปค ์์ฑ ๋ก๊ทธ๊ฐ n๋ฒ ์ฐํ๋๋ค. ์ด๋ฒคํธ ๋ฐฉ์ถ์ ํ ๋ฒ ๋๋๋ฐ ์ด๋ฒคํธ ๋ฌธ์ ๋ผ๊ธฐ๋ณด๋จ ํ๋๊ทธ๋จผํธ ๋ฌธ์ ๋ผ๊ณ ์๊ฐํ๊ณ ์์๋๋ฐ ์ค๊ฒธ๋์ด ์ธ๊ธํด์ฃผ์ ์ ๋ค์ ์ด ๋ฌธ์ ์ ๋ํด ์์๋ดค์ต๋๋ค.
์ ํฌ๋ ์ง๊ธ MapScreen ์์์ AndroidView๋ก MapFragment๋ฅผ ๋์ฐ๊ณ ์์ต๋๋ค.
๋ค๋ฅธ ํ๋ฉด์ ๋ค๋ ์์ ๋ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ด๋ฒคํธ ๋ฐฉ์ถ์ ํ ๋ฒ์ธ๋ฐ ์ ๋ง์ปค ์์ฑ์ด ๋ ๋ฒ ๋๋์ง ์ด๊ฒ์ ๊ฒ ๊ฐ์ค์ ์ธ์๋ณด๊ณ ๋ก๊ทธ๋ฅผ ์ฐ์ด๋ณด๋ฉฐ ์์ธ์ ์ฐพ์์ต๋๋ค.
AndroidView( modifier=Modifier.fillMaxSize(), factory= { context-> FragmentContainerView(context).apply { id=View.generateViewId() (contextasFragmentActivity).supportFragmentManager.beginTransaction() .replace(id,MapFragment()) .commitAllowingStateLoss() } } )
ํ์ฌ ์์ฒ๋ผ AndroidView๊ฐ ์์ฑ๋์ด ์์ต๋๋ค. AndroidView์ factory๋ composable์ด ์ปดํฌ์ง์ ๋ ๋ ์คํ๋ฉ๋๋ค. ํ๋ฉด์ ์ด๋ํ๋ค๊ฐ ๋์์ค๋ฉด ์๋ก ์ปดํฌ์ง์ ๋๊ธฐ ๋๋ฌธ์ ์๋ก์ด ํ๋ฉด์ผ๋ก ์ด๋ํ๋ค๊ฐ ๋์์ฌ ๋๋ง๋ค factory๊ฐ ํธ์ถ๋ฉ๋๋ค.
factory ์์์ id๋ฅผ View.generateViewId()๋ก ์์ฑํ๊ณ ์๋๋ฐ ์ด๋ factory๊ฐ ์คํ๋ ๋๋ง๋ค ๋ค๋ฅธ ๊ฐ์ ์์ฑํฉ๋๋ค. ๋ฐ๋ผ์ replace๊ฐ ๋๋ ๊ฒ์ด ์๋๋ผ ์๋กญ๊ฒ ์ถ๊ฐ๊ฐ ๋ฉ๋๋ค.
๋ค๋ฅธ ํ๋ฉด์ผ๋ก ๊ฐ๋ค๊ฐ ๋ค์ ๋์์์ ๋ factory์์ ์๋ก์ด ํ๋๊ทธ๋จผํธ๊ฐ ๋ง๋ค์ด์ง๊ณ ์ด์ ํ๋๊ทธ๋จผํธ๋ ์ฌ์ ํ ์ด์์๋ ์ํ์ ๋๋ค. ํ๋๊ทธ๋จผํธ๋ผ๋ฆฌ ๋ทฐ๋ชจ๋ธ์ ๊ณต์ ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ฒํผ์ ํ ๋ฒ ๋๋ ์ ๋ ๋ ํ๋๊ทธ๋จผํธ์์ ์ด๋ฒคํธ๋ฅผ ๋ฐ๊ณ ๊ฐ์ ๋ง์ปค๋ฅผ ์์ฑํ์ฌ ๋ก๊ทธ๊ฐ ๋ ๋ฒ ์ฐํ๋ ๊ฒ์ด์์ต๋๋ค.
์ ์ฝ๋์์ id ๊ฐ์ ๊ณ ์ ๊ฐ(ex. R.id.fragment_map)์ผ๋ก ๋ฐ๊พธ๋ฉด replace์์ ํ๋๊ทธ๋จผํธ๊ฐ ๊ต์ฒด๋๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํ๋ฉด์ ๊ฐ๋ค์๋ ํ๋๊ทธ๋จผํธ๊ฐ ํ๋๋ง ์๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ ํ๋ฉด์ ์ด๋ํ๊ณ ๋์์๋ ๋ฒํผ์ ๋๋ ์ ๋ ๋ง์ปค๊ฐ ์ค๋ณต์ผ๋ก ์์ฑ๋์ง ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์์ฒ๋ผ ๋ณ๊ฒฝํ์ ๋ ์ ๋ค๋ฅธ ํ๋ฉด์ผ๋ก ๊ฐ๋ MapScreen์ด ์คํ๋๋์ง(๋ก๊ทธ์์ ํ๊ทธ๊ฐ MapScreen์ธ ๊ฒ์ด MapScreen์ด ์คํ๋ ๊ฒ์ ๋๋ค), ๋ค๋ฅธ ํ๋ฉด์ผ๋ก ๊ฐ์ ๋ ๊ธฐ์กด ํ๋๊ทธ๋จผํธ๊ฐ onPause() ๋๋ ๊ฒ ์๋๋ผ ๋ค์ ๋์์์ ๋ onPause()๋ถํฐ ์๋ฉธ๊น์ง ์ํํ๋ ๊ฒ ๋ฑ ์์ง ์ดํดํ ์ ์๋ ๋ถ๋ถ๋ค์ด ์์ต๋๋ค ใ
๊ฝค ์์๋ด์ผ ํ ๋ถ๋ถ์ด ์์ ๊ฒ ๊ฐ์ ์ด PR์ ๊ณ์ ์ด์ด๋๋ ๊ฒ๋ณด๋ค๋ bug ์ด์๋ฅผ ์์ฑํ๊ณ ๊ฑฐ๊ธฐ์ ํด๊ฒฐํด๋ณด๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
compose navigation๊ณผ fragment๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ๊ฐ ์ด๋ ต๋ค์ ใ ใ
- Fragment์ Compose์ ์๋ช
์ฃผ๊ธฐ ์ฐจ์ด
-
AndroidView
๋ฅผ ํตํด Fragment๋ฅผ ์ฝ์ ํ๋ฉด, Fragment์ ์๋ช ์ฃผ๊ธฐ์ Compose ์๋ช ์ฃผ๊ธฐ๊ฐ ์๋ก ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ๋์ํ๊ฒ ๋์ด, ํ๋ฉด ์ฌ์ง์ ์ Fragment๊ฐ ์ค๋ณต ์์ฑ๋๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์
-
-
AndroidView
์factory
์์ฑ ์๋ ๋ฐฉ์-
factory
๋Composable
์ด ์ฒ์ ์์ฑ๋๊ฑฐ๋ ์ฌ์์ฑ๋ ๋ ์คํ - ํ๋ฉด์ ์ด๋ํ๊ฑฐ๋ ๋์์ฌ ๋๋ง๋ค
factory
๊ฐ ํธ์ถ๋๋ฉด,View.generateViewId()
๋ก ์์ฑ๋ ID๊ฐ ๋ณ๊ฒฝ๋์ด ์๋ก์ด Fragment๊ฐ ์ถ๊ฐ๋ ์ ์์- custom view๋ก ๋ง์ปค ์์ฑํ ๋ id๋ฅผ ์ง์ ํด๋๊ณ ์ฌ์ฉํด์ผ๊ฒ ์
-
id
๊ฐ์ ๊ณ ์ ๋ ๋ฆฌ์์ค ID (์:R.id.fragment_map
)๋ก ์ค์ ํ์ฌ Fragment๊ฐ ๊ต์ฒด๋๋๋ก ํ๊ธฐ
-
- Compose์ Fragment๋ฅผ ํจ๊ป ์ฌ์ฉํ ๋์ Navigation ๋ฌธ์
- Compose Navigation๊ณผ Fragment Navigation์ ๊ฐ๊ฐ ๋ณ๋์ ์คํ์ ๊ด๋ฆฌ
- Compose Navigation์ผ๋ก ํ๋ฉด์ ์ด๋ํ๋ฉด Fragment์ ์๋ช ์ฃผ๊ธฐ๊ฐ ์ ์ ํ๊ฒ ๊ด๋ฆฌ๋์ง ์๊ฑฐ๋ ์์์น ๋ชปํ ๋์์ ์ ๋ฐ(ํ๋ฉด ์ ํ์ด๋ ์ฌ์ง์ ์ ๋ ๋ณต์ก)
- Fragment ์๋ช
์ฃผ๊ธฐ์ ViewModel ๊ณต์
- ํ๋ฉด ์ด๋ ํ ๋์์์ ๋ ๋ ๊ฐ์ Fragment๊ฐ ๊ฐ์ ViewModel์ ๊ณต์ ํ๊ณ ์๋ค๋ฉด, ์ด๋ฒคํธ๊ฐ ์ค๋ณต ์ฒ๋ฆฌ๋ ๊ฐ๋ฅ์ฑ์ด ์์( Fragment๊ฐ ์ฌ๋ฌ ๊ฐ ์ค๋ณต ์์ฑ๋์๊ธฐ ๋๋ฌธ)
- Fragment๋ฅผ ๊ณ ์ ๋ ID๋ก ์ค์ ํ์ฌ ์ค๋ณต ์์ฑ์ ๋ง์์ผ ํจ
- ํ๋ฉด ์ด๋ ํ ๋์์์ ๋ ๋ ๊ฐ์ Fragment๊ฐ ๊ฐ์ ViewModel์ ๊ณต์ ํ๊ณ ์๋ค๋ฉด, ์ด๋ฒคํธ๊ฐ ์ค๋ณต ์ฒ๋ฆฌ๋ ๊ฐ๋ฅ์ฑ์ด ์์( Fragment๊ฐ ์ฌ๋ฌ ๊ฐ ์ค๋ณต ์์ฑ๋์๊ธฐ ๋๋ฌธ)
- https://webconcert-public-assets.s3.ap-northeast-2.amazonaws.com/conferences/woowa2021/presentations/1-6.pdf
- https://www.youtube.com/watch?v=BX0rQvYgf1I
https://navermaps.github.io/android-map-sdk/guide-ko/5-1.html
์ค๋ฒ๋ ์ด ๊ฐ์ฒด๋ ์๋ฌด ์ค๋ ๋์์๋ ์์ฑํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ค๋ฒ๋ ์ด์ ์์ฑ์ ์ค๋ ๋ ์์ ์ฑ์ด ๋ณด์ฅ๋์ง ์์ผ๋ฏ๋ก ์ฌ๋ฌ ์ค๋ ๋์์ ๋์์ ์ ๊ทผํด์๋ ์๋ฉ๋๋ค. ํนํ ์ง๋์ ์ถ๊ฐ๋ ์ค๋ฒ๋ ์ด์ ์์ฑ์ ๋ฉ์ธ ์ค๋ ๋์์๋ง ์ ๊ทผํด์ผ ํ๋ฉฐ, ๊ทธ๋ ์ง ์์ผ๋ฉด
[CalledFromWrongThreadException](https://navermaps.github.io/android-map-sdk/reference/com/naver/maps/map/CalledFromWrongThreadException.html)
์ด ๋ฐ์ํฉ๋๋ค. ๋จ, ์ค๋ฒ๋ ์ด๊ฐ ์ง๋์ ์ถ๊ฐ๋์ง ์์๋ค๋ฉด ๋ค๋ฅธ ์ค๋ ๋์์ ์ค๋ฒ๋ ์ด์ ์์ฑ์ ์ ๊ทผํด๋ ์์ธ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.๋ฐ๋ผ์ ๋๋์ ์ค๋ฒ๋ ์ด๋ฅผ ๋ค๋ฃฐ ๊ฒฝ์ฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ด๊ธฐ ์ต์ ์ ์ง์ ํ๋ ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์ํํ๊ณ ์ง๋์ ์ถ๊ฐํ๋ ์์ ๋ง์ ๋ฉ์ธ ์ค๋ ๋์์ ์ํํ๋ฉด ๋ฉ์ธ ์ค๋ ๋๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค์์ 1000๊ฐ์ ๋ง์ปค๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์์ฑํ๊ณ ์์ฑ์ ์ง์ ํ ํ ๋ฉ์ธ ์ค๋ ๋์์ ์ง๋์ ์ถ๊ฐํ๋ ์์ ์ ๋๋ค.
-
DisposableEffect
๋ ํน์ Composable
์ด ํ๋ฉด์ ์ง์ ํ๊ฑฐ๋ ๋ ๋ ๋ ํ ๋ฒ์ฉ ์คํ๋์ด์ผ ํ๋ ์์ ์ ์ฒ๋ฆฌํ๋ ๋ฐ ์ ์ฉ -
SideEffect
๋ ์ปดํฌ์ง์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ํ ํ ๋ฒ ์คํ๋์ด์ผ ํ๋ ์์ ์ ์ฒ๋ฆฌ - ๊ธฐ์กด์
Fragment
๋Activity
์์์onResume
/onPause
์ ๊ฐ์ ์ญํ ์ ์ํ
https://www.youtube.com/watch?v=G67sUjEpsGQ
- ์คํ๋ ค mapview๋ก ๋๊ณ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ๋ ๋์์ง๋ ๋ชจ๋ฆ. ๊ทธ๊ฒ์ด composable ์ฒ๋ผ ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ์.
- https://webconcert-public-assets.s3.ap-northeast-2.amazonaws.com/conferences/woowa2021/presentations/1-6.pdf
- https://www.youtube.com/watch?v=BX0rQvYgf1I
- ์๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํด์ MapView์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์กฐ์ ํด๋ณด์.
package com.and04.naturealbum.ui.maps
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import com.naver.maps.map.MapView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.platform.LocalLifecycleOwner
@Composable
fun MapScreen(modifier: Modifier = Modifier) {
// ํ์ฌ Context๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ์ด๋ MapView ์ด๊ธฐํ ์ ์ฌ์ฉ
val context = LocalContext.current
// ํ์ฌ MapScreen์ LifecycleOwner ๊ฐ์ ธ์ด. ์ด๋ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
// MapView๋ฅผ Compose์์ ์ฌ์ฉํ ์ ์๋๋ก rememberSaveable์ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๊ด๋ฆฌ
// Configuration change์๋ MapView๊ฐ ์ฌ์์ฑ๋์ง ์๊ณ ์ ์ง
val MAP_VIEW_ID = 12345 // ์ดํ ids.xml๋ก ๊ณ ์ id ๋นผ๊ธฐ
val mapView = remember {
MapView(context).apply {
id = MAP_VIEW_ID // MapView์ ๊ณ ์ ํ ID๋ฅผ ์ค์
}
}
// MapView์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด DisposableEffect๋ฅผ ์ฌ์ฉ
DisposableEffect(lifecycleOwner) {
// ํ์ฌ LifecycleOwner์ Lifecycle์ ๊ฐ์ ธ์ด
val lifecycle = lifecycleOwner.lifecycle
// Lifecycle ์ด๋ฒคํธ๋ฅผ ๊ด์ฐฐํ๋ Observer๋ฅผ ์์ฑ
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_CREATE -> mapView.onCreate(null)
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 -> Unit
}
}
// Lifecycle์ Observer๋ฅผ ์ถ๊ฐํ์ฌ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด์ฐฐ
lifecycle.addObserver(observer)
// DisposableEffect๊ฐ ํด์ ๋ ๋ Observer๋ฅผ ์ ๊ฑฐํ๊ณ MapView์ ๋ฆฌ์์ค๋ฅผ ํด์
onDispose {
lifecycle.removeObserver(observer)
mapView.onDestroy() // MapView์ ๋ฆฌ์์ค๋ฅผ ํด์ ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์ง
}
}
// AndroidView๋ฅผ ์ฌ์ฉํ์ฌ Compose ๋ด์ MapView๋ฅผ ํ์
AndroidView(factory = { mapView }, modifier = modifier) {
// ํ์ํ ๊ฒฝ์ฐ ์ถ๊ฐ์ ์ธ ์ค์ ์ ์
๋ฐ์ดํธ
it.getMapAsync { naverMap ->
// ์ง๋๊ฐ ์ค๋น๋ ํ ์ถ๊ฐ ์ค์ ์ ์ํ
naverMap.minZoom = 10.0
naverMap.maxZoom = 18.0
}
}
}
- ๋ค์ด๋ฒ ์ง๋ API์์ ์ง๋์ ์ฌ์ฉํ ์ด๋ฏธ์ง ์ค๋ฒ๋ ์ด๋ฅผ ์์ฑํ๊ธฐ ์ํ
OverlayImage
์ถ์ ํด๋์ค - ๋ค์ํ ์์ค(๋ทฐ, ๋นํธ๋งต, ๋ฆฌ์์ค ID, ์์ ํ์ผ, ์ฑ ๋ด๋ถ ํ์ผ, ํ์ผ ๊ฒฝ๋ก ๋ฑ)์์ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ก ๋ณํํ๋ ํด๋์ค
-
ํ๋
-
id
: ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง์ ๊ณ ์ ์๋ณ์์ด๋ค. ์์ค์ ๋ฐ๋ผ ID๋ ๋ค๋ฅด๊ฒ ์ค์ ๋๋ค.
-
-
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
- ๋ค์ํ ์์ค์์
OverlayImage
๊ฐ์ฒด๋ฅผ ์์ฑํ๊ธฐ ์ํด ์ฌ๋ฌ ์ ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค:-
fromView(View view)
: ๋ทฐ๋ฅผ ํตํด ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromBitmap(Bitmap bitmap)
: ๋นํธ๋งต์ผ๋ก๋ถํฐ ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromResource(int resourceId)
: ๋ฆฌ์์ค ID๋ฅผ ํตํด ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromAsset(String assetName)
: ์์ ํ์ผ ์ด๋ฆ์ ํตํด ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromPrivateFile(String fileName)
: ์ฑ์ ๋ด๋ถ ํ์ผ์ ํตํด ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromPath(String absolutePath)
: ํ์ผ์ ์ ๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. -
fromFile(File file)
:File
๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค.
-
- ๋ค์ํ ์์ค์์
-
์ถ์ ๋ฉ์๋
-
getBitmap(Context context)
: ๊ตฌ์ฒด์ ์ธ ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง์์ ๋นํธ๋งต์ ๊ฐ์ ธ์ค๋ ๋ฉ์๋๋ก, ๊ฐ ์์ค๋ณ ํด๋์ค์์ ๊ตฌํํด์ผ ํ๋ค.
-
-
equals
์hashCode
๋ฉ์๋- ๋
OverlayImage
๊ฐ์ฒด๊ฐ ๋์ผํid
๋ฅผ ๊ฐ์ง๋์ง ํ์ธํ๊ธฐ ์ํดequals
์hashCode
๋ฉ์๋๋ฅผ ์ฌ์ ์ํ๋ค.
- ๋
AndroidView(factory = { mapView }, modifier = modifier) {
// ํ์ํ ๊ฒฝ์ฐ ์ถ๊ฐ์ ์ธ ์ค์ ์ ์
๋ฐ์ดํธ
it.getMapAsync { naverMap ->
// TODO: ์ง๋๊ฐ ์ค๋น๋ ํ ์ถ๊ฐ ์ค์ ์ ์ํ
naverMap.minZoom = 10.0
naverMap.maxZoom = 18.0
photos.value.map { photoDetail ->
Marker().apply {
position = LatLng(photoDetail.latitude, photoDetail.longitude)
icon = OverlayImage.fromView(ImageMarker(context, photoDetail.photoUri))
width = 72
height = 100
map = naverMap
}
}
}
}
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import coil3.load
import coil3.request.crossfade
import coil3.request.error
import coil3.request.placeholder
import com.and04.naturealbum.R
class ImageMarker @JvmOverloads constructor(
context: Context,
uri: String,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.image_marker, this, true)
findViewById<ImageView>(R.id.iv_marker_image).load(uri) {
crossfade(true)
placeholder(R.drawable.cat_dummy)
error(R.drawable.ic_launcher_background)
}
}
}