工具栏区域中的 SwiftUI 手势被忽略
SwiftUI gestures in the toolbar area ignored
我想实现一个自定义滑块 SwiftUI 组件并将其放在 SwiftUI Mac 应用程序的工具栏区域。然而,控件的手势会被忽略,因为系统的 window 移动手势优先。系统 UI 控件不会出现此问题,例如 Slider
或 Button
。
如何修复下面的代码,使滑块在工具栏区域也能正常工作,而不仅仅是在类似于默认 SwiftUI 组件的 window 内部?
struct MySlider: View {
@State var offset: CGFloat = 0.0
var body: some View {
GeometryReader { gr in
let thumbSize = gr.size.height
let maxValue = (gr.size.width - thumbSize) / 2.0
let gesture = DragGesture(minimumDistance: 0).onChanged { v in
self.offset = max(min(v.translation.width, maxValue), -maxValue)
}
ZStack {
Capsule()
Circle()
.foregroundColor(Color.yellow)
.frame(width: thumbSize, height: thumbSize)
.offset(x: offset)
.highPriorityGesture(gesture)
}
}.frame(width: 100, height: 20)
}
}
struct ContentView: View {
@State var value = 0.5
var body: some View {
MySlider()
.toolbar {
MySlider()
Slider(value: $value).frame(width: 100, height: 20)
}.frame(width: 500, height: 100)
}
}
看起来像是设计限制(或尚未实现的功能 - Apple 未将此类视图视为支持用户交互的项目)。
一种可能的解决方法是将您的活动元素包装成按钮样式。作为容器的按钮被解释为 user-interaction-able 区域,但所有绘图和处理都在您的代码中。
测试 Xcode 13.2 / macOS 12.2
注意:滑块逻辑没有变化
struct MySlider: View {
var body: some View {
Button("") {}.buttonStyle(SliderButtonStyle())
}
struct SliderButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
MySliderContent()
}
struct MySliderContent: View {
@State var offset: CGFloat = 0.0
var body: some View {
GeometryReader { gr in
let thumbSize = gr.size.height
let maxValue = (gr.size.width - thumbSize) / 2.0
let gesture = DragGesture(minimumDistance: 0).onChanged { v in
self.offset = max(min(v.translation.width, maxValue), -maxValue)
}
ZStack {
Capsule()
Circle()
.foregroundColor(Color.yellow)
.frame(width: thumbSize, height: thumbSize)
.offset(x: offset)
.highPriorityGesture(gesture)
}
}.frame(width: 100, height: 20)
}
}
}
}
我想实现一个自定义滑块 SwiftUI 组件并将其放在 SwiftUI Mac 应用程序的工具栏区域。然而,控件的手势会被忽略,因为系统的 window 移动手势优先。系统 UI 控件不会出现此问题,例如 Slider
或 Button
。
如何修复下面的代码,使滑块在工具栏区域也能正常工作,而不仅仅是在类似于默认 SwiftUI 组件的 window 内部?
struct MySlider: View {
@State var offset: CGFloat = 0.0
var body: some View {
GeometryReader { gr in
let thumbSize = gr.size.height
let maxValue = (gr.size.width - thumbSize) / 2.0
let gesture = DragGesture(minimumDistance: 0).onChanged { v in
self.offset = max(min(v.translation.width, maxValue), -maxValue)
}
ZStack {
Capsule()
Circle()
.foregroundColor(Color.yellow)
.frame(width: thumbSize, height: thumbSize)
.offset(x: offset)
.highPriorityGesture(gesture)
}
}.frame(width: 100, height: 20)
}
}
struct ContentView: View {
@State var value = 0.5
var body: some View {
MySlider()
.toolbar {
MySlider()
Slider(value: $value).frame(width: 100, height: 20)
}.frame(width: 500, height: 100)
}
}
看起来像是设计限制(或尚未实现的功能 - Apple 未将此类视图视为支持用户交互的项目)。
一种可能的解决方法是将您的活动元素包装成按钮样式。作为容器的按钮被解释为 user-interaction-able 区域,但所有绘图和处理都在您的代码中。
测试 Xcode 13.2 / macOS 12.2
注意:滑块逻辑没有变化
struct MySlider: View {
var body: some View {
Button("") {}.buttonStyle(SliderButtonStyle())
}
struct SliderButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
MySliderContent()
}
struct MySliderContent: View {
@State var offset: CGFloat = 0.0
var body: some View {
GeometryReader { gr in
let thumbSize = gr.size.height
let maxValue = (gr.size.width - thumbSize) / 2.0
let gesture = DragGesture(minimumDistance: 0).onChanged { v in
self.offset = max(min(v.translation.width, maxValue), -maxValue)
}
ZStack {
Capsule()
Circle()
.foregroundColor(Color.yellow)
.frame(width: thumbSize, height: thumbSize)
.offset(x: offset)
.highPriorityGesture(gesture)
}
}.frame(width: 100, height: 20)
}
}
}
}