用自定义按钮替换 SwiftUI 按钮

Pie*_*ith 2 swiftui

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

换句话说,如果我这样做

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)
        })
    }
    
    
}
Run Code Online (Sandbox Code Playgroud)

它将闭包限制为仅允许标签返回 text()

如何才能做到这一点

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

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

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

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

尽管他们有着相同的结果,但他们并没有实现相同的目标。我的解决方案将提供一个动态样式的组件,可以在整个项目中使用。无需尾随.buttonStyle(BlueButtonStyle())

use*_*ser 6

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


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() } }
    
}
Run Code Online (Sandbox Code Playgroud)

用例:

    Button(action: { print("hello") }, label: { Text("Button") })
Run Code Online (Sandbox Code Playgroud)
    Button(action: { print("hello") }, title: "Button")
Run Code Online (Sandbox Code Playgroud)


Pie*_*ith 5

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"))
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Button(type: .outlined, action: { print("pressed") }, title: "Button")
Run Code Online (Sandbox Code Playgroud)

或者

Button(action: { print("pressed") }, title: "Button")
Run Code Online (Sandbox Code Playgroud)

或者

Button(action: addItem, label: {
    Label("Add Item", systemImage: "plus")
})
Run Code Online (Sandbox Code Playgroud)