尝试使用 SwiftUI 制作可滑动的图像视图时,索引意外更改

Posted

技术标签:

【中文标题】尝试使用 SwiftUI 制作可滑动的图像视图时,索引意外更改【英文标题】:Index unexpectedly changes when trying to make Swipeable Image View with SwiftUI 【发布时间】:2021-08-11 11:35:19 【问题描述】:

我正在尝试使用 SwiftUI 制作可滑动的图像视图。 向左/向右滑动可将图像向左/向右移动,当您滑动足够长的时间时,图像会滑开并出现下一张/上一张图像:就像主屏幕选项卡一样。 点击左/右使上一张/下一张图像替换当前图像,但没有动画。

此视图获取图像数组、索引和图像偏移量。

其他一些视图检测到滑动手势并更改索引。 问题是,当滑动手势更改索引和图像幻灯片时,索引在动画开始后立即更改,而不是在动画完成后更改。

看来var currentIndex = index是这个bug的根源,bug如何修复?

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 && 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】:

我使用 Timer 在动画持续时间(=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))
    

【讨论】:

以上是关于尝试使用 SwiftUI 制作可滑动的图像视图时,索引意外更改的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中使用可观察对象切换视图

如何使用 SwiftUI 实现已裁剪为形状的缓慢滑动图像?

SwiftUI: 使用 ImagePaint 制作边框和填充

如何在 swiftUI 中创建一个普通视图

ScrollView 或 List,如何制作特定的可滚动视图 (SwiftUI)

使用 viewpager 制作图像视图