Drag and Drop Editable Lists: Tutorial for SwiftUI

Grow your SwiftUI List skills beyond the basics. Implement editing, moving, deletion and drag-and-drop support. Then, learn how custom views can support draggable content. By Bill Morefield.

3.6 (9) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Dropping Between Views

For the final piece of the puzzle, open ContentView.swift and add the following modifier to FocusTodoView underneath its padding() modifier:

.onDrop(
  of: [TodoItem.typeIdentifier],
  delegate: TodoDropDelegate(focusId: $focusId))

Here, you indicate you only want to accept objects with TodoItem‘s type identifier and pass an instance of the delegate you just created with a binding to the focusId state you added earlier.

Build and run. And there you have it! Drag any TODO item from the active list and drop it in the focused area. You can even tap the Completed toggle in the focus area, and you’ll see both elements reflect the change in status.

Dragging a TODO item into the focus area at the top of the screen

Trying Out Another Way to Drop

Using DropDelegate isn’t the only way to support dropping. To demonstrate another approach, you’ll add support for dropping an active TODO into the Completed section and marking it as completed at the same time.

Open ContentView.swift and add the following modifier to the CompletedTodoView:

// 1
.onDrop(of: [TodoItem.typeIdentifier], isTargeted: nil) { itemProviders in
  // 2
  for itemProvider in itemProviders {
    itemProvider.loadObject(ofClass: TodoItem.self) { todoItem, _ in
      // 3
      guard let todoItem = todoItem as? TodoItem else { return }
      DispatchQueue.main.async {
        todoList.updateTodo(withId: todoItem.id, isCompleted: true)
      }
    }
  }
  // 4
  return true
}

This might look familiar:

  1. Instead of onDrop(of:delegate:), use onDrop(of:isTargeted:perform:), which allows you to perform the drop operation directly inside the closure.
  2. For each NSItemProvider passed to the closure, load the TODO, as before, by using loadObject(ofClass:completionHandler:).
  3. Attempt to cast the loaded object to a TodoItem . If that succeeds, call updateTodo(withId:isCompleted:) to update TodoItem on the main thread.
  4. Return true to tell the system you’ve handled the drop event.

Build and run. Drop any active item into the completed list, and you’ll see it marked as completed.

TODO items being marked as completed as they are dropped into the Completed section

Congratulations! By now, you should have a good handle on how to add editing items and dragging and dropping to your own apps.

Where to Go From Here

Access the final project using the Download Materials button at the top or bottom of this tutorial.

In this tutorial, you explored SwiftUI’s support for user management of the content displayed inside a list. You implemented edit and delete operations and added drag and drop for your custom data type to your app. You also studied the trade-offs on some platforms when using drag and drop.

If you want to explore the concepts in this tutorial further, here are some good resources:

If you have any questions or comments, ask in the forum below!