프레임워크/Android

CoordinatorLayout에서 겹쳐진 뷰의 터치 이벤트를 처리하는 방식

Julie825 2022. 12. 1. 15:01

BottomSheet를 구현하는 도중, BottomSheet 뒤에 가려진 버튼들이 클릭이 가능해지는 버그가 있었다.

스택 오버플로우의 글을 읽고 바텀시트에 clickable="true"를 추가해서 간단히 해결했지만, CoordinatorLayout에서 터치를 가로채는 방식에 대해서 정리해야겠다는 생각이 들었다.

 

coordinatorLayout에서 상위 뷰가 하위 뷰의 터치를 가로채는 동작은 아래에 보이는 CoordinatorLayout.Behavior 를 상속받아서 구현한다. 

public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent2,
        NestedScrollingParent3 { ...

	public static abstract class Behavior<V extends View> { ...
		
		public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull V child,
                @NonNull MotionEvent ev) {
            return false;
        }
		
		public boolean onTouchEvent(@NonNull CoordinatorLayout parent, @NonNull V child,
                @NonNull MotionEvent ev) {
            return false;
        }
	...}
...}

 

Behavior에는 다른 메서드들도 많이 있지만, 지금은 터치에 관련된 메서드 두개만 보자.

 

onInterceptTouchEvent

Params:
parent – the parent view currently receiving this touch event
child – the child view associated with this Behavior
ev – the MotionEvent describing the touch event being processed

Returns:
true if this Behavior would like to intercept and take over the event stream. 
The default always returns false.

 

말 그대로 Event를 intercept할지 결정한다.

CoordinatorLayout으로 전달된 터치 이벤트 중 어떤걸 가로채고 어떤걸 자식에게 전달해줄건지 결정한다.

드래그처럼 단일 터치 이벤트만으로는 판단이 힘든 경우, 자식에게 넘겨주는 일을 보류할 수도 있다.

이벤트를 intercept 할거라면 true를 반환하고, 그 전까지는 false를 반환하면 된다.

기본적으로 항상 false를 반환하기 때문에 따로 구현하지 않으면 자식에게 모든 터치 이벤트가 넘어가게된다.

자식 뷰가 표시되는지에 대한 여부를 View.isShown() 으로 확인할 수 있다. 이 메서드는 자식뷰가 보일때만 터치를 넘겨주는 동작을 구현할 때 유용하게 사용할 수 있다.

 

onTouchEvent

Params:
parent – the parent view currently receiving this touch event
child – the child view associated with this Behavior
ev – the MotionEvent describing the touch event being processed

Returns:
true if this Behavior would like to intercept and take over the event stream. 
The default always returns false.

onInterceptTouchEvent 가 intercept를 시작했을 때, (=true를 반환하는 경우)

가로챈 이벤트를 가지고 뷰 레이아웃을 변경하는 작업을 여기서 처리한다.
이 메서드도 자식의 가시성과 상관없이 동작하기 때문에 View.isShown() 으로 확인해서 처리해야한다.

UI 창을 열고닫는 동작 등을 여기서 구현할 수 있다.