SwiftUI按钮在iOS 18中无法点击的问题
 SwiftUI按钮在iOS 18中无法点击的问题

 SwiftUI按钮在iOS 18中无法点击的问题

2025年7月2日,有用户反馈“存钱猪猪”的“存入/取出”按钮,经常无法点击。当时,我以为是个别机型的问题。

因为“存入/取出”按钮和其他按钮一样,都是SwiftUI的Button按钮,不应该存在只有个别按钮无法点击的情况。只可能全部按钮都无法点击。

最近一位朋友也告诉我关于存钱猪猪的按钮无法点击的问题,昨天,一位用户来信反馈按钮无法点击,这让我意识到这个问题确实存在并且很严重。

因为文章内容过长,先谈结论:onTapGesture与NavigationStack存在冲突,存在随机无法点击的问题。

目前只能移除NavigationStack的onTapGesture修饰符,恢复可点击的状态,给NavigationStack的具体视图组件添加onTapGesture修饰符,才能解决这一问题。

分析问题

我联系我的朋友,让它告诉我它的手机型号和系统版本:

它的手机型号为iPhone 16,系统版本号为18.6.2。

我的手机型号为iPhone 13 mini,系统版本号为 17.6.1。

因此,我推测按钮无法点击的问题跟iOS 18系统版本有关,因为该问题的首次反馈在2025年7月2日,2025年上半年没有反馈这一问题。

我尝试在网络上搜索发现一些iOS18中按钮无法点击的文章《🚨 SwiftUI Buttons Not Working in iOS 18? Here’s What We Need to Know (And How to Fix It)》、《SwiftUI List elements not registering onTapGesture after ios 18 upgrade?》和《Anyone Else Finding Inability to Click Web Buttons in Safari in iOS 18?》。

这些文章内容都指向iOS18导致按钮无法点击的问题。

定位问题

因为我在iPhone 13 mini上,点击按钮无法在并未复现这一问题。

我尝试在Xcode模拟器上,对比iOS17和iOS18两个模拟器,来定位问题是否出现在iOS18版本上。

在iOS17设备中,所有按钮正常点击。

1、iOS18第一次测试应用按钮

在iOS18设备中,无法点击设置按钮和底部的“存入/取出”按钮。

我开始随机点击视图按钮,我发现当我打开“活动”-“人生存钱罐”视图时,Xcode输出:

Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).

关闭“活动”-“人生存钱罐”视图后,存入/取出”按钮和设置按钮恢复可点击的状态。

2、Xcode输出分析

根据查询了解到Xcode错误输出,是SwiftUI / UIKit内部的layout报错。

“negative or non-finite” 说明有某个 View 的 frame 计算出来是负数或者 NaN(不是数字)。

这种情况经常出现在 .frame(width: someBindingValue) 里,someBindingValue 可能是 0、负数或者 Double.nan。

一旦布局异常,SwiftUI 的命中区域(hit test)可能就出错,按钮虽然显示正常,但点不到。

结合前面的按钮无法点击问题,在打开“活动”视图后,按钮恢复可点击的状态。

 推测机制:当SwiftUI界面有布局出错(Invalid frame dimension),时,渲染系统会生成一个不可交互的透明层,挡住底下按钮。

当打开“活动”-“人生存钱罐”视图后,SwiftUI重新布局视图树,把之前出错的布局刷新掉,透明层消失,按钮恢复可点击状态。

这只是一个推测,还需要重新复现这一问题。

3、iOS18第二次测试应用按钮

当我卸载应用,重新安装存钱猪猪。发现这次无法点击的按钮是图片中的“统计”按钮和“存入/取出”按钮。

第一次测试时的设置按钮可以正常点击。

这就意味着在iOS18中,按钮存在随机不可点击的情况。

当我重新打开“活动”-“人生存钱罐”视图后,“统计”按钮和“存入/取出”按钮仍然无法点击。

我在尝试点击各种视图,发现当我打开“管理”-“创建存钱罐”视图时,返回主界面,“存入/取出”按钮恢复可点击的状态,“统计”按钮仍然无法点击。

