noloman
noloman

Reputation: 11975

SwiftUI: draw a rectangle around a view when tapped

I'm trying to "select" and "deselect" a view in SwiftUI.

What I thought I could do is, when the user taps on a Text that contains a certain string (in my case it is an emoji) the Text should be surrounded by a rectangle. If the view is being deselected, then the rectangle would disappear.

I have tried the following but it does not work, as nothing changes in the view:

Text(emoji.text)
  .onDrag { NSItemProvider(object: emoji.text as NSString) }
  .modifier(SelectionSquare(select: selectedEmojis.toggleMatching(element: emoji) ? true: false))
  // Getting a warning in the line above: Modifying state during view update, this will cause undefined behavior.

struct SelectionSquare: ViewModifier {
    var select: Bool
    func body(content: Content) -> some View {
        content
            .onTapGesture {
                content.overlay(Rectangle().border(Color.red, width: 2.0))
                // Getting a warning here: Result of call to 'overlay(_:alignment:)' is unused
            }
    }
}

Why doesn't this work? Is there any other way to do this?

Thanks in advance!

Upvotes: 2

Views: 754

Answers (1)

Raja Kishan
Raja Kishan

Reputation: 18914

You are getting warning this Result of call to 'overlay(_:alignment:)' is unused because of onTapGesture is not returning anything and overlay return view.

You can use this approach.

struct EmojiView: View {
    private var text = "😄😄😄😄😄😄😄😄😄😄😄😄"
    @State private var selectedEmojis: Bool = false
    
    var body: some View {
        Text(text)
            .onDrag { NSItemProvider(object: text as NSString) }
            .modifier(SelectionSquare(select: $selectedEmojis))
    }
}

struct SelectionSquare: ViewModifier {
    
    @Binding var select: Bool
    
    func body(content: Content) -> some View {
        
        self.setBorder(to: content)
            .onTapGesture {
                select.toggle()
            }
    }
    
    @ViewBuilder
    private func setBorder(to content: Content) -> some View{
        if select {
            content
                .overlay(Rectangle().fill(Color.clear).border(Color.red, width: 2.0))
        } else {
            content
        }
    }
}

enter image description here

Upvotes: 2

Related Questions