You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中onTapGesture导致NavigationLink无法跳转的问题

问题:SwiftUI内部手势导致外层NavigationLink无法触发

代码文件:LycéesRow.swift

import SwiftUI

struct LycéesRow: View {
    var lycée: Lycée
    
    @State private var customOpacity = 1.0
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            let firstImage = lycée.image
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 365, height: 280)
                .clipped()
                .cornerRadius(15)
                .offset(y: -35)
            
            firstImage
            
            RoundedRectangle(cornerRadius: 15)
                .frame(width: 365, height: 280)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 15))
                .offset(y: -35)
                .onTapGesture {
                    customOpacity = 0.0
                }


            let secondImage = lycée.image
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 355, height: 200)
                .clipped()
                .cornerRadius(15)
                .offset(x: 5)
                .offset(y: 39.8)
                .onTapGesture {
                    customOpacity = 0.0
                }
                .opacity(customOpacity)

            secondImage

            VStack(alignment: .leading, spacing: 1) {
                Text(lycée.département + ", France")
                    .font(.system(size: 15, weight: .medium, design: .default))
                    .foregroundColor(.white)
                    .opacity(0.5)
                
                Text(lycée.nom)
                    .font(.system(size: 25, weight: .bold, design: .serif))
                    .foregroundColor(.white)
                
                Text(lycée.ville)
                    .font(.system(size: 14, weight: .medium, design: .default))
                    .foregroundColor(.white)
                    .opacity(0.9)
            }
            .offset(y: -30)
            .offset(x: 12)
        }
    }
    
    
    struct LycéesRow_Previews: PreviewProvider {
        static var previews: some View {
            Group {
                LycéesRow(lycée: lycées[0])
                LycéesRow(lycée: lycées[1])
            }
        }
    }
}

代码文件:LycéesListe.swift

import SwiftUI

struct LycéesListe: View {
var body: some View {
    NavigationView {
            ScrollView {
                LazyVStack(spacing: 20) {
                    ForEach(lycées) { lycée in
                        NavigationLink {
                            LycéeDétail(lycée: lycée)
                        } label: {
                            LycéesRow(lycée: lycée)
                        }
                    }
                }    .navigationTitle("Lycées")
                    .accentColor(Color.clear)
                    .offset(y: 50)
            }
        }
    }
}


struct LycéesListe_Previews: PreviewProvider {
        static var previews: some View {
            LycéesListe() }
}

问题描述

点击LycéesRow中的矩形或图片时,onTapGesture能正常将customOpacity设为0.0以降低透明度,但无法触发外层NavigationLink跳转到LycéeDétail视图。


解决方案

原因分析

SwiftUI中,子视图的onTapGesture默认会拦截并消耗点击事件,导致父视图(这里是NavigationLink的label区域)无法接收到点击信号,因此跳转逻辑不会触发。

解决方法1:使用同时手势(Simultaneous Gesture)

将子视图中的onTapGesture替换为simultaneousGesture,这样既执行自身的透明度修改逻辑,也允许点击事件传递到父视图触发NavigationLink的跳转。

修改后的LycéesRow关键代码如下:

// 修改RoundedRectangle的手势
RoundedRectangle(cornerRadius: 15)
    .frame(width: 365, height: 280)
    .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 15))
    .offset(y: -35)
    .simultaneousGesture(TapGesture().onEnded {
        customOpacity = 0.0
    })

// 修改secondImage的手势
let secondImage = lycée.image
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 355, height: 200)
    .clipped()
    .cornerRadius(15)
    .offset(x: 5)
    .offset(y: 39.8)
    .simultaneousGesture(TapGesture().onEnded {
        customOpacity = 0.0
    })
    .opacity(customOpacity)

完整修改后的LycéesRow代码

import SwiftUI

struct LycéesRow: View {
    var lycée: Lycée
    
    @State private var customOpacity = 1.0
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            let firstImage = lycée.image
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 365, height: 280)
                .clipped()
                .cornerRadius(15)
                .offset(y: -35)
            
            firstImage
            
            RoundedRectangle(cornerRadius: 15)
                .frame(width: 365, height: 280)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 15))
                .offset(y: -35)
                .simultaneousGesture(TapGesture().onEnded {
                    customOpacity = 0.0
                })

            let secondImage = lycée.image
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 355, height: 200)
                .clipped()
                .cornerRadius(15)
                .offset(x: 5)
                .offset(y: 39.8)
                .simultaneousGesture(TapGesture().onEnded {
                    customOpacity = 0.0
                })
                .opacity(customOpacity)

            secondImage

            VStack(alignment: .leading, spacing: 1) {
                Text(lycée.département + ", France")
                    .font(.system(size: 15, weight: .medium, design: .default))
                    .foregroundColor(.white)
                    .opacity(0.5)
                
                Text(lycée.nom)
                    .font(.system(size: 25, weight: .bold, design: .serif))
                    .foregroundColor(.white)
                
                Text(lycée.ville)
                    .font(.system(size: 14, weight: .medium, design: .default))
                    .foregroundColor(.white)
                    .opacity(0.9)
            }
            .offset(y: -30)
            .offset(x: 12)
        }
    }
    
    
    struct LycéesRow_Previews: PreviewProvider {
        static var previews: some View {
            Group {
                LycéesRow(lycée: lycées[0])
                LycéesRow(lycée: lycées[1])
            }
        }
    }
}

解决方法2:手动控制NavigationLink跳转

如果需要更灵活的控制(比如添加跳转前确认逻辑),可以给NavigationLink绑定isActive状态,然后在子视图的手势中手动触发跳转:

  1. 修改LycéesListe添加状态变量与回调:
struct LycéesListe: View {
    @State private var selectedLycée: Lycée?
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVStack(spacing: 20) {
                    ForEach(lycées) { lycée in
                        NavigationLink(
                            destination: LycéeDétail(lycée: lycée),
                            tag: lycée,
                            selection: $selectedLycée
                        ) {
                            LycéesRow(lycée: lycée) {
                                selectedLycée = lycée
                            }
                        }
                    }
                }
                .navigationTitle("Lycées")
                .accentColor(Color.clear)
                .offset(y: 50)
            }
        }
    }
}
  1. 修改LycéesRow添加回调闭包:
struct LycéesRow: View {
    var lycée: Lycée
    var onTap: () -> Void
    
    @State private var customOpacity = 1.0
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            // ... 原有视图代码 ...
            
            RoundedRectangle(cornerRadius: 15)
                .frame(width: 365, height: 280)
                .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 15))
                .offset(y: -35)
                .onTapGesture {
                    customOpacity = 0.0
                    onTap()
                }
            
            let secondImage = lycée.image
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 355, height: 200)
                .clipped()
                .cornerRadius(15)
                .offset(x: 5)
                .offset(y: 39.8)
                .onTapGesture {
                    customOpacity = 0.0
                    onTap()
                }
                .opacity(customOpacity)
            
            // ... 原有视图代码 ...
        }
    }
}

内容的提问来源于stack exchange,提问作者kwiky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 02:53:11