[英]SwiftUI - how to exclude inner `DragGesture` from outer `simultaneousGesture`?
我在灰色容器中有一个黄色按钮和一个蓝色圆圈。 我将DragGesture
添加到圆圈和容器中——但是,圆圈永远不会移动。
这是我想要的行为:
拖动灰色区域 | 拖动按钮 | 拖动圆圈 |
---|---|---|
容器移动 | 容器移动 | 圆圈移动 |
这就是我得到的:
这是我的代码:
struct ContentView: View {
@GestureState var containerOffset = CGSize.zero
@GestureState var circleOffset = CGSize.zero
var body: some View {
VStack { /// gray container
/// should move the gray container when dragged
Button {
print("Button Pressed")
} label: {
Text("Button")
.padding(50)
.background(.yellow)
}
/// should **NOT** move the gray container when dragged
/// How do I make it move the circle instead?
Circle()
.fill(.blue)
.frame(width: 100, height: 100)
.offset(circleOffset)
.gesture(
DragGesture() /// this never gets called!
.updating($circleOffset) { value, circleOffset, transaction in
circleOffset = value.translation
}
)
.padding(50)
}
.background(Color.gray)
.offset(containerOffset)
.simultaneousGesture( /// `simultaneous` is needed to allow dragging from the yellow button
DragGesture() /// move the gray container
.updating($containerOffset) { value, containerOffset, transaction in
containerOffset = value.translation
}
)
}
}
如何阻止外部DragGesture
吞下内圈的DragGesture
?
一种方法是在ContentView
中添加一个 state 变量来跟踪圆圈的手势是否处于活动状态。 当圆圈的手势处于活动状态时,在外部手势上使用GestureMask
的.subviews
以防止其激活。 您可以使用@State
来做到这一点:
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
@GestureState var containerOffset = CGSize.zero
@GestureState var circleOffset = CGSize.zero
@State var subviewDragIsActive = false
var body: some View {
VStack { /// gray container
/// should move the gray container when dragged
Button {
print("Button Pressed")
} label: {
Text("Button")
.padding(50)
.background(Color.yellow)
}
/// should **NOT** move the gray container when dragged
/// How do I make it move the circle instead?
Circle()
.fill(Color.blue)
.frame(width: 100, height: 100)
.offset(circleOffset)
.gesture(
DragGesture() /// this never gets called!
.updating($circleOffset) { value, circleOffset, transaction in
circleOffset = value.translation
}
.onChanged { _ in
subviewDragIsActive = true
}
.onEnded { _ in
subviewDragIsActive = false
}
)
.padding(50)
}
.background(Color.gray)
.offset(containerOffset)
.simultaneousGesture( /// `simultaneous` is needed to allow dragging from the yellow button
DragGesture() /// move the gray container
.updating($containerOffset) { value, containerOffset, transaction in
containerOffset = value.translation
},
including: subviewDragIsActive ? .subviews : .all
)
}
}
PlaygroundPage.current.setLiveView(ContentView())
或者您可以使用@GestureState
来做到这一点:
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
@GestureState var containerOffset = CGSize.zero
@GestureState var circleOffset = CGSize.zero
@GestureState var subviewDragIsActive = false
var body: some View {
VStack { /// gray container
/// should move the gray container when dragged
Button {
print("Button Pressed")
} label: {
Text("Button")
.padding(50)
.background(Color.yellow)
}
/// should **NOT** move the gray container when dragged
/// How do I make it move the circle instead?
Circle()
.fill(Color.blue)
.frame(width: 100, height: 100)
.offset(circleOffset)
.gesture(
DragGesture() /// this never gets called!
.updating($circleOffset) { value, circleOffset, transaction in
circleOffset = value.translation
}
.updating($subviewDragIsActive) {
_, flag, _ in
flag = true
}
)
.padding(50)
}
.background(Color.gray)
.offset(containerOffset)
.simultaneousGesture( /// `simultaneous` is needed to allow dragging from the yellow button
DragGesture() /// move the gray container
.updating($containerOffset) { value, containerOffset, transaction in
containerOffset = value.translation
},
including: subviewDragIsActive ? .subviews : .all
)
}
}
PlaygroundPage.current.setLiveView(ContentView())
如果圆圈属于单独定义的View
类型,则应使用@State
以便向下传递Binding
,如下所示:
import SwiftUI
import PlaygroundSupport
struct CircleView: View {
@GestureState var circleOffset = CGSize.zero
@Binding var dragIsActive: Bool
var body: some View {
Circle()
.fill(Color.blue)
.frame(width: 100, height: 100)
.offset(circleOffset)
.gesture(
DragGesture() /// this never gets called!
.updating($circleOffset) { value, circleOffset, transaction in
circleOffset = value.translation
}
.onChanged { _ in dragIsActive = true }
.onEnded { _ in dragIsActive = false }
)
}
}
struct ContentView: View {
@GestureState var containerOffset = CGSize.zero
@State var subviewDragIsActive = false
var body: some View {
VStack { /// gray container
/// should move the gray container when dragged
Button {
print("Button Pressed")
} label: {
Text("Button")
.padding(50)
.background(Color.yellow)
}
/// should **NOT** move the gray container when dragged
/// How do I make it move the circle instead?
CircleView(dragIsActive: $subviewDragIsActive)
.padding(50)
}
.background(Color.gray)
.offset(containerOffset)
.simultaneousGesture( /// `simultaneous` is needed to allow dragging from the yellow button
DragGesture() /// move the gray container
.updating($containerOffset) { value, containerOffset, transaction in
containerOffset = value.translation
},
including: subviewDragIsActive ? .subviews : .all
)
}
}
PlaygroundPage.current.setLiveView(ContentView())
如果多个子视图中的任何一个可能同时进行拖动(由于多点触控),您可能应该使用首选项系统将它们的 isActive 状态传递给ContentView
,但这是一个复杂得多的实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.