contentShape: Tappable Area 만들기

SteadySlower·2023년 2월 17일
0

SwiftUI

목록 보기
37/64
post-custom-banner

만들고자 하는 뷰

현재 제가 만들고자 하는 뷰는 아래와 같습니다. 일단 기존의 단어 Cell 위에 ZStack으로 이미지를 올립니다. 그리고 이 상태에서 Cell을 터치하게 되면 단어 수정을 위한 Modal을 띄우는 것입니다.

하지만 그냥 Image에 onTapGesture를 구현하면 이미지를 터치할 때만 모달이 뜨고 이미지 양쪽에 빈공간을 터치할 때는 모달이 띄워지지 않습니다.

따라서 저는 이미지 위에 Color.clear를 Cell을 모두 채우도록 넣어서 이미지 이외의 부분을 터치해서 모달이 띄워지도록 해보겠습니다. 코드는 아래와 같습니다.

private struct EditableCell: View {
    var body: some View {
        ZStack {
            Color.clear
            Image(systemName: "pencil")
                .resizable()
                .foregroundColor(.green)
                .opacity(0.5)
                .scaledToFit()
                .padding()
        }
    }
}

Color.clear는 Tappable Area가 없다!

하지만 위의 코드를 실행해보면 이미지를 터치할 때만 모달이 뜨고 이미지 이외의 부분을 터치할 때는 모달이 뜨지 않습니다.

그 이유는 Color.clear에는 Tappable Area가 없기 때문입니다. Tappable Area가 없다는 뜻은 Tap Gesture를 자신이 처리하지 못하고 (ZStack 상의) 뒤에 있는 View에 전달한다는 뜻입니다.

이 경우에는 Color.clear에 contentShape()를 사용해서 Tappable Area를 만들어주어야 합니다. contentShape의 정의는 아래와 같습니다.

아래 코드처럼 contentShape를 적용하면 우리가 의도한대로 이미지 뿐만이 아니라 이외의 여백을 터치할 때도 onTapGesture에 정의된 코드를 실행하는 것을 알 수 있습니다.

private struct EditableCell: View {
    var body: some View {
        ZStack {
            Color
                .clear
                .contentShape(Rectangle())
            Image(systemName: "pencil")
                .resizable()
                .foregroundColor(.green)
                .opacity(0.5)
                .scaledToFit()
                .padding()
        }
    }
}

(참고) allowsHitTesting(false)

contentShape()는 Tappable Area가 없는 View에 Tappable Area를 만들어주는 메소드였습니다. 반대로 있는 Tappable Area를 없애는 방법도 있습니다. allowHitTesting(false)를 Tappable Area가 있는 View에 적용하면 마치 Color.clear처럼 해당 View를 터치해도 인식되지 않고 ZStack 상의 뒤에 있는 View에 해당 터치 이벤트를 전달합니다.

profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.
post-custom-banner

0개의 댓글