簡體   English   中英

SwiftUI:在初始化程序中沒有標簽/字符串但具有 ButtonStyle 的按鈕

[英]SwiftUI: Button without Label/String in the initializer but with ButtonStyle

SwiftUI 有一些Button初始化器,但它們都需要一個Stringsome View作為參數以及action

但是,按鈕的外觀也可以在ButtonStyle的幫助下進行自定義,它可以添加自定義視圖。

讓我們考慮一個帶有以下圖標的復制按鈕:

SF 符號復制

我為按鈕制作的樣式如下所示:

struct CopyButtonStyle: ButtonStyle {

    init() {}

    func makeBody(configuration: Configuration) -> some View {
        let copyIconSize: CGFloat = 24
        return Image(systemName: "doc.on.doc")
            .renderingMode(.template)
            .resizable()
            .frame(width: copyIconSize, height: copyIconSize)
            .accessibilityIdentifier("copy_button")
            .opacity(configuration.isPressed ? 0.5 : 1)
    }
}

它工作得很好,但是,我必須在調用站點用一個空字符串初始化Button

Button("") {
    print("copy")
}
.buttonStyle(CopyButtonStyle())

那么,問題是如何擺脫按鈕初始化參數中的空字符串?

潛在解決方案

我能夠創建一個簡單的擴展來完成我需要的工作:

import SwiftUI

extension Button where Label == Text {
    init(_ action: @escaping () -> Void) {
        self.init("", action: action)
    }
}

調用站點:

Button() { // Note: no initializer parameter
    print("copy")
}
.buttonStyle(CopyButtonStyle())

但是很好奇,我是否錯誤地使用了Button結構並且已經有一個用例,這樣我就可以擺脫這個擴展。

比進行ButtonStyle配置更簡單的方法是直接傳入 label:

Button {
    print("copy")
} label: {
    Label("Copy", systemImage: "doc.on.doc")
        .labelStyle(.iconOnly)
}

這也帶來了一些好處:

  1. 默認情況下,按鈕為藍色,表示可以點擊
  2. 沒有對您當前擁有的圖像進行奇怪的拉伸
  3. 無需實現按下時不透明度如何變化

您還可以將其重構為自己的視圖:

struct CopyButton: View {
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Label("Copy", systemImage: "doc.on.doc")
                .labelStyle(.iconOnly)
        }
    }
}

像這樣調用:

CopyButton {
    print("copy")
}

整體看起來更干凈。

這是您嘗試做的正確方法,您不需要為每種按鈕創建一個新的 ButtonStyle,您可以只創建一個並將其重用於您想要的任何其他按鈕。 我還用.scaledToFit()解決了您的圖像拉伸問題。

struct CustomButtonView: View {
    
    let imageString: String
    let size: CGFloat
    let identifier: String
    let action: (() -> Void)?
    
    init(imageString: String, size: CGFloat = 24.0, identifier: String = String(), action: (() -> Void)? = nil) {
        self.imageString = imageString
        self.size = size
        self.identifier = identifier
        self.action = action
    }

    var body: some View {
        
        return Button(action: { action?() } , label: {
            
            Image(systemName: imageString)
               .renderingMode(.template)
               .resizable()
               .scaledToFit()
               .frame(width: size, height: size)
               .accessibilityIdentifier(identifier)
            
        })
        .buttonStyle(CustomButtonStyle())

    }
    
}

struct CustomButtonStyle: ButtonStyle {

    func makeBody(configuration: Configuration) -> some View {
        return configuration.label
            .opacity(configuration.isPressed ? 0.5 : 1.0)
            .scaleEffect(configuration.isPressed ? 0.95 : 1.0)
    }
}

用例:

struct ContentView: View {
    var body: some View {
        
        CustomButtonView(imageString: "doc.on.doc", identifier: "copy_button", action: { print("copy") })

    }
}

您可以將EmptyView用於 label,例如

    Button(action: { // Note: no initializer parameter
         print("copy")
    }, label: { EmptyView() })
    .buttonStyle(CopyButtonStyle())

但是從重用和代碼可讀性的角度來看,將其包裝在自定義按鈕類型中(如其他答案所示)更可取。

暫無
暫無

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

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