SwiftUI ONTAPPORATION on Color.clear背景与Color.blue的行为不同

SwiftUI ONTAPPORATION on Color.clear背景与Color.blue的行为不同,swiftui,Swiftui,我正在SegmentedPickerStyle()中制作一个自定义选择器。我希望有相同的行为,但当我点击其中一个可能选择的内容和边框之间的区域时,ontapsignate不起作用。当我添加一个蓝色背景时,它确实可以工作,但如果背景清晰,它就不能工作 在蓝色背景下工作 背景不清楚 非工作代码: import SwiftUI struct PickerElementView<Content>: View where Content : View { @Binding var

我正在
SegmentedPickerStyle()
中制作一个自定义
选择器。我希望有相同的行为,但当我点击其中一个可能选择的内容和边框之间的区域时,
ontapsignate
不起作用。当我添加一个蓝色背景时,它确实可以工作,但如果背景清晰,它就不能工作

在蓝色背景下工作

背景不清楚

非工作代码:

import SwiftUI

struct PickerElementView<Content>: View where Content : View {
    @Binding var selectedElement: Int
    let content: () -> Content

    @inlinable init(_ selectedElement: Binding<Int>, @ViewBuilder content: @escaping () -> Content) {
        self._selectedElement = selectedElement
        self.content = content
    }

    var body: some View {
        GeometryReader { proxy in
            self.content()
                .fixedSize(horizontal: true, vertical: true)
                .frame(minWidth: proxy.size.width, minHeight: proxy.size.height)
                // ##################################################################
                // CHANGE COLOR HERE TO BLUE TO MAKE IT WORK
                // ##################################################################
                .background(Color.clear)
                // ##################################################################
                .border(Color.yellow, width: 5)

        }
    }

}

struct PickerView: View {
    @Environment (\.colorScheme) var colorScheme: ColorScheme

    var elements: [(id: Int, view: AnyView)]

    @Binding var selectedElement: Int
    @State var internalSelectedElement: Int = 0

    private var width: CGFloat = 220
    private var height: CGFloat = 100
    private var cornerRadius: CGFloat = 20
    private var factor: CGFloat = 0.95
    private var color = Color(UIColor.systemGray)
    private var selectedColor = Color(UIColor.systemGray2)


    init(_ selectedElement: Binding<Int>) {
        self._selectedElement = selectedElement
        self.elements = [
            (id: 0, view: AnyView(PickerElementView(selectedElement) {
                    Text("9").font(.system(.title))
            })),
            (id: 1, view: AnyView(PickerElementView(selectedElement) {
                    Text("5").font(.system(.title))

            })),
        ]
        self.internalSelectedElement = selectedElement.wrappedValue
    }

    func calcXPosition() -> CGFloat {
        var pos = CGFloat(-self.width * self.factor / 4)
        pos += CGFloat(self.internalSelectedElement) * self.width * self.factor / 2
        return pos
    }

    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(self.selectedColor)
                .cornerRadius(self.cornerRadius * self.factor)
                .frame(width: self.width * self.factor / CGFloat(self.elements.count), height: self.height - self.width * (1 - self.factor))
                .offset(x: calcXPosition())
                .animation(.easeInOut(duration: 0.2))

            HStack {
                ForEach(self.elements, id: \.id) { item in
                    item.view
                        .gesture(TapGesture().onEnded { _ in
                            print(item.id)
                            self.selectedElement = item.id
                            withAnimation {
                                self.internalSelectedElement = item.id
                            }
                        })
                }
            }
        }
        .frame(width: self.width, height: self.height)
        .background(self.color)
        .cornerRadius(self.cornerRadius)
        .padding()
    }
}

struct PickerView_Previews: PreviewProvider {
    static var previews: some View {
        PickerView(.constant(1))
    }
}


