SwiftUI-手势

742 阅读2分钟

SwiftUI 为我们提供了许多处理视图的手势,并且很好地消除了大部分艰苦的工作

点击 onTapGesture

Text("xxx")
    .onTapGesture {

        //...
    }

可以向它们传递一个参数count,让它们处理双击、三击等等,就像这样:

.onTapGesture(count: 2) {

}  

长按 onLongPressGesture

Text("Hello, World!")
    .onLongPressGesture {


    }  

可以指定按下的最短持续时间,以便您的操作关闭仅在经过特定秒数后触发

.onLongPressGesture(minimumDuration: 2) {

}  

可以添加第二个闭包,该闭包会在手势状态发生更改时触发。

Text("Hello, World!")
    .onLongPressGesture(minimumDuration: 1) {


    } onPressingChanged: { inProgress in


    }  

对于更高级的手势,您应该将gesture()修饰符与以下手势结构之一结合使用:DragGesture、LongPressGesture、MagnifyGesture、RotateGesture和TapGesture。这些通常都有特殊的修饰符onEnded(),onChanged()您可以使用它们在手势进行中 或完成 时采取行动。

捏合

将放大手势附加到视图,以便捏合和张开可以放大或缩小视图。这可以通过创建两个@State属性来存储缩放量,在scaleEffect()修改器内使用它,然后在手势中设置这些值来完成,

struct ContentView: View {

    @State private var currentAmount = 0.0
    @State private var finalAmount = 1.0

    var body: some View {

        Text("Hello, World!")
            .scaleEffect(finalAmount + currentAmount)
            .gesture(

                MagnifyGesture()
                    .onChanged { value in

                        currentAmount = value.magnification - 1

                    }
                    .onEnded { value in

                        finalAmount += currentAmount 
                        currentAmount = 0

                    }
            )
    }
} 

旋转

struct ContentView: View {

    @State private var currentAmount = Angle.zero
    @State private var finalAmount = Angle.zero

    var body: some View {

        Text("Hello, World!")
            .rotationEffect(currentAmount + finalAmount)
            .gesture(

                RotateGesture()
                    .onChanged { value in

                        currentAmount = value.rotation

                    }
                    .onEnded { value in

                        finalAmount += currentAmount
                        currentAmount = .zero

                    }
            )
    }
} 

手势的优先级

当您有两个或多个可能同时识别的手势时,例如,如果您将一个手势附加到视图,并将相同的手势附加到其父级。

VStack {

    Text("Hello, World!")
        .onTapGesture {
 
        }
}
.onTapGesture {
 

} 

在这种情况下,SwiftUI 将始终优先考虑 子视图 的手势 。

如果您想更改此设置,可以使用highPriorityGesture()修饰符强制触发父级的手势

VStack {

    Text("Hello, World!")
        .onTapGesture {

        }
}
.highPriorityGesture(

    TapGesture()
        .onEnded {

        }
)  

或者,您可以使用simultaneousGesture()修饰符告诉 SwiftUI 您希望父手势和子手势同时触发

 VStack {

    Text("Hello, World!")
        .onTapGesture {

        }
}
.simultaneousGesture(

    TapGesture()
        .onEnded {

        }
)  

手势序列

SwiftUI 允许我们创建手势序列,其中一个手势只有在另一个手势首先成功时才会激活 。示例:您可以在其中拖动一个圆圈,但前提是先长按它

禁止交互

Circle()
    .fill(.red)
    .frame(width: 300, height: 300)
    .onTapGesture {
        print("Circle tapped!")
    }
    .allowsHitTesting(false)  

堆栈的交互

默认情况下,当点击堆栈间隔符时,SwiftUI 不会触发操作

VStack {

    Text("Hello")
    Spacer().frame(height: 100)
    Text("World")
}
.onTapGesture {

    print("VStack tapped!")
}  

如果你运行它,你会发现你可以点击“Hello”标签和“World”标签,但不能点击之间的空格。

使用contentShape(.rect) ,VStack那么堆栈的整个区域都变得可点击,包括间隔符

VStack {
    Text("Hello")
    Spacer().frame(height: 100)
    Text("World")
}
.contentShape(.rect)
.onTapGesture {

    print("VStack tapped!")
}