티스토리 뷰

 

리스트 항목에서 리스트 안의 데이터가 아닌 셀 전체 너비를 터치영역으로 설정하고 싶을 때가 있다.

예제를 통해 설정하는 방법을 알아보자!

 

데이터 모델 선언

 

리스트의 각 항목들의 데이터 모델을 정의해 준다.

항목 클릭 여부를 나타내는 click과 항목에 표시될 text를 넣어주었다. 

struct dataModel: Identifiable {
    var id: Int
    let text: String
    var click: Bool
}

 

 

뷰 만들기

 

 

먼저 리스트에 들어갈 각 항목들을 dataArr 배열에 초기화해 준다.

struct ContentView: View {
    @State private var dataArr: [dataModel] = [
        dataModel(id: 1, text: "가", click: false),
        dataModel(id: 2, text: "나", click: false),
        dataModel(id: 3, text: "다", click: false),
        dataModel(id: 4, text: "라", click: false)
    ]
    
    var body: some View {
        ...
    }
}

 

이제 리스트를 구현해 보자

위에서 만들어 놓은 dataArr배열의 각 항목을 반복하여 표시한다.

 

ForEach에서 dataArr를 바인딩하는 이유는 항목들을 클릭했을 때 click 값을 변경해야 되기 때문이다.

text의 color는 click 여부에 따라 색상이 변경되도록 하였다.

var body: some View {
    List {
        ForEach($dataArr) { $data in
            HStack(spacing: 10) {
                Text(data.text)
                    .font(.title)
                    .foregroundStyle(data.click ? Color.blue : Color.red)
            }
            .frame(maxWidth: .infinity, alignment: .leading)
        }
    }
}

 

HStack을 클릭했을 때 data의 click 값이 변경되어야 하기 때문에 onTapGesture를 사용하여 클릭 액션을 처리해 준다.

버튼인 경우에는 아래와 같이 label과 action으로 나눠져 있는데 HStack은 버튼이 아닌 뷰이기 때문에 onTapGesture를 사용하였다.

Button(action: {}, label: {})

 

https://developer.apple.com/documentation/swiftui/view/ontapgesture(count:perform:)

 

찾아보니 count로 몇 번 터치했을 때 perform이 수행되도록 설정도 가능하다고 한다.

기본적으로 count=1 이니 한번 터치한 경우 perform이 수행된다.

 

이제 onTapGesture를 사용해 보면 아래와 같이 action을 수행한다.

data의 click을 toggle로 처리해서 클릭할 때마다 값이 변경되도록 하였다.

 

 var body: some View {
    List {
        ForEach($dataArr) { $data in
            HStack(spacing: 10) {
                Text(data.text)
                    .font(.title)
                    .foregroundStyle(data.click ? Color.blue : Color.red)
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .onTapGesture {
                data.click.toggle()
                print("\(data.text) clicked: \(data.click)")
            }
        }
    }
}

 

자 이제 여기까지 구현하고 테스트를 해보자.

 

 

click으로 텍스트 색상이 바뀌는 건 잘 구현되었는데 텍스트가 없는 곳을 터치하면 onTapGesture가 작동하지 않았다,,,,,

HStack의 너비를 .infinity로 구현해서 onTapGesture도 모든 너비를 터치해도 작동하도록 구현될 줄 알았다.

 

 

해결방법

 

 

각 리스트 항목의 터치영역을 전체 너비로 만들어야 하기 때문에 HStack 전체를 터치 가능한 영역으로 설정해야 한다.

찾아보다가 contentShape(Rectangle())를 알게 되었다.

 

이걸 사용하지 않으면 HStack 내의 이미지나 텍스트와 같은 실제 콘텐츠 부분만 터치가 가능하고, 패딩이나 빈 공간을 터치했을 때 제스처가 인식되지 않는다고 한다.

https://developer.apple.com/documentation/swiftui/view/contentshape(_:eofill:)

 

contentShape터치 가능한 영역을 설정하는 데 사용된다고 한다.

그래서 HStack을 터치 가능한 영역으로 설정할 수 있는 것이다.

 

결론적으로 contentShape(Rectangle())를 사용해서 다시 구현하면 최종 코드는 아래와 같다.

 

struct dataModel: Identifiable {
    var id: Int
    let text: String
    var click: Bool
}

struct ContentView: View {
    @State private var dataArr: [dataModel] = [
        dataModel(id: 1, text: "가", click: false),
        dataModel(id: 2, text: "나", click: false),
        dataModel(id: 3, text: "다", click: false),
        dataModel(id: 4, text: "라", click: false)
    ]
    
    var body: some View {
        List {
            ForEach($dataArr) { $data in
                HStack(spacing: 10) {
                    Text(data.text)
                        .font(.title)
                        .foregroundStyle(data.click ? Color.blue : Color.red)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .contentShape(Rectangle())
                .onTapGesture {
                    data.click.toggle()
                    print("\(data.text) clicked: \(data.click)")
                }
            }
        }
    }
}

 

이제 빈 곳을 클릭해도 잘 동작한다!!

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함