web-dev-qa-db-fra.com

Animation indésirable lors du déplacement d'éléments dans la liste SwiftUI

J'ai une liste SwiftUI comme dans l'exemple de code ci-dessous.

struct ContentView: View {
    @State var numbers = ["1", "2", "3"]
    @State var editMode = EditMode.inactive

    var body: some View {
        NavigationView {
            List {
                ForEach(numbers, id: \.self) { number in
                    Text(number)
                }
                .onMove {
                    self.numbers.move(fromOffsets: $0, toOffset: $1)
                }
            }
            .navigationBarItems(trailing: EditButton())
        }
    }
}

Lorsque j'entre en mode édition et que je déplace l'élément d'une position vers le haut, l'animation étrange se produit après avoir déposé l'élément (voir le gif ci-dessous). Il semble que l'élément glissé revient à sa position d'origine, puis se déplace à nouveau vers la destination (avec animation)

strange animation when reordering items

Ce qui est intéressant, cela ne se produit pas si vous faites glisser l'élément vers le bas de la liste ou plusieurs positions vers le haut.

Je suppose que c'est parce que la liste effectue une animation lorsque les éléments dans l'état sont réorganisés même s'ils ont déjà été réorganisés du côté de la vue par glisser-déposer. Mais apparemment, il le gère bien dans tous les cas, à l'exception du déplacement de l'élément d'une position vers le haut.

Des idées sur la façon de résoudre ce problème? Ou peut-être est-ce un bug connu?

J'utilise XCode 11.4.1 et la cible de construction est iOS 13.4

(Veuillez également noter que dans l'application "du monde réel", j'utilise Core Data et que lors du déplacement des éléments, leur ordre est mis à jour dans la base de données, puis l'état est mis à jour, mais le problème avec l'animation est exactement le même.)

6
Mateusz K

Voici une solution basée sur le commentaire de Mateusz K dans la réponse acceptée. J'ai combiné le hachage de l'ordre et du numéro. J'utilise un objet complexe à la place du nombre qui est mis à jour dynamiquement. De cette façon, l'élément de liste s'actualise si l'objet sous-jacent change.

class HashNumber : Hashable{
        
        var order : Int
        var number : String
        
        init(_ order: Int, _ number:String){
            self.order = order
            self.number = number
        }
        
        static func == (lhs: HashNumber, rhs: HashNumber) -> Bool {
            return lhs.number == rhs.number && lhs.order == rhs.order
        }
        //
        func hash(into hasher: inout Hasher) {
            hasher.combine(number)
            hasher.combine(order)
        }
    }
    
    func createHashList(_ input : [String]) -> [HashNumber]{
        
        var r : [HashNumber] = []
        
        var order = 0
        for i in input{
            let h = HashNumber(order, i)
            r.append(h)
            order += 1
        }
        
        return r
    }
    
    struct ContentView: View {
        @State var numbers = ["1", "2", "3"]
        @State var editMode = EditMode.inactive
        
        var body: some View {
            NavigationView {
                List {
                    ForEach(createHashList(numbers), id: \.self) { number in
                        Text(number.number)
                    }
                    .onMove {
                        self.numbers.move(fromOffsets: $0, toOffset: $1)
                    }
                }
                .navigationBarItems(trailing: EditButton())
            }
        }
    }
0
Jerry Sha