导入快捷界面
结构PickerElementView:视图,其中内容:视图{
@绑定变量selectedElement:Int
让内容:()->内容
@Inlineable init(selectedElement:Binding,@ViewBuilder内容:@escaping()->content){
self.\u selectedElement=selectedElement
self.content=内容
}
var body:一些观点{
GeometryReader{中的代理
self.content()
.fixedSize(水平:真,垂直:真)
.frame(最小宽度:proxy.size.width,最小高度:proxy.size.height)
// ##################################################################
//将此处的颜色更改为蓝色以使其正常工作
// ##################################################################
.背景(颜色.清晰)
// ##################################################################
.边框(颜色.黄色,宽度:5)
}
}
}
结构PickerView:视图{
@环境(\.colorScheme)变量colorScheme:colorScheme
var元素:[(id:Int,view:AnyView)]
@绑定变量selectedElement:Int
@状态变量internalSelectedElement:Int=0
专用变量宽度:CGFloat=220
专用变量高度:CGFloat=100
专用var转弯半径:CGFloat=20
私人var系数:CGFloat=0.95
private var color=color(UIColor.systemGray)
私有变量selectedColor=Color(UIColor.systemGray2)
init(uselectedelement:Binding){
self.\u selectedElement=selectedElement
self.elements=[
(id:0,视图:任意视图(PickerElementView(selectedElement)){
文本(“9”).font(.system(.title))
})),
(id:1,视图:任意视图(PickerElementView(selectedElement)){
文本(“5”).font(.system(.title))
})),
]
self.internalSelectedElement=selectedElement.wrappedValue
}
func calcXPosition()->CGFloat{
var pos=CGFloat(-自宽*自系数/4)
pos+=CGFloat(self.internalSelectedElement)*self.width*self.factor/2
返回位置
}
var body:一些观点{
ZStack{
矩形()
.foregroundColor(自选颜色)
.转角半径(自转角半径*自转角系数)
.frame(宽度:self.width*self.factor/CGFloat(self.elements.count),高度:self.height-self.width*(1-self.factor))
.offset(x:calcXPosition())
.animation(.easeInOut(持续时间:0.2))
HStack{
ForEach(self.elements,id:\.id){item in
item.view
.手势(点击手势().onEnded{uu}in
打印(项目id)
self.selectedElement=item.id
动画片{
self.internalSelectedElement=item.id
}
})
}
}
}
.框架(宽度:自宽,高度:自高)
.背景(自身颜色)
.转角半径(自转角半径)
.padding()
}
}
结构PickerView\u预览:PreviewProvider{
静态var预览:一些视图{
PickerView(.常量(1))
}
}
更改我标记的颜色


有人知道为什么它们的行为会不同吗?我如何解决这个问题?

似乎是一个设计决策,任何不透明度为0的
颜色都是不可见的

Color.clear.onTapGesture { print("tapped") }                 // will not print
Color.blue.opacity(0).onTapGesture { print("tapped") }       // will not print
Color.blue.onTapGesture { print("tapped") }                  // will print
Color.blue.opacity(0.0001).onTapGesture { print("tapped") }  // will print

您可以使用第四个选项来解决这个问题,因为它在视觉上与第一个选项不可区分。

一行答案不是设置背景色,请为命中测试设置
contentShape

 var body: some View {
    GeometryReader { proxy in
        self.content()
            .fixedSize(horizontal: true, vertical: true)
            .frame(minWidth: proxy.size.width, minHeight: proxy.size.height)
            // ##################################################################
            // CHANGE COLOR HERE TO BLUE TO MAKE IT WORK
            // ##################################################################
            .contentShape(Rectangle())
            // ##################################################################
            .border(Color.yellow, width: 5)

    }
}

在SwiftUI中,透明视图默认情况下不可点击,因为其内容形状为零

您可以使用
.contentShape
修改器更改此行为:

Color.clear
.框架(宽度:300,高度:300)
.contentShape(矩形())
.ontaps{print(“tapped”)}

我遇到了一个类似的问题,那就是如何在圆形直角上敲击

我的简单解决方案是将不透明度设置为一个非常低的值,这样就行了

RoundedRectangle(cornerRadius: 12)
.fill(Color.black)
.opacity(0.0001)
.frame(width: 32, height: 32)
.onTapGesture {
 ...
}

谢谢,我将暂时使用它,但这似乎更像是一种解决方法。是的,可能值得提交反馈,即能够在透明视图上注册一个手势会很好。如果默认设置是禁用透明视图的命中测试,这没关系,但是添加一个明确的手势应该会覆盖它,我同意!我将提交反馈,并尝试提出一个更优雅的解决方案。也许其他人会回答这个问题,或者给我一个正确的提示。
。frame(maxWidth:.infinity,maxHeight:.infinity)
非常有用nicer@pleshis没有contentShape,无论框架如何,都无法工作。它不会在非渲染区域上注册接触。这是一个经常让人非常困惑的优化问题。最近在一个游戏库中出现了这个问题,尽管你经常想在其中使用触发器。