상황 설명
스크롤뷰 안에 지도가 들어갈 경우, 지도를 상하 방향으로 움직일 때 스크롤뷰 쪽의 이벤트 우선순위가 높아서 지도는 안움직이고 화면 스크롤이 됨
예제는 네이버 지도를 사용했지만 네이버, 구글, 카카오 상관없이 적용 가능한 코드임
-
맵 클릭 이벤트를 구현할 인터페이스를 추가한다.
interface OnMapTouchListener { fun onTouch() }
-
스크롤 뷰에대한 터치 이벤트를 재정의할 수 있도록 FrameLayout을 상속받은
TouchableWrapper
클래스를 추가한다.class TouchableWrapper @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, private val onTouchListener: OnMapTouchListener? = null ) : FrameLayout(context, attrs, defStyleAttr) { override fun dispatchTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> onTouchListener?.onTouch() MotionEvent.ACTION_UP -> onTouchListener?.onTouch() } return super.dispatchTouchEvent(event) } }
-
지도를 표시할 MapFragment 클래스를 만든다.
MapFragment 쪽으로 재정의된 지도 터치 이벤트를 전달해야하는데, Fragment는 생성자 argument를 사용할 수 없기 때문에 ScrollView가 포함된 Activity나 Fragment를 OnMapTouchListener의 구현체로 만들어서 콜백을 전달한다. onTouch를 구현할 때 스크롤뷰 객체에 requestDisallowInterceptTouchEvent(true)를 적용하면 자식 객체(지도)가 부모(스크롤뷰)의 이벤트를 가로채게 된다.class MainActivity : BaseActivity, OnMapTouchListener { // ... override fun onTouch() { // 스크롤뷰 객체에 requestDisallowInterceptTouchEvent를 true로 설정 binding.scrollView.requestDisallowInterceptTouchEvent(true) } }
fragment_map.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/fragment_map" android:name="com.naver.maps.map.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:navermap_zoomControlEnabled="false" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
MapFragment.kt
: MapFragment가 onAttach 되는 시점에 부모 activity를 형변환해서 Activity에서 정의한 이벤트를 가져온다. 지도 클릭 이벤트를 가로채기 위해 onCreateView에서 fragment 전체를 덮도록 FrameLayout을 상속받은 TouchableWrapper 객체를 추가한다.class NaverMapFragment : Fragment(R.layout.fragment_naver_map), OnMapReadyCallback { private lateinit var binding: FragmentNaverMapBinding private var listener: OnMapTouchListener? = null override fun onAttach(context: Context) { super.onAttach(context) listener = requireActivity() as? OnMapTouchListener } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { binding = DataBindingUtil.inflate(inflater, R.layout.fragment_naver_map, container, false) binding.lifecycleOwner = this // MapFragment 객체 초기화 val mapFragment = childFragmentManager.findFragmentById(R.id.fragment_map) as? MapFragment? mapFragment?.getMapAsync(this) // 지도 전체를 덮어씌우도록 TouchableWrapper를 추가 val frameLayout = TouchableWrapper(requireActivity(), null, 0, listener) frameLayout.setBackgroundColor(ContextCompat.getColor(requireContext(), android.R.color.transparent)) (binding.root as? ViewGroup)?.addView( frameLayout, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) ) return binding.root } // ... }
그러면 스크롤뷰 안에서 지도의 상하 방향 이동이 가능해진다.
참고 자료
'if (study) > Android' 카테고리의 다른 글
[Android] MotionLayout 내부에서 visibility 변경이 안될 때 (0) | 2021.04.21 |
---|---|
Firebase Crashlytics에서 line number가 실제와 다르게 표시됨 (0) | 2021.01.15 |
[Android] 이탤릭체 사용시 TextView 끝이 잘리는 문제 (0) | 2020.10.21 |