skip to Main Content

I am wondering if anyone else is seeing this behavior. I have an app that builds for iPadOS 14-16 only where editMode behavior is broken in iOS 16 only. We have a custom edit button design so using the default one(which seems to be the only way to get the drag and drop icon to show) is not an option. Only after dragging a cell or when there are a lot of cells and you scroll off screen does the drag and drop icon show. Using the following code:

struct Number: Identifiable {
    let id: String
    let number: Int
}

struct ContentView: View {
    @State var testData = Array(1..<10).map { Number(id: UUID().uuidString, number: $0) }
    @State var editMode: EditMode = .inactive
    @State var isEditing: Bool = false
    
    var body: some View {
        NavigationView {
            List {
                ForEach(testData) {
                    TestCellView(title: "($0.number)")
                }
                .onMove(perform: editMode == .active ? moveRow : nil)
            }
            .listStyle(PlainListStyle())
            .padding()
            .navigationBarTitle("Hello")
            .navigationBarItems(leading: Button(editMode == .active ? "Done" : "Edit", action: {
                editMode = editMode == .active ? .inactive : .active
            }))
            .environment(.editMode, $editMode)
        }
    }
    
    private func moveRow(from source: IndexSet, to destination: Int) {
        withAnimation {
            testData.move(fromOffsets: source, toOffset: destination)
        }
    }
}

I have been beating my head against the wall with no results so far.

editMode is on but there is no drag and drop indicator on the right of the cells

2

Answers


  1. Chosen as BEST ANSWER

    Based on the design of our app the above solutions didn't work for us as iPadOS allows editing of a list even when editMode is not .active. So we ended up going with a hack/workaround where we show one list that edits/one list that is read-only and switch back and forth.

    Something like the code below:

    List {
        if editMode == .active {
            ForEach(testData) {
                TestCellView(title: "($0.number)")
            }
            .onMove(perform: moveRow)
        } else {
            ForEach(testData) {
                TestCellView(title: "($0.number)")
            }
        }
    }
    .environment(.editMode, $editMode)
    .listStyle(PlainListStyle())
    .padding()
    .navigationBarTitle("Hello")
    .navigationBarItems(leading: Button(editMode == .active ? "Done" : "Edit", action: {
        editMode = editMode == .active ? .inactive : .active
    }))
    .animation(nil, value: editMode.isEditing)
    

    It isn't the best solution but it gets the job done.


  2. Instead of creating your own button, how about using the .buttonStyle modifier, and customising the standard EditButton, e.g.

    struct EditButtonStyle: ButtonStyle {
            
        @Environment(.editMode) var editMode
        
        func makeBody(configuration: Configuration) -> some View {
            switch editMode?.wrappedValue {
            case .active:
                Image(systemName: "checkmark.square")
                    .foregroundColor(.accentColor)
            default:
                Image(systemName: "square.and.pencil")
                    .foregroundColor(.accentColor)
            }
        }
    }
    
    extension ButtonStyle where Self == EditButtonStyle {
        static var edit: Self {
            EditButtonStyle()
        }
    }
    
    

    This simplifies your List

    struct ContentView: View {
        @State var testData = Array(1..<10).map { Number(id: UUID().uuidString, number: $0) }
        
        var body: some View {
            NavigationView {
                List {
                    ForEach(testData) {
                        Text("($0.number)")
                    }
                    .onMove(perform: moveRow)
                }
                .listStyle(PlainListStyle())
                .padding()
                .navigationBarTitle("Hello")
                .navigationBarItems(leading: EditButton().buttonStyle(.edit))
            }
        }
        
        private func moveRow(from source: IndexSet, to destination: Int) {
            testData.move(fromOffsets: source, toOffset: destination)
        }
    }
    

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search