8

I have a simple view which contains a group of Buttons which allow drag feature depends on condition. How can i disable .onDrag based on the condition? The .disabled only disable click function.

    ScrollView
    {
        ForEach(animals, id: \.id)
        {
            animal in
            Button(action:{})
            {
               Text(animal.name)
            }
                .disabled(!animal.isEnable)
                .onDrag
                {
                    let provider = NSItemProvider(object: animal.name as NSString )
                    provider.suggestedName = animal.name
                    return provider
                }
          }
    }
1
  • What about wrapping the .onDrag closure in an if statement? Commented Apr 23, 2020 at 14:40

3 Answers 3

13

Here is a solution with helper modifier. Tested with Xcode 11.4.

// @available(iOS 13.4, *) - needed for iOS
struct Draggable: ViewModifier {
    let condition: Bool
    let data: () -> NSItemProvider

    @ViewBuilder
    func body(content: Content) -> some View {
        if condition {
            content.onDrag(data)
        } else {
            content
        }
    }
}

// @available(iOS 13.4, *) - needed for iOS
extension View {
    public func drag(if condition: Bool, data: @escaping () -> NSItemProvider) -> some View {
        self.modifier(Draggable(condition: condition, data: data))
    }
}

and updated your code would be

ForEach(animals, id: \.id)
{
    animal in
    Button(action:{})
    {
        Text(animal.name)
    }
    .disabled(!animal.isEnable)
    .drag(if: animal.isEnable) {     // << here !!
        let provider = NSItemProvider(object: animal.name as NSString )
        provider.suggestedName = animal.name
        return provider
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

Disabled usually won't work.

Create an extension for a View and put if

extension View {
    @ViewBuilder func `if`<Content: View>(_ condition: @autoclosure () -> Bool, transform: (Self) -> Content) -> some View {
        if condition() {
            transform(self)
        } else {
            self
        }
    }
}

and use like this:

Button(//) {
//
}
.if(animal.isEnable, transform: { view in
    view
       .draggable()
       // or .onDrag...
}

Comments

0

.disable kills the interaction with the view therefore no dragging so it does what you need

you can check the documentation

A view that controls whether users can interact with this view. https://developer.apple.com/documentation/swiftui/list/disabled(_:)

I think there might be a small mistake here, better to be sure isEnable param is correctly sent.

.disabled(!animal.isEnable)

4 Comments

disabled(_:) does not work on onDrop.
disabled() does indeed work if applied after the onDrag() and kills the interaction(just tested on iOS16.4 sim). Keep in mind that not only the dragging, but also other interaction will be killed, like buttons etc.
testing disabled() on macOS 12 and 13 showed no effect to .onDrag().
My bad, I just noticed that I mixed onDrag with onDrop. Yes disabled() works for onDrag, but not onDrop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.