Индекс неожиданно меняется при попытке сделать вид изображения с возможностью прокрутки с помощью SwiftUI

#swift #swiftui

Вопрос:

Я пытаюсь сделать вид изображения с возможностью прокрутки с помощью SwiftUI. Проводя пальцем влево/вправо, изображение перемещается влево/вправо, и когда вы проводите достаточно долго, изображение соскальзывает и появляется следующее/предыдущее изображение: точно так же, как вкладки на главном экране. Нажатие влево/вправо заставляет предыдущее/следующее изображение заменить текущее изображение, но без анимации.

Это представление получает массив изображений, индекс и смещение изображения.

Какой-то другой вид обнаруживает жест свайпа и изменяет индекс. Проблема в том, что когда жест свайпа изменяет индекс и слайды изображения, индекс меняется сразу после запуска анимации, а не после завершения анимации.

Похоже, это var currentIndex = index и есть причина этой ошибки, ошибка, как я могу ее исправить?

 struct MyImagesView: View {
    @Binding var index:Int
    let imgArray:[URL]
    @Binding var dragOffset:CGSize
    @State var nextindex:Int = 1
    @State var screenSize:CGRect = UIScreen.main.bounds
    var body: some View {
        var currentindex = index
        let insertionAnimation: ()->AnyTransition = { nextindex > currentindex ? AnyTransition.move(edge: .leading) : AnyTransition.move(edge: .trailing) }
        let removalAnimation: ()->AnyTransition = { nextindex < currentindex ? AnyTransition.move(edge: .trailing) : AnyTransition.move(edge: .leading) }
        ZStack {`enter code here`
            MyImageView(array: imgArray,index:currentindex-2).offset(x: -screenSize.width, y: 0)
            MyImageView(array: imgArray,index:currentindex-1)
            MyImageView(array: imgArray,index:currentindex).offset(x: screenSize.width, y: 0)
        }
        .offset(dragOffset)
        .onAppear(perform: { nextindex = index })
        .onChange(of: index, perform: { value in
            if dragOffset.width != 0 amp;amp; value != currentindex {
                nextindex = value
                Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { _ in dragOffset = .zero; currentindex = value })
                dragOffset.width = nextindex>currentindex ? -screenSize.width : (nextindex < currentindex ? screenSize.width : 0)
            }
        })
        .transition(.asymmetric(insertion: insertionAnimation(), removal: removalAnimation()))
        .animation(.linear(duration: (dragOffset.width==0) ? 0 : 0.5))
    }
}
 

Ответ №1:

Я использовал таймер для изменения индекса после продолжительности анимации(=0,5 с), и это решило проблему. И не было никакой необходимости в переходе.

 struct MyImagesView: View {
    @Binding var index:Int
    let imgArray:[URL]
    @Binding var dragOffset:CGSize
    @State var nextindex:Int = 1
    @State var screenSize:CGRect = UIScreen.main.bounds
    var body: some View {
        ZStack {
            MyImageView(array: imgArray, index: index-2).offset(x: -screenSize.width, y: 0)
            MyImageView(array: imgArray, index: index-1)
            MyImageView(array: imgArray, index: index).offset(x: screenSize.width, y: 0)
        }
        .offset(dragOffset)
        .onAppear(perform: { nextindex = index })
        .onChange(of: index, perform: { value in
            if dragOffset.width != 0 {
                dragOffset = .zero
            }
        })
        .animation(.linear(duration: (dragOffset.width==0) ? 0 : 0.5))
    }
}