我重新打开“管理”-“创建存钱罐”视图,返回主界面。发现“历史记录”和“设置”按钮无法点击。

再次打开“管理”-“创建存钱罐”视图,返回主界面。发现除了左上角和进度按钮外,其他按钮都无法点击。

这就说明,每次打开“管理”-“创建存钱罐”视图,都会影响主视图的按钮点击区域。

4、重新定位iOS和程序问题

这时,我开始怀疑是我的程序存在问题,而不是iOS版本问题。

重新运行iOS 17,按钮一切正常。

打开“管理”-“创建存钱罐”视图,进入主视图,按钮一切正常。

打开“活动‘-“人生存钱罐”,Xcode输出:

Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).
Invalid frame dimension (negative or non-finite).

因此,这里的“negative or non-finite”报错实际上并不会影响按钮。

多次重复以上步骤,以及随机点击按钮,在iOS17模拟器中,按钮正常使用,不存在无法点击的情况。

因此,断定按钮问题与iOS18系统版本有关,与应用本身无法。

5、iOS18第三次测试应用按钮

重新运行存钱猪猪。这次只有左上角的按钮和小猪可以点击,其他按钮都无法点击。

打开“活动‘-“人生存钱罐”,Xcode输出 Invalid frame dimension 报错提示,按钮仍然是无法点击状态。

可以排除第一次的定论,“活动”-“人生存钱罐”视图对按钮的没有影响。

打开“管理”-“创建存钱罐”视图,进入主视图,动画以及顶部进度按钮无法点击,其他按钮恢复可点击状态。

得出的结论:

1、在iOS18中,每次打开应用,主界面的个别按钮都会存在无法点击的情况,打开/关闭“管理”-创建存钱罐视图,按钮会随机出现不可点击的情况,最终会导致所有按钮不可点击。iOS17中不会出现。

2、左上角的按钮始终可以点击,右上角按钮存在无法点击的情况,我对比发现右上角按钮没有使用Menu包裹,当我使用Menu包裹并重新测试,发现当大部分按钮无法点击时,左上角和右上角由Menu包裹的按钮仍然可以点击。说明问题和Button的hit-testing行为有关,Menu 的实现走的是另一套 UIKit / SwiftUI 交互管线。

3、打开“管理”-“创建存钱罐”视图为fullScreenCover类型,但是当我打开其他fullScreenCover类型视图时,按钮不会出现随机不可点击的情况,因此,bug 的根源不是 fullScreenCover 本身,而是这个特定视图里某个布局/状态,引发了 iOS 18 SwiftUI hit-testing 的 bug。

排查问题

1、使用Debug View Hierarchy验证

以底部的“存入/取出”按钮为例,按钮上方并没有透明的View存在遮挡。

2、对比法

创建一个相同的视图,检查可能影响视图的原因。

经过对比发现,当按钮设置不设置opacity时,可以点击,其他按钮设置opacity后,不可点击。

但是在后续复现验证时,发现无法复现。

并且,即使按钮为最简单的样式,也存在不可点击的状态。

Button(action: {
    // 打开存取视图
    print("点击了存入/取出按钮2")
    showDepositAndWithdrawView.toggle()
}, label: {
    Text("Deposit/withdraw")
})

因此,推断并非是按钮的点击行为导致的问题。

3、排除法

将一个简单的按钮从外层使用ZStack嵌套,一直到无法点击的层级。

在测试中发现,当放在NavigationStack和GeometryReader中,按钮出现无法点击的情况。

NavigationStack {
    GeometryReader { geometry in
        // 通过 `geometry` 获取布局信息
        let width = geometry.size.width * 0.85
        let height = geometry.size.height
        ZStack {
            Button {}   // 测试按钮,此时存在无法点击的情况
            VStack {}   // 原本内容
        }
    }
}

隐藏NavigationStack,发现按钮均可点击;隐藏GeometryReader,按钮仍然存在无法点击的情况。

该判断推测问题在NavigationStack和iOS18存在某种冲突,导致点击失效。

