SwiftUI ButtonStyle-如何检查按钮是否已禁用?

时间:2019-12-04 05:24:50

标签: ios swift swiftui

根据我的理解,要在SwiftUI中设置按钮的样式,请扩展ButtonStyle并实现func makeBody(configuration: Self.Configuration) -> some View,在其中开始对configuration.label进行修改,该修改是对{{ 1}}视图。

现在,除了Button字段之外,label还有一个ButtonStyle.Configuration的布尔字段,但这似乎就是全部。

如何检查按钮是启用还是禁用?

例如,我想在按钮周围绘制边框,如果按钮启用,我希望边框为蓝色,如果按钮禁用,我希望边框为灰色。

我的第一个猜测是这样的:

isPressed

但是没有 func makeBody(configuration: Self.Configuration) -> some View { configuration.label .overlay( RoundedRectangle(cornerRadius: 4).stroke(configuration.isEnabled ? Color.blue : Color.gray, lineWidth: 1).padding(8) ) } 字段。

Apple提供的isEnabled显然可以访问此信息,因为声明它的头文件中的doc注释说:“样式可以应用视觉效果来指示按下,聚焦或启用的状态。按钮。”

PlainButtonStyle

是否可以访问此信息?

编辑:

在您建议关闭此问题之前,请先阅读以下内容:

前段时间有一个类似的问题。该问题未指定任何上下文。

在这里,我有一个特定的上下文:创建通用的可重用按钮样式。

那里提供的答案是不够的。我不能指望人们将禁用状态传递给样式构造函数。这太过重复了。

您能想象人们是否必须以这种方式编写代码吗?

/// A `Button` style that does not style or decorate its content while idle. /// /// The style may apply a visual effect to indicate the pressed, focused, /// or enabled state of the button. @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) public struct PlainButtonStyle : PrimitiveButtonStyle { .....

显然这是不可取的。

显然,苹果提供的样式可以访问信息,而无需人们再次将禁用状态传递给样式。

如果您关闭问题,将永远阻止任何人在StackOverflow上对该问题提供有用的答案。

在建议关闭之前,请重新考虑。

EDIT2:

我猜测,如果您可以获取Button() { .... }.disabled(someExprssion).buttonStyle(MyCustomStyle(disabled: someExpression))视图的EnvironmentValues.isEnabled,那么它可能是正确的值。

另一个提出问题的方法是:在SwiftUI中是否有可能获得您未定义自己的视图的环境?

4 个答案:

答案 0 :(得分:5)

对@hasen 的回答进行了一些调整,以使事情更易于配置

struct MyButtonStyle: ButtonStyle {
    var foreground = Color.white
    var background = Color.blue
    
    func makeBody(configuration: ButtonStyle.Configuration) -> some View {
        MyButton(foreground: foreground, background: background, configuration: configuration)
    }

    struct MyButton: View {
        var foreground:Color
        var background:Color
        let configuration: ButtonStyle.Configuration
        @Environment(\.isEnabled) private var isEnabled: Bool
        var body: some View {
            configuration.label
                .padding(EdgeInsets(top: 7.0, leading: 7.0, bottom: 7.0, trailing: 7.0))
                .frame(maxWidth: .infinity)
                .foregroundColor(isEnabled ? foreground : foreground.opacity(0.5))
                .background(isEnabled ? background : background.opacity(0.5))
                .opacity(configuration.isPressed ? 0.8 : 1.0)
        }
    }
}

用法

       Button(action: {}) {
            Text("Hello")
        }.buttonStyle(MyButtonStyle(foreground: .white, background: .green))

答案 1 :(得分:1)

您可以将禁用状态合并到buttonStyle中,这样您就不会在应用程序中使用它两次。

  struct CustomizedButtonStyle : PrimitiveButtonStyle {

var disabled: Bool = false

func makeBody(configuration: Self.Configuration) -> some View {
configuration.label.disabled(disabled)
    .overlay(
        RoundedRectangle(cornerRadius: 4).stroke(disabled ? Color.blue :  Color.gray, lineWidth: 1).padding(8)
    )
}
}


 struct ButtonUpdate: View {
 var body: some View {
    VStack{
    Button(action: {
    }) { Text("button")
    }.buttonStyle(CustomizedButtonStyle(disabled: true))
    Button(action: {
    }) { Text("button")
    }.buttonStyle(CustomizedButtonStyle())
    }}

  }

答案 2 :(得分:1)

我通过以下博客找到了答案:https://swiftui-lab.com/custom-styling/

您可以通过创建包装器视图并在样式struct中使用它来从环境中获取启用状态:

struct MyButtonStyle: ButtonStyle {
    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.foregroundColor(isEnabled ? Color.green : Color.red)
        }
    }
}

此示例演示如何获取状态并使用其更改按钮的外观。如果按钮被禁用,它将按钮文本颜色更改为红色,如果启用则将其更改为绿色。

答案 3 :(得分:0)

另一种选择是将disabled布尔值传递给ButtonStyle,然后在标签上使用allowsHitTesting修饰符以有效地禁用按钮:

struct MyButtonStyle: ButtonStyle {
    let disabled: Bool

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration
            .label
            .allowsHitTesting(!disabled)
    }
}