SwiftUI点击按钮第11次时如何禁止NavigationView弹出贴纸选择页
问题根因
两个基础写法错误导致弹窗异常弹出:
- 计数阈值写错:你设置
counter < 11时显示添加按钮,第10次点击按钮时,代码会先执行isAddingSticker = true触发弹窗,之后才把counter加到11切换到奖励视图,等奖励视图加载出来的时候弹窗已经弹出来盖在上面了。 - 弹窗挂载位置错误:你把
.sheet写在了ForEach循环的内部元素上,相当于给每一张已添加的贴纸都绑定了一个弹窗实例,很容易出现状态联动误触发。
修复方案
按下面三步改就能解决问题:
- 把添加按钮的判断阈值从
counter < 11改成counter < 10,在按钮点击逻辑里提前拦截临界状态:当counter已经到9的时候,第10次点击只累加计数、不触发弹窗,直接切到奖励展示状态。 - 把
.sheet修饰符从ForEach循环内部剪出来,挪到NavigationView的外层,保证全局只有一个弹窗实例,避免多实例状态冲突。 - 给奖励按钮的重置逻辑加3秒延迟(和你写的奖励动画时长一致),等奖励动画播完再清空贴纸、重置计数,符合你要的“先展示奖励再清空”的需求。
修正后的核心代码
按钮逻辑部分
if counter < 10 { Button { // 临界值拦截:第10次点击时不触发弹窗,直接切奖励状态 guard counter < 9 else { counter += 1 return } isAddingSticker = true print("button pressed: \(counter)") counter += 1 } label: { RoundedRectangle(cornerRadius: 10) .foregroundColor(Color(red: 55/255, green: 255/255, blue: 213/255)) .frame(width: 300, height: 40, alignment: .center) .overlay( Text(" ステッカーをはろう!") .foregroundColor(Color(red: 41/255, green: 52/255, blue: 98/255)) .font(.title2)) } } else { Button{ // 等3秒奖励动画播放完成后再重置状态 DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { isAddingSticker = false counter = 0 stickers.removeAll() } } label: { Image("WellDone") .resizable() .frame(width: self.screenWidth*0.5, height: self.screenWidth*0.5) .scaleEffect(2.0) .rotationEffect(Angle(degrees: 360)) .animation(.easeInOut(duration: 3.0), value: counter) } }
注:你原来写的绿色通道值266/255超出了RGB 0-255的取值范围,这里直接改成了255,要是需要调整绿色深浅自己改对应数值就行。
弹窗位置调整
把原来写在ForEach内VStack后面的.sheet代码整块删除,移到NavigationView的外层:
NavigationView { // 原有ZStack、贴纸展示、按钮逻辑保持不变,只移除内部的.sheet } // 全局只保留这一个弹窗实例 .sheet(isPresented: $isAddingSticker, onDismiss: addSticker) { StampView(sticker: $selectedSticker) }
内容的提问来源于stack exchange,提问作者Yua
相关产品推荐
相关产品推荐

