에어비앤비와 유사한 앱을 만들어보았다. BottomSheetDialog 역할을 하는 view와 네이버 mapAPI, viewpager2등을 사용했다. 무엇보다 안드로이드 실제 디바이스를 당근마켓에서 구입해서 하고있는데, 빠릿빠릿하니 왠지 공부하는게 더 재밌어졌다. 버벅이는게 없어서 그런가.. 돈이 좋다!
구현 기능은, 임시로 구현한 mock서버에서 api통신을 통해 데이터를 가져와 map위에 마커를 찍어주고, 공유하기 기능, viewpager전환 또는 마커 클릭시 서로과 상호작용을 하도록 했다.
# 공부내용 정리
1. 네이버 API 연동 및 현재위치 마커찍기
2. 코디네이터레이아웃, 레이아웃 include
3. bottomSheet layout 만들기
4. Mock으로 임시 데이터 API만들기
5. Glide 및 레트로핏
6. 뷰 페이저 및 어댑터
7. 글라이드 이미지 보정시 CenterCrop & radius( dp -> px )
8. 마커 클릭시, 뷰페이저 전환시 지도 이동
9. 공유하기
# 네이버 API 연동
## 네이버 개발자 플랫폼
//build.gradle(app)
//naver api
implementation 'com.naver.maps:map-sdk:3.15.0'
//google location
implementation 'com.google.android.gms:play-services-location:20.0.0'
//setting.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url 'https://naver.jfrog.io/artifactory/maven/'
}
}
}
//gradle.properties
android.useAndroidX=true
android.enableJetifier=true
을 추가해주어 naver API를 사용 할 수 있도록 해야한다.
이후 매니페스트에 클라이언트ID를 추가해주는 작업도 해야하는데, 해당 api문서(DOC)에 친절히 설명 돼 있기 때문에 생략한다.
## naver MapView
<com.naver.maps.map.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="83dp"
/>
MapView와 프래그먼트 둘중 한개로 지도를 화면 위에 그릴 수 있는데, 강의에서는 MapView를 사용했고 그에 따른 생명주기를 작성해주었다.
## 생명주기
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onMapReady(map: NaverMap) {
/* 여기서부터 mapView관련된 코드를 구현함 */
}
다음과 같이 생명주기를 만들고, onMapReady에 들어갈 코드를 구현한다. 메인액티비티에서 OnMapReadyCallback 인터페이스를 상속받아 준다.
class MainActivity : AppCompatActivity(), OnMapReadyCallback, Overlay.OnClickListener{
private val mapView : MapView by lazy {
findViewById(R.id.mapView)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
}
}
## naver MapView 기본적인 기능 사용해보기
private lateinit var naverMap : NaverMap
override fun onMapReady(map: NaverMap) {
naverMap = map
// 확대 축소
naverMap.maxZoom = 18.0
naverMap.minZoom = 10.0
// 지도 옵션 설정
naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true)
naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_BUILDING, true)
naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRAFFIC, true)
naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true)
naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true)
// 초기 위치 설정
val cameraUpdate = CameraUpdate.scrollTo((LatLng(37.4979921,127.028046))).animate(CameraAnimation.Easing)
naverMap.moveCamera(cameraUpdate)
// 현위치 받아오기
val uiSettings = naverMap.uiSettings
uiSettings.isLocationButtonEnabled = false
// 로케이션 버튼 재할당
locationButton.map = naverMap
naverMap.locationTrackingMode = LocationTrackingMode.Face
// 현재 위치 설정
locationSource = FusedLocationSource(this@MainActivity, CURRENT_LOCATION_CODE)
naverMap.locationSource = locationSource
// Marker
/*val marker = Marker()
marker.position = LatLng(37.6154444,127.0341968)
marker.map = naverMap
marker.icon = MarkerIcons.BLACK
marker.iconTintColor = Color.RED*/
// TODO API로 정보가져오기
getHouseDataAPI()
}
어렵다기 보다는 공식 문서에 나오는 내용들을 활용하면 된다.
# bottomSheet Layout 만들기
XML에서 include라는 기능을 활용하면 내가 만든 XML을 그자리에 짧게 넣어버릴 수 있다. XML파일이 길어져 복잡해지는 것을 방지함과 동시에 XML을 하나의 컴포넌트 처럼 사용할 수 있었다.
<include layout="@layout/bottom_sheet"/>
손으로 드래그하면 올라가도록 구현해야하는데, 분리해내어 bottomSheet로 사용하는 XML에서 material에서 제공해주는 기능을 사용하면 손쉽게 구현이 가능했다.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
app:behavior_peekHeight="100dp"
android:background="@drawable/top_lf_radius_white_bg"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
layout_behavior을 사용해서 위로 드래그해서 올리도록 하고, peekHeight를 사용하여 숨겨졌을때 보이는 최대 크기를 지정 가능하다.
# CoordinatorLayout (코디네이터 레이아웃)
bottomSheet.xml을 만들어줬는데, 이걸 include하여 사용하는 main 레이아웃은 코디네이터 레이아웃을 사용했다. Frame레이아웃에서 진화한 레이아웃이라고 하는데, 스크롤 이벤트에 대해서 조금 더 능동적으로 대체가 가능하다고 했다.
# 끝내며
이번에 공부하면서 새로운 레이아웃들을 사용해봤다. 바텀시트 같은 경우도 요즘 많이 쓰이는 UI방식인데 실제로 구현해봤다. 아직 Frame레이아웃과 코디네이터 레이아웃을 많이 써본게 아니라 정확히 어떤 느낌인지는 감이 오지 않지만, 차츰 하나씩 배워나가면 쉽게 다가 올거 같다. 다음편에서는 Mock API를 만드는 방법과 Glide와 레트로핏을 사용해 어댑터에 넣는것을 해보겠다.