SwiftUI:禁用具有自定义 ButtonStyle 的 NavigationLink 的最佳方法

Posted

技术标签:

【中文标题】SwiftUI:禁用具有自定义 ButtonStyle 的 NavigationLink 的最佳方法【英文标题】:SwiftUI: Optimal way to disable NavigationLink which has a custom ButtonStyle 【发布时间】:2020-11-14 18:39:49 【问题描述】:

我有一个具有自定义 ButtonStyle 的导航链接:

NavigationLink(destination: NextScreen()) 
   Text("Next")

.buttonStyle(CustomButtonStyle(disabled: !isValidPassword))

我的 CustomButtonStyle 看起来像这样:

@State var disabled = false
    func makeBody(configuration: Self.Configuration) -> some View 
        configuration.label
            .frame(minWidth: 0, maxWidth: .infinity)
            .padding(15)
            .foregroundColor(.white)
            .background(disabled ? .black : .gray)
            .cornerRadius(40)
            .disabled(disabled) // this has no effect when inside a NavigationLink
    

用户输入密码时,用户界面会正确更新。 您可以看到我禁用了 ButtonStyle 内的按钮,但这并不妨碍用户仍然点击 NavigationLink 以转到 NextScreen()。 为了解决这个问题,我最终这样做了:

NavigationLink(destination: SignupStepBirthdayView()) 
    Text("Next")

.buttonStyle(BobbleUpButtonStyle(disabled: !isValidPassword))
.disabled(!isValidPassword)

这似乎效率低下,因为我将禁用状态传递给按钮样式以更新 UI,然后不得不禁用实际的 NavigationLink。 有没有更好的方法来做到这一点?

【问题讨论】:

ButtonStyle 是关于按钮的视觉呈现(在这种情况下是链接),而不是关于行为。通过自定义样式,您禁用了 NavigationLink 内的文本标签,而不是链接本身 - 它应该在外部禁用,就像您已经做的那样。 【参考方案1】:

我将向您展示简单的方法,无需使用@Bingding 或@State

    首先,创建您的按钮样式:

    struct CustomButtonStyle: ButtonStyle 
    
        public func makeBody(configuration: ButtonStyle.Configuration) -> some View 
            MyButton(configuration: configuration) 
        
    
        struct MyButton: View 
    
            let configuration: ButtonStyle.Configuration
    
            @Environment(\.isEnabled) private var isEnabled: Bool
    
            var body: some View 
                configuration.label
                    .frame(minWidth: 0, maxWidth: .infinity)
                    .padding(15)
                    .foregroundColor(.white)
                    .background(isEnabled ? Color.blue : Color.gray)
                    .cornerRadius(40)
                    .disabled(!isEnabled)
                
        
    
    

    然后,将其作为任何 SwiftUI 组件禁用:

    struct ContentView: View 
    
        @State var text: String = ""
    
        var body: some View 
            NavigationView 
                VStack 
                    TextField("Enter your text", text: $text)
                    NavigationLink(destination: NextScreen()) 
                       Text("Next")
                    
                    .buttonStyle(CustomButtonStyle())
                    .disabled(text.isEmpty)
                
            
        
    
    

【讨论】:

【参考方案2】:

您必须在 CustomButtonStyle 中使用 Binding 而不是 State

@Binding var disabled : Bool

这会在您的 ContentView 中发生变化

@State var isValidPassword: Bool = true

还有:

.buttonStyle(BobbleUpButtonStyle(disabled: $isValidPassword))

【讨论】:

以上是关于SwiftUI:禁用具有自定义 ButtonStyle 的 NavigationLink 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

当视图出现在 SwiftUI 中时禁用动画

SwiftUI:自定义按钮无法识别具有清晰背景和 buttonStyle 的触摸

具有最大值的 SwiftUI 自定义滑块

具有自定义数据结构的 SwiftUI 列表,每个循环都嵌套 [关闭]

在 iPad 上具有自定义大小的 SwiftUI sheet() 模态

SwiftUI-使用drawingGroup()禁用TextField