【问题标题】:Replacing SwiftUI Button with a custom Button用自定义按钮替换 SwiftUI 按钮
【发布时间】:2021-07-04 19:30:46
【问题描述】:

我想扩展 SwiftUI.Button 以便我可以添加一个类型道具并将该类型更改为不同类型的主题按钮。但我是 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)
        })
    }
    
    
}

它将闭包限制为只允许 label 返回 text()

如何做到这一点

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

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

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

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

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

【问题讨论】:

  • 如何扩展按钮?所有的事情都和以前一样,如果它还能正常工作的话!
  • 另外,听起来你在描述button style
  • 这能回答你的问题吗? swiftui-dynamic-action-closure-for-button
  • @swiftPunk 是的,一切都是一样的,因为我不确定如何扩展功能,因此问题...
  • @loremipsum 谢谢。这两者的结合可以解决我的问题非常感谢!

标签: swiftui


【解决方案1】:

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 结构,例如:

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

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

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

【讨论】:

    【解决方案2】:

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


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

    【讨论】:

    • 我的答案是Button主题的最底层!你不能比这更深! :)
    • 是的,我从自定义视图主题中看到了您的答案。我必须将此解决方案与 SwiftUI 列表解决方案中的自定义按钮混合使用。
    • 基本上用我的回答你用你自己的自定义按钮替换苹果按钮!多么酷啊!最好的部分就在这里!当你在这里或那里分享你的代码时,每个人都可以使用这个自定义按钮,因为我只是从真正的苹果按钮复制而来,所以你有自己的设计,而且你的代码对一些没有你的自定义按钮的人有用!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 2017-10-10
    相关资源
    最近更新 更多