在 SwiftUI 视图中禁用用户交互而不更改其外观

发布于 2025-01-09 01:51:12 字数 1493 浏览 1 评论 0原文

我有一个允许用户交互的自定义​​视图 InteractiveView。我想在概述页面(在 NavigationLink 内)上显示该视图的缩略图,以便用户可以点击它来导航到全屏视图。

因此,我需要 InteractiveView 在显示为缩略图时处于非交互式(即禁用)状态。我的实现如下:

NavigationLink {
    InteractiveView(viewModel)
} label: {
    InteractiveView(viewModel)
        .disabled(true)
}

这按预期工作(即点击视图不会与视图交互,而是执行导航到全屏交互式视图)。

但是,disabled(true) 修饰符还会更改 InteractiveView 的外观:其所有子视图都淡出,即它们的不透明度降低并且呈现半透明。我知道这通常是我想要的,因为它向用户发出信号,表明该视图已禁用并且我无法与其交互。但就我而言,用户可以与其交互,因为他们可以点击它以显示全屏视图。

问题:

  • 如何禁用InteractiveView,同时保持其原始外观(没有淡出效果)?

  • 或者:是否有更好的方法来禁用视图中的所有控件而不改变其外观?


更新(附加信息)

此问题的许多答案建议在上面的代码中使用 .allowsHitTesting(false) 而不是 .disabled(true) 进行命中测试。这确实在导航方面有效,但它违反了问题中指定的另一个要求:即“不改变其外观”部分。

为什么命中测试不起作用

NavigationLink 总是将其 label 视图的前景色更改为蓝色,从而修改 label 视图的外观。我通过在 NavigationLink 上使用 PlainButtonStyle 解决了这个问题:

NavigationLink {
    InteractiveView(viewModel)
} label: {
    InteractiveView(viewModel)
        .allowsHitTesting(false)
}
.buttonStyle(PlainButtonStyle()) // prevent change of foreground color

使用此按钮样式,当我添加 .allowsHitTesting(false) 时,导航链接会中断> 修饰符:导航链接的内容视图不再拦截触摸,但导航链接本身也不会接收(或处理)这些触摸。这就是问题所在:

我需要正确(正常)的导航链接行为,而不需要突出显示典型的导航链接。

I have a custom view InteractiveView that allows user interaction. I want to show a thumbnail of that view on an overview page (inside a NavigationLink) so the user can tap it to navigate to the the fullscreen view.

For that reason, I need the InteractiveView to be non-interactive (i.e. disabled) when it's displayed as a thumbnail. I implemented this as follows:

NavigationLink {
    InteractiveView(viewModel)
} label: {
    InteractiveView(viewModel)
        .disabled(true)
}

This works as intended (i.e. tapping the view does not interact with the view but performs the navigation to the fullscreen interactive view instead).

However, the disabled(true) modifier also changes the InteractiveView's appearance: All its subviews are faded out, i.e. their opacity is reduced and they appear semi-transparent. I understand that this is usually what I want as it signals to the user that the view is disabled and I cannot interact with it. But in my case, the user can interact with it as they can tap on it in order to show the fullscreen view.

Question:

  • How can I disable the InteractiveView while keeping its original appearance (without the fade-out effect)?

  • Or: Is there a better way to disable all controls in a view without changing their appearance?


Update (Additional Information)

Many answers to this question suggest using hit testing with .allowsHitTesting(false) instead of .disabled(true) in the code above. This works indeed in terms of navigation, but it violates another requirement specified in the question: namely, the "without changing its appearance" part.

Why hit testing doesn't work

A NavigationLink always changes the foreground color of its label view to blue, thus it modifies the label view's appearance. I solved this problem by using a PlainButtonStyle on the NavigationLink:

NavigationLink {
    InteractiveView(viewModel)
} label: {
    InteractiveView(viewModel)
        .allowsHitTesting(false)
}
.buttonStyle(PlainButtonStyle()) // prevent change of foreground color

With this button style, the navigation link breaks when I add the .allowsHitTesting(false) modifier: The navigation link's content view doesn't intercept touches anymore, but the navigation link itself also doesn't receive (or handle) those touches. And that's the problem:

I need the correct (normal) navigation link behavior without the typical navigation link highlighting.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撩心不撩汉 2025-01-16 01:51:12

看起来 allowsHitTesting 就是您可能想要的。

https://stackoverflow.com/a/58912816/1066424

Seems like allowsHitTesting is what you may be after.

https://stackoverflow.com/a/58912816/1066424

牛↙奶布丁 2025-01-16 01:51:12
        NavigationLink {
            InteractiveView()
        } label: {
            InteractiveView()
                .allowsHitTesting(false)
        }
        NavigationLink {
            InteractiveView()
        } label: {
            InteractiveView()
                .allowsHitTesting(false)
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文