Mystic Muffin
Mystic Muffin

Reputation: 221

How to find out if view is currently selected in SwiftUI

I'd like to find out whether my view is currently selected or not. I have a rectangle which represents a card. Once I tap the card, the card should go into the selected state and change properties like the color.

But once I tap somewhere else, the card should not be in that state anymore.

So far, I did not manage to figure this out as I tried with the onTapGesture property but with that I run into the problem that when I tap outside that card, the card does not change the state to false unless I tap the card again, which makes sense but it seems to be the wrong choice in this case.

import SwiftUI

struct CardView: View {
    @State var selected = false
    let rectangle = Rectangle()
    @State var rectangleColor: Color = .purple


    var body: some View {
        GeometryReader { g in
            self.rectangle
                .foregroundColor(self.rectangleColor)
                .frame(width: g.size.width / 2, height: g.size.width / 2)
                .onTapGesture {
                    self.selected.toggle()
                    self.modifyColors()
                }
        }
    }

    func modifyColors() {
        if selected {
            rectangleColor = .red
        } else {
            rectangleColor = .purple
        }
    }
}

The selected state is the red color, the unselected one the purple color. So I want that the color becomes red when I tap into the rectangle but not if I tap outside it. It should become purple only again when I tap outside the rectangle but not inside it. Example: Card is purple. I select it and it becomes red. When I then tap it again, it should stay red. It should become only purple (unselected) when I tap somewhere outside the card but not inside it.


View that contains this rectangle:

import SwiftUI
struct ContentView: View {
    var body: some View {
        CardView()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

It shouldn't matter where the view is actually - I want to know weather the space around that view is tapped. So if it is inside a modal, or the top view on a ZStack, the behavior should be the same.

Upvotes: 5

Views: 3295

Answers (1)

LuLuGaGa
LuLuGaGa

Reputation: 14428

The way to achieve this is by having the parent view manage both the selection and the gestures.

The CardView just takes a @Binding to isSelected and changes the colour accordingly:

struct CardView: View {

    @Binding var isSelected: Bool

    var body: some View {
        Rectangle()
            .fill(self.isSelected ? Color.red : Color.purple)
            .aspectRatio(1.0, contentMode: .fit)
    }
}

While the parent manages the @State and updates it using gestures.

struct ContentView: View {

    @State var isCardSelected = false

    var body: some View {
        ZStack {
            Color.white
                .onTapGesture {
                    self.isCardSelected = false
                }
            CardView(isSelected: $isCardSelected)
                .onTapGesture {
                    self.isCardSelected = true
                }
        }
    }
}

Upvotes: 2

Related Questions