How to create a scrollable list in which the items can be edited, reordered, added, and removed?

Hi, I am a beginner to swiftui development. I am looking for a way to create a view like the following:

Other than adding and removing, I would also like it to support reordering by drag and drop, and renaming by double clicking.

Since similar views are implemented across applications from apple and third party developers, I was thinking that there should be an intuitive way to do so.

However, the best I could do was:

List(outboundExample, id: \.tag) { outboundObject in
    Text(outboundObject.tag)
}
.navigationTitle("Servers:")
.listStyle(.bordered(alternatesRowBackgrounds: true))
.moveDisabled(false)
.frame(width: 100.0)
.padding()

Which creates a list box that looks similar but without the editing buttons on the bottom, and cannot be clicked on.

I tried googling, and look into the swiftui documentation. However, most of the resources out there are either about iOS, or explains how to edit list with swiping. I just want this simple interface.

Thank you in advance for any help!

Answered by Loriland in 748653022

After a crazy amount of effort, I finally managed to create a view that resembles the images in the question. Here is the result:

Here is how I did it

List(selection: $selectedObject) {
    Foreach($objectList) { object in
        Text(object.name)
            .tag(object)
    }
    .onMove(perform: moveRows)
    .onDelete(perform: deleteRow) /* this use swiping to remove a row */
}
.listStyle(.bordered(alternatesRowBackgrounds: true))
.safeAreaInset(edge: .bottom) {
    HStack {
        Button(action: addRow) {
            Image(systemName: "plus")
        }
        /* uncomment this if you don't want to use swipe to delete a row
        Button(action: deleteRow) {
            Image(systemName: "minus")
        }
        */
        Spacer()
    }
    .buttonStyle(.plain)
    .padding(5)
    .background(.background) /* otherwise the background is translucent */
    .border(.tertiary) /* otherwise no border is shown */
}

func addRow() {
    /* make a new object */
    objectList.append(newObject)
}

func deleteRow(offset: IndexSet) {
    objectList.remove(atOffsets: offset)
}

func moveRows(from source: IndexSet, to destination: Int) {
    objectList.move(fromOffsets: source, toOffset: destination)
}

The solution is a bit complicated and involves several manual adjustion. It seems like this style is not implemented as a native style in SwiftUI

List(outboundExample, id: \.tag) { outboundObject in
    Text(outboundObject.tag)
}
.navigationTitle("Servers:")
.listStyle(.bordered(alternatesRowBackgrounds: true))
.moveDisabled(false)
.frame(width: 100.0)
.padding()
HStack {
 Button {
                    //add row action
                } label: {
                    Image(systemName: "plus")
                }
 Button {
                   //remove row action
                } label: {
                     Image(systemName: "minus")
                }
Spacer()
}

@Geolenko17 Thank you for the reply.

When I applied this solution, I got this

Which is not exactly the style I'm expecting. Also, I still can't click on the rows, not mentioning reordering them. Is there a better way?

Accepted Answer

After a crazy amount of effort, I finally managed to create a view that resembles the images in the question. Here is the result:

Here is how I did it

List(selection: $selectedObject) {
    Foreach($objectList) { object in
        Text(object.name)
            .tag(object)
    }
    .onMove(perform: moveRows)
    .onDelete(perform: deleteRow) /* this use swiping to remove a row */
}
.listStyle(.bordered(alternatesRowBackgrounds: true))
.safeAreaInset(edge: .bottom) {
    HStack {
        Button(action: addRow) {
            Image(systemName: "plus")
        }
        /* uncomment this if you don't want to use swipe to delete a row
        Button(action: deleteRow) {
            Image(systemName: "minus")
        }
        */
        Spacer()
    }
    .buttonStyle(.plain)
    .padding(5)
    .background(.background) /* otherwise the background is translucent */
    .border(.tertiary) /* otherwise no border is shown */
}

func addRow() {
    /* make a new object */
    objectList.append(newObject)
}

func deleteRow(offset: IndexSet) {
    objectList.remove(atOffsets: offset)
}

func moveRows(from source: IndexSet, to destination: Int) {
    objectList.move(fromOffsets: source, toOffset: destination)
}

The solution is a bit complicated and involves several manual adjustion. It seems like this style is not implemented as a native style in SwiftUI

How to create a scrollable list in which the items can be edited, reordered, added, and removed?
 
 
Q