Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - delete row in list with context menu - UI glitch

I've a array of items displayed using List in my SwiftUI View. I tired to add a contextMenu to delete individual items in the List. The following is the result.

delteing items from list

The animation is not what is expected. The row blinks before moving the next one. How to set animation.right or something like that so that there is no UI glitch and looks like the default behavior which happens at onDelete.

PS: I can't use onDelete because, in my app, swiping right and left has other functions.

Here is the code.


struct ListDelete: View {
    
    @State var cars = ["Tesla", "Mercedes", "Audi", "Tata", "Jaguar"]
    
    var body: some View {
        List(cars, id: \.self) { car in
            Text(car).contextMenu {
                Button(action: {
                    if let index = self.cars.firstIndex(of: car) {
//                        self.cars.remove(at: index)
                        self.cars.remove(atOffsets: [index])
                    }
                }, label: {
                    HStack {
                        Text("Delete")
                        Spacer()
                        Image(systemName: "trash")
                    }
                })
            }
        }
    }
}

The two approaches used to remove the items from the array, resulted in this same behavior.

like image 754
Imthath Avatar asked Feb 23 '20 03:02

Imthath


2 Answers

It’s an issue with SwiftUI, hopefully Apple fix it in the next major release. For now you can solve the issue by adding a small delay before actions are performed in your context button action:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7){
    //delete row
}
like image 187
Nick Avatar answered Oct 18 '22 02:10

Nick


It goes from List, unfortunately ListStyle protocol has any public API. The only way I see now, is mimic List with ScrollView

import SwiftUI

struct ContentView: View {

    @State var cars = ["Tesla", "Mercedes", "Audi", "Tata", "Jaguar"]
    var body: some View {
        ScrollView {
            ForEach(cars, id: \.self) { car in
                VStack(alignment: .leading, spacing: 0) {
                    HStack {
                        Text(car).padding()
                        Spacer()
                    }
                    .contextMenu {
                        Button(action: {
                            if let index = self.cars.firstIndex(of: car) {
                                    self.cars.remove(at: index)
                            }
                        }, label: {
                            HStack {
                                Text("Delete")
                                Spacer()
                                Image(systemName: "trash")
                            }
                        })
                    }
                    Divider().padding(.leading)
                }.padding(.bottom, 0) // set -4 to be symetric
            }
        }
    }
}

with the following result

enter image description here

like image 3
user3441734 Avatar answered Oct 18 '22 04:10

user3441734