CatHand Blog

アプリ開発やMac弄り

SwiftUIのListでNavigationLinkを付けずにハイライトさせたい

SwiftUI で List のセルのタップを拾うとき、素直に NavigationLink を設定していればセルがハイライトされますが、 onTapGesture() 等でカスタムしたいときはセルがハイライトされません。

struct LandmarkRow: View {
    var landmark: Landmark

    var body: some View {
        HStack {
            landmark.image
                .resizable()
                .frame(width: 50, height: 50)
            Text(landmark.name)
            Spacer()
        }
    }
}

↑こんなセルで

struct LandmarkList: View {
    var body: some View {
        NavigationView {
            List(landmarkData) { landmark in
                NavigationLink(destination: LandmarkDetail()) {
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationBarTitle(Text("Landmarks"))
        }
    }
}

struct LandmarkList_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkList()
    }
}

↑ハイライトされる

struct LandmarkList: View {
    var body: some View {
        NavigationView {
            List(landmarkData) { landmark in
                LandmarkRow(landmark: landmark).onTapGesture {
                    // 何か
                }
            }
            .navigationBarTitle(Text("Landmarks"))
        }
    }
}

struct LandmarkList_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkList()
    }
}

↑ハイライトされない

セル内に Button を入れるとハイライトされるようになります。

struct LandmarkRow: View {
    var landmark: Landmark

    var body: some View {
        ZStack {
            Button(action: {
                // 何か
            }) {
                Color.clear
            }
            HStack {
                landmark.image
                    .resizable()
                    .frame(width: 50, height: 50)
                Text(landmark.name)
                Spacer()
            }
        }
    }
}

逆に、セル内にボタンがあるけどセル自体はハイライトさせたくない場合は、 buttonStyle を設定します。

struct LandmarkRow: View {
    var landmark: Landmark

    var body: some View {
        HStack {
            Button(action: {
                // 何か
            }) {
                landmark.image
                    .resizable()
                    .frame(width: 50, height: 50)
            }
            Text(landmark.name)
            Spacer()
        }
            .buttonStyle(PlainButtonStyle())
    }
}