SwiftUI中onTapGesture导致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状态,然后在子视图的手势中手动触发跳转:
- 修改
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) } } } }
- 修改
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
相关产品推荐
相关产品推荐

