我正在努力在
TapGesture
中同时实现 LongPressGesture
和 ScrollView
。 .onTapGesture
和 .onLongPressGesture
一切正常,但我希望当用户点击按钮时,按钮的不透明度会降低,就像正常的 Button()
一样。
但是,无论出于何种原因,
Button()
都无法选择在长按时执行某些操作。所以我尝试使用.gesture(LongPressGesture() ... )
。此方法有效并显示点击指示。不幸的是,这不适用于 ScrollView
:你无法再滚动它!
所以我做了一些研究,发现在
LongPressGesture
之前必须有一个TapGesture,这样ScrollView
才能正常工作。确实是这样,但我的 LongPressGesture
不再起作用了。
希望有人能提供解决方案...
struct ContentView: View {
var body: some View {
ScrollView(.horizontal){
HStack{
ForEach(0..<5){ _ in
Button()
}
}
}
}
}
struct Button: View{
@GestureState var isDetectingLongPress = false
@State var completedLongPress = false
var body: some View{
Circle()
.foregroundColor(.red)
.frame(width: 100, height: 100)
.opacity(self.isDetectingLongPress ? 0 : 1)
// That works, but there is no indication for the user that the UI recognized the gesture
// .onTapGesture {
// print("Tapped!")
// }
// .onLongPressGesture(minimumDuration: 0.5){
// print("Long pressed!")
// }
// The approach (*) shows the press indication, but the ScrollView is stuck because there is no TapGesture
// If I add a dummy TapGesture, the LongPressGesture won't work anymore but now the ScrollView works as expected
//.onTapGesture {}
// (*)
.gesture(LongPressGesture()
.updating(self.$isDetectingLongPress) { currentstate, gestureState,
transaction in
gestureState = currentstate
}
.onEnded { finished in
self.completedLongPress = finished
}
)
}
}
我已经尝试了多种尝试 onTapGesture + LongPressGesture + 自定义计时和动画的组合,并且许多工作/几乎/但留下了一些小烦恼。这就是我发现效果完美的方法。在 iOS 13.6 上测试。
使用此解决方案,您的滚动视图仍然滚动,您可以获得按钮按下动画,长按按钮也可以。
struct MainView: View {
...
Scrollview {
RowView().highPriorityGesture(TapGesture()
.onEnded { _ in
// The function you would expect to call in a button tap here.
})
}
}
struct RowView: View {
@State var longPress = false
var body: some View {
Button(action: {
if (self.longPress) {
self.longPress.toggle()
} else {
// Normal button code here
}
}) {
// Buttons LaF here
}
// RowView code here.
.simultaneousGesture(LongPressGesture(minimumDuration: 0.5)
.onEnded { _ in
self.longPress = true
})
}
}
我遇到了类似的情况,并使用多个状态变量来处理点击和长按手势,并在 SwiftUI 列表中突出显示行。
代码示例
struct ContentView: View {
@State private var selectedIndex: Int = -1
@State private var longPressStarted = false
@State private var tapStarted = false
let items = ["Item 1", "Item 2", "Item 3", "Item 4"]
var body: some View {
List {
ForEach(items.indices, id: \.self) { index in
listItem(index)
}
}
}
func listItem(_ index: Int) -> some View {
ZStack {
VStack {
Text(items[index])
.padding()
}
.background(selectedIndex == index ? Color(.systemGray4) : Color.white)
.cornerRadius(8)
.onLongPressGesture(minimumDuration: 0) {
longPressStarted = true
selectedIndex = index
} onPressingChanged: { inProgress in
selectedIndex = index // Highlight row while pressing
if !inProgress && longPressStarted {
longPressStarted = false
// Long press finished, handle action here if needed
} else if !inProgress && tapStarted {
tapStarted = false
// Delay to briefly show highlight on tap
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
selectedIndex = -1
}
} else if !inProgress {
// Cancel selection
selectedIndex = -1
}
}
.highPriorityGesture(TapGesture()
.onEnded {
tapStarted = true
selectedIndex = index
})
}
.listRowInsets(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20))
}
}