用自定义按钮替换 SwiftUI 按钮

时间:2021-04-08 21:44:56

标签: swiftui

我想扩展 SwiftUI.Button 以便我可以添加一个类型道具并将该类型更改为不同类型的主题按钮。但我是 Swift 的新手,我不知道如何让我的标签和动作道具通用。

换句话说,如果我这样做

/api/image

它限制闭包只允许标签返回 text()

如何做到这一点

还有关于我应该如何根据类型更改对按钮所做的“更改”的任何建议。

注意: 有人对此表示反对,因为它类似于来自另一个用户的 button style 查询,但事实并非如此。

该解决方案只是将预制样式添加到默认的 SwiftUI.button 结构中,这不是我的目标。

我正在尝试使用可以传递的类型属性扩展 SwiftUI.Button,并将根据该输入设置样式。

虽然他们分享相同的结果,但他们并没有完成相同的目标。我的解决方案将提供可在整个项目中使用的动态样式组件。无需尾随 import SwiftUI struct Button: View { var type: String = "" var action = {} var label = { Text("Button") } var body: some View { ZStack(content: { SwiftUI.Button(action: action, label: label) }) } }

2 个答案:

答案 0 :(得分:0)

正如我所看到的,您正在尝试重新创建苹果按钮,您可以这样做,然后在正文中进行自定义:


struct Button<Content: View>: View {
    
    let action: () -> Void
    let label: () -> Content
    
    init(action: @escaping () -> Void, @ViewBuilder label: @escaping () -> Content) {
        self.action = action
        self.label = label
    }
    
    init(action: @escaping () -> Void, title: String) where Content == Text {
        
        self.init(action: action, label: { Text(title) })
    }

    var body: some View { label().onTapGesture { action() } }
    
}

用例:

    Button(action: { print("hello") }, label: { Text("Button") })

    Button(action: { print("hello") }, title: "Button")

答案 1 :(得分:0)

swiftPunk 的结论如下。

struct Button<Content: View>: View {
    let type: button_styles
    let action: () -> Void
    let label: () -> Content
    
    enum button_styles {
        case filled
        case outlined
        case plain
    }
    
    
    init(type: button_styles, action: @escaping () -> Void, @ViewBuilder label: @escaping () -> Content ) {
        self.type = type
        self.action = action
        self.label = label
    }
    
    init(type: button_styles, action: @escaping () -> Void, title: String) where Content == Text {
        self.init(type: type, action: action, label: { Text(title) })
    }
    
    init(action: @escaping () -> Void, title: String) where Content == Text {
        self.init(type: .plain, action: action, label: { Text(title) })
    }
    init(action: @escaping () -> Void, @ViewBuilder label: @escaping () -> Content) {
        self.init(type: .plain, action: action, label: label)
    }
    
    var body: some View {
        switch type {
        case .filled:
            SwiftUI.Button(action: self.action, label: self.label).buttonStyle(FilledButtonStyle())
        case .outlined:
            SwiftUI.Button(action: self.action, label: self.label).buttonStyle(OutlinedButtonStyle())
        case .plain:
            SwiftUI.Button(action: self.action, label: self.label).buttonStyle(PlainButtonStyle())
        }
    }
    
}

struct FilledButtonStyle: ButtonStyle {
    
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .font(.headline)
            .frame(maxWidth: 108, maxHeight: 34, alignment: .center)
            .contentShape(Rectangle())
            .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white)
            .background(configuration.isPressed ? Color("Red").opacity(0.5) : Color("Red"))
            .cornerRadius(20)
            
    }
}
struct OutlinedButtonStyle: ButtonStyle {
    
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .font(.headline)
            .frame(maxWidth: 108, maxHeight: 34, alignment: .center)
            .foregroundColor(Color("Grey"))
            .background(Color.white.opacity(0))
            .overlay(RoundedRectangle(cornerRadius:10).stroke(Color("Grey"), lineWidth: 2))
    }
}

struct PlainButtonStyle: ButtonStyle {
    
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .font(.headline)
            .frame(maxWidth: 108, maxHeight: 34, alignment: .center)
            .contentShape(Rectangle())
            .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color("Grey"))
    }
}

这将允许您使用按钮结构,例如:

Button(type: .outlined, action: { print("pressed") }, title: "Button")

Button(action: { print("pressed") }, title: "Button")

Button(action: addItem, label: {
    Label("Add Item", systemImage: "plus")
})