4、最小化NavigationStack

使用最小化NavigationStack显示内容,NavigationLink正常点击。

NavigationStack {
    List {
        NavigationLink("去详情页 1") {
            DetailViews(text: "这是详情页 1")
        }
        
        NavigationLink("去详情页 2") {
            DetailViews(text: "这是详情页 2")
        }
    }
    .navigationTitle("首页")
}

新增NavigationStack修饰符:

NavigationStack {}
    .onAppear {}
    .onDisappear {}
    .onTapGesture {}
    ..onChange {}

新增修饰符后,测试发现,无法点击NavigationLink并实现跳转。

尝试将一个NavigationLink封装到Menu视图中,发现可以点击封装Menu视图的NavigationLink。

NavigationStack {
    List {
        NavigationLink("去详情页 1") {
            DetailViews(text: "这是详情页 1")
        }
        
        Menu("去详情页 2") {
            NavigationLink("去详情页 2") {
                DetailViews(text: "这是详情页 2")
            }
        }
    }
    .navigationTitle("首页")
}

推测,问题可能与NavigationStack和某个修饰符存在冲突,导致无法点击问题,而Menu的点击规则影响了这一冲突,让其可点击。

5、排除法

经过排除法发现当onTapGesture代码运行时,就存在无法点击NavigationLink的情况,如果不运行onTapGesture代码,NavigationLink正常点击。

.onTapGesture {
    if appStorage.isSilentMode {
        resetSilentMode()
    }
}

添加输出语句测试:

.onTapGesture {
    print("点击了一下屏幕")
    print("当前是否为静默模式:\(appStorage.isSilentMode)")
    if appStorage.isSilentMode {
        print("调用resetSilentMode方法")
        resetSilentMode()
    }
}

当点击屏幕时,输出:

点击了一下屏幕
当前是否为静默模式:false

没有进入方法,但是NavigationLink无法点击。

这里,我判断问题为NavigationStack与onTagGesture存在冲突导致的问题。

我使用VStack替代NavigationStack,按钮可以正常点击。

6、恢复原代码,将最小化改为原始的代码

恢复原始代码后,仍然存在无法点击的问题。

当隐藏onTapGesture代码后,视图按钮可以点击,问题基本判断为onTapGesture与NavigationStack存在冲突。

总结

我根据《🚨 SwiftUI Buttons Not Working in iOS 18? Here’s What We Need to Know (And How to Fix It)》文章内容,尝试使用contentShape和highPriorityGesture修饰符,并未真正的解决这一问题。

目前只能移除NavigationStack的onTapGesture修饰符,将onTapGesture修饰符添加到具体的视图组件,才能解决这一问题。

最近因为iOS26的发布,有“存钱猪猪”的用户反馈iOS 26中,按钮无法点击的问题已经得到解决,总的来看,这个问题确实是iOS 18上的特殊BUG。

参考文章

1、🚨 SwiftUI Buttons Not Working in iOS 18? Here’s What We Need to Know (And How to Fix It)

https://medium.com/@gauravkumarjaipur/swiftui-buttons-not-working-in-ios-18-heres-what-we-need-to-know-and-how-to-fix-it-3e5b2ea9357b

2、SwiftUI List onTapGesture Not Working After iOS 18 Update: Solutions and Fixes:https://iostutorialjunction.com/2024/12/swiftui-list-ontapgesture-not-working-after-ios-18-update-solutions-and-fixes.html

3、SwiftUI List elements not registering onTapGesture after ios 18 upgrade?

https://stackoverflow.com/questions/79004931/swiftui-list-elements-not-registering-ontapgesture-after-ios-18-upgrade

4、Anyone Else Finding Inability to Click Web Buttons in Safari in iOS 18? https://www.reddit.com/r/ios/comments/1fj1ktx/anyone_else_finding_inability_to_click_web/

5、Xcode调试工具Debug View Hierarchy

https://fangjunyu.com/2025/09/11/xcode%e8%b0%83%e8%af%95%e5%b7%a5%e5%85%b7debug-view-hierarchy/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注