簡體   English   中英

SwiftUI ButtonStyle - 如何檢查按鈕是否被禁用或啟用?

[英]SwiftUI ButtonStyle - how to check if button is disabled or enabled?

要在 SwiftUI 中設置按鈕樣式,根據我的理解,您需要擴展ButtonStyle並實現func makeBody(configuration: Self.Configuration) -> some View ,您可以在其中開始對configuration.label應用修改,該func makeBody(configuration: Self.Configuration) -> some View是對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)
            )
    }

但是沒有isEnabled字段。

Apple 提供的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 {
.....

有沒有辦法訪問這些信息?

編輯:

在您建議關閉此問題之前,請閱讀以下內容:

前段時間也有人問過類似的問題。 該問題沒有具體說明任何上下文。

這里我有一個特定的上下文:創建一個通用的可重用按鈕樣式。

那里提供的答案是不夠的。 我不能指望人們將禁用狀態傳遞給樣式構造函數。 這是太多的重復工作。

你能想象人們是否必須這樣寫代碼:

Button() { .... }.disabled(someExprssion).buttonStyle(MyCustomStyle(disabled: someExpression))

顯然這是不可取的。

同樣很明顯,Apple 提供的樣式可以訪問信息,而無需人們再次將禁用狀態傳遞給樣式。

如果你關閉這個問題,你將永遠阻止任何人在 StackOverflow 上為這個問題提供有用的答案。

在您提議關閉之前,請重新考慮。

編輯2:

我有一個猜測,如果您可以獲得Button視圖的EnvironmentValues.isEnabled那么它可能是正確的值。

因此,另一種提問方式是:是否有可能在 SwiftUI 中獲得您沒有定義自己的視圖的環境?

感謝這個博客,我找到了答案: https : //swiftui-lab.com/custom-styling/

您可以通過創建包裝視圖並在樣式結構中使用它來從環境中獲取啟用狀態:

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)
        }
    }
}

此示例演示如何獲取狀態並使用它來更改按鈕的外觀。 如果按鈕被禁用,它會將按鈕文本顏色更改為紅色,如果啟用則將其更改為綠色。

對@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))

另一種選擇是將disabled布爾值傳遞給您的ButtonStyle ,然后使用標簽上的allowsHitTesting修飾符來有效禁用按鈕:

struct MyButtonStyle: ButtonStyle {
    let disabled: Bool

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

您可以直接在 ButtonStyle 中通過環境訪問啟用的值,例如:

struct MyButtonStyle: ButtonStyle {
    @Environment(\.isEnabled) var isEnabled
    
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .background(!isEnabled ? Color.black : (configuration.isPressed ? Color.red : Color.blue))
            
    }
    
}

您可以將禁用狀態合並到 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())
    }}

  }

回答您的問題:是的,有可能獲得您自己沒有通過的Environment值。 SwiftUI大量使用Environment並且很多View依賴於它,而您甚至SwiftUI知道它。

ButtonStyle也可以訪問Environment因此您可以輕松實現您想要的:

struct SomeButtonStyle: ButtonStyle {
    @Environment(\.isEnabled)
    private var isEnabled: Bool

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .disabled(!self.isEnabled)
            .opacity(self.isEnabled ? 1 : 0.5)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM