即使没有“点击”,SwiftUI List ForEach 视图中的按钮也会触发?

Posted

技术标签:

【中文标题】即使没有“点击”,SwiftUI List ForEach 视图中的按钮也会触发?【英文标题】:Buttons in SwiftUI List ForEach view trigger even when not "tapped"? 【发布时间】:2022-01-20 18:30:39 【问题描述】:

我有以下代码:

struct ButtonTapTest: View 
    
    let items = [1, 2, 3]
    
    var body: some View 
        
        List 
            ForEach(items, id:\.self)  item in
                CellTestView()
            
        
        
    



struct CellTestView:View 
    
    
    var body: some View 
        
        VStack 
            
            Button 
                print("TOP")
             label: 
                Image(systemName: "play.fill")
                    .font(.system(size: 40))
                    .foregroundColor(.red)
            
            .border(.red)
            
            Spacer()
            
            Button 
                print("BOTTOM")
                
             label: 
                Image(systemName: "play")
                    .font(.system(size: 40))
                    .foregroundColor(.red)
            
            .border(.yellow)
            
        
        
    
    

创建以下屏幕:

问题:

无论我在哪里点击CellTestView,都会在单元格中触发两个按钮操作。我希望单独触发各个按钮操作,每个按钮仅在其按钮被点击时触发,而不是在我在单元格的其他任何地方点击外部时触发。

您可以在下面的 gif 中看到,无论我在哪里点击 CellTestView,这两个按钮操作都会触发,无论我点击视图的哪个位置,“TOP”和“BOTTOM”日志都会在同一时间。

如何解决此问题,以便单元格中的两个按钮独立接收点击,并且仅当点击位于相关按钮内时?

【问题讨论】:

【参考方案1】:

当列表行中有多个按钮时,您需要手动将按钮样式设置为.borderless.plain。这是因为按钮“适应”它们的上下文。 根据documentation:

如果您在容器内创建按钮,如List,则样式将解析为该容器内针对该特定平台的按钮的推荐样式。

因此,当您的按钮位于列表中时,它的点击目标会延伸以填充行,并且您会获得高亮动画。当你有两个以上的按钮时,SwiftUI 不够聪明,无法阻止这种副作用,所以你需要手动设置buttonStyle

CellTestView()
    .buttonStyle(.borderless)

结果:

【讨论】:

那么,这是为什么呢?我想了解这样做的原因。我们是否需要一直使用.buttonStyle(.borderless) 修饰符来修改单元格视图以使按钮工作,或者这是一个例外?你能详细说明为什么会这样吗? @zumzum 查看我的编辑【参考方案2】:

我对这个问题的解决方法是将每个按钮包装在它自己的 VStack 或 HStack 中。

【讨论】:

【参考方案3】:

当您有一个列表时,点击列表行将触发两个按钮。 试试这段代码,让每个“按钮”等效,分别触发。

struct CellTestView: View 

    var body: some View 
        VStack 
            Image(systemName: "play.fill") .font(.system(size: 40)).foregroundColor(.red).border(.red)
                .onTapGesture 
                    print("-----> playFill \(playFill)")
                
            Spacer()
            Image(systemName: "play") .font(.system(size: 40)).foregroundColor(.red).border(.yellow)
                .onTapGesture 
                    print("--> play \(play)")
                
        
    

【讨论】:

以上是关于即使没有“点击”,SwiftUI List ForEach 视图中的按钮也会触发?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 15.3+ SwiftUI的Form视图中嵌入List及Button若干诡异行为的解决

Xcode 12 + SwiftUI List:点击粘贴时列表行叠加

使用 SwiftUI,我们在 List 中安装了一个 Button。为啥当我点击按钮显示模态然后再次关闭时模态消失?

为啥即使发布者发出一个值,我的视图也没有在 SwiftUI 中呈现

在 SwiftUI for macOS 应用程序中获取点击手势的鼠标/指针位置

如何在 SwiftUI 中以编程方式滚动列表?