繁体   English   中英

SwiftUI 中 DragGesture 和 ScrollView 的交互

[英]Interaction of DragGesture and ScrollView in SwiftUI

在我正在开发的应用程序中,有一部分主要是“前进”导航——点击按钮将显示下一张幻灯片。 然而,辅助“向后”导航也是必要的。 这是我使用的方法:

import SwiftUI

struct Sample: View {
    @State private var dragOffset: CGFloat = -100
    var body: some View {
        VStack {

            Text("Perhaps a title")

            ScrollView {
                VStack {
                    Text("Some scrollable content is going to be here")

                    // ...

                    Button(action: {
                        // Go to the next slide
                    }) { Text("Next") }
                }
            }

            Text("and, maybe, something else")
        }
        .overlay(
            Image(systemName: "arrow.left").offset(x: dragOffset / 2),
            alignment: .leading
        )
        .gesture(
            DragGesture()
                .onChanged{
                    self.dragOffset = $0.translation.width
                }
                .onEnded {
                    self.dragOffset = -100 // Hide the arrow

                    if $0.translation.width > 100 {
                        // Go to the previous slide
                    }
                }
        )
    }
}

有一个小指标(左箭头),最初是隐藏的(dragOffset = -100)。 当拖动手势开始时,偏移量被输入到dragOffset状态变量中,并且有效地显示箭头。 当拖动手势结束时,箭头再次隐藏,如果达到某个偏移量,则显示上一张幻灯片。

工作得很好,除了当用户滚动 ScrollView 中的内容时,这个手势也会被触发并更新一段时间,但我认为,它被 ScrollView 取消并且不调用“onEnded”。 结果,箭头指示符停留在屏幕上。

因此,问题是:做这样的手势的正确方法是什么,可以与 ScrollView 一起使用? SwiftUI 的当前状态是否有可能?

对于这种临时状态,最好使用GestureState ,因为它会在手势取消/完成后自动重置为初始状态。

所以这是可能的方法

更新:使用 Xcode 13.4 / iOS 15.5 重新测试

演示:

在此处输入图像描述

代码:

struct Sample: View {
    @GestureState private var dragOffset: CGFloat = -100
    var body: some View {
        VStack {

            Text("Perhaps a title")

            ScrollView {
                VStack {
                    Text("Some scrollable content is going to be here")

                    // ...

                    Button(action: {
                        // Go to the next slide
                    }) { Text("Next") }
                }
            }

            Text("and, maybe, something else")
        }
        .overlay(
            Image(systemName: "arrow.left").offset(x: dragOffset / 2),
            alignment: .leading
        )
        .gesture(
            DragGesture()
                .updating($dragOffset) { (value, gestureState, transaction) in
                    let delta = value.location.x - value.startLocation.x
                    if delta > 10 { // << some appropriate horizontal threshold here
                        gestureState = delta
                    }
                }
                .onEnded {
                    if $0.translation.width > 100 {
                        // Go to the previous slide
                    }
                }
        )
    }
}

注意: dragOffset: CGFloat = -100这可能对不同的真实设备有不同的影响,所以可能最好明确计算。

备份

如果您不想使用@GestureState也可以使用DragGesture(minimumDistance: 0.0) 这让 DragGesture 在滚动手势被激活之前启动。 虽然这对我来说似乎是苹果的一个错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM