【问题标题】:SwiftUI Button selectionSwiftUI 按钮选择
【发布时间】:2019-12-28 06:37:40
【问题描述】:

我正在尝试掌握 SwiftUI 概念(已完成 Apple 的 SwiftUI 教程),但在 UIKit 十年之后对我来说似乎很难。

我需要通过单击它们(UIKit 的isSelected)来切换 HStack 中多个按钮的状态,并更改它们的字体和文本(在 UIKit 世界中,我将在if 语句中使用attributedText 属性@ 语句检查isSelected属性,全部在@IBActionTouchUpInside)。

我的第一个想法是在其动作块中获得 Button 的“引用”,但感觉这不是 SwiftUI 的方式(甚至是不可能的)。我找到了使用 Configurator 及其 isPressed 属性(这不是我要搜索的)的解决方案,但我需要 Button 实际上表现得像切换。 SwiftUI 中是否有任何内置的 isSelected 替换,或者我必须使用 @State 或 @BindableObject 制作我自己的 View 实现,这将封装一些手势识别器(看起来很丑陋)。提前致谢!

【问题讨论】:

  • 你是对的(关于很多事情),包括 SwiftUI 在可能的情况下关于 UI。没有“多个按钮的状态”——老实说,“状态”意味着完全不同的东西,请查看@State。按钮“状态”实际上内置在 SwiftUI Button 中。看看这两个:alejandromp.com/blog/2019/06/09/playing-with-swiftui-buttonsalejandromp.com/blog/2019/06/22/swiftui-reusable-button-style
  • 更改按钮标签中的字体或文本没有任何问题,只要数据来自观察到的变量,以便 SwiftUI 检测到更改。 AFAIK 唯一不能做的就是使用媒体进行更改,我相信这些操作是由发布触发的。 Apple 在 Landmarks 教程中使用一个按钮作为收藏夹的切换,它还将外观从一颗开放的星星更改为填充的星星。任何状态都可以影响任何视图,因此您可以将最喜欢的星扩展到 5 星并使用fav >= 3 来影响第三星的标签和fav = 3 在它的动作中。
  • 感谢您的回复,朋友。很抱歉给您带来不便,我并不是说“多个按钮的状态”作为每个按钮状态的结合都简化为“按钮组的全局状态”,我的意思是像 UIKit 中的每个按钮的 isSelected 状态,就是这样,我提到多个按钮只是为了表明在我的视图中将状态存储为@State (isSelected=true/false) 不是一个选项,因为我有很多按钮,并且每个按钮的状态都是单独的(因此它必须由每个特定的按钮本身)。
  • @dfd 我阅读了您提供的链接,谢谢,但找不到与“按钮“状态”实际上内置在 SwiftUI 按钮中的任何内容。能否请您更具体一点?
  • @MichaelSalmon 感谢您的评论,问题是 Apple 的示例使用模型的 isFavorite 属性来简单地在其 Label 闭包中显示 if-else 按钮​​。我唯一能想到的就是创建自定义视图,它封装了 Button,并将内部的每次触摸计数为 2x isPressed 计数器,或者只使用带有手势识别器的视图。对我来说似乎很奇怪,要完成在 UIKit 中花费 2 行代码的事情,你必须真正思考如何去做:/

标签: swift button uibutton swiftui selected


【解决方案1】:

您可以根据isPressed创建自定义ButtonStyle并修改配置的标签

struct CustomButton: View {
    var body: some View {
        Button {
            // action
        } label: {
            Text("Button")
        }
        .buttonStyle(CustomStyle())
    }
}

struct CustomStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(.white)
            .background(configuration.isPressed ? .green : .black)
    }
}

【讨论】:

    【解决方案2】:

    我有一个简单的方法来做到这一点。

        @State var selected = false
    
        func createButton() -> some View {
            Button(action: {
                self.selected.toggle()
            }, label: {
                Text("Hello World")
                    .padding(.all, 5)
                    .background(selected ? Color.blue : Color.white)
                    .foregroundColor(selected ? Color.white : Color.blue)
            })
                .overlay(
                    RoundedRectangle(cornerRadius: 4)
                        .stroke(Color.blue, lineWidth: 1)
            )
        }
    
    

    【讨论】:

    • self.$selected.wrappedValue.toggle()
    【解决方案3】:

    我想出了自定义视图,它像这样封装 Button:

        import SwiftUI
    
    struct SelectableButtonStyle: ButtonStyle {
    
        var isSelected = false
    
        func makeBody(configuration: Self.Configuration) -> some View {
            configuration.label
                .frame(width: 60.0, height: 60.0, alignment: .center)
                .padding()
                .background(Color(#colorLiteral(red: 1, green: 0.8980392157, blue: 0.7058823529, alpha: 1)))
                .clipShape(RoundedRectangle(cornerRadius: isSelected ? 16.0 : 0.0))
                .overlay(RoundedRectangle(cornerRadius: isSelected ? 16.0 : 0.0).stroke(lineWidth: isSelected ? 2.0 : 0.0).foregroundColor(Color.pink))
                .animation(.linear)
        }
    }
    
    
    struct StatedButton<Label>: View where Label: View {
    
    
        private let action: (() -> ())?
    
        private let label: (() -> Label)?
    
        @State var buttonStyle = SelectableButtonStyle()
    
        init(action: (() -> ())? = nil, label: (() -> Label)? = nil) {
            self.action = action
            self.label = label
        }
    
        var body: some View {
            Button(action: {
                self.buttonStyle.isSelected = !self.buttonStyle.isSelected
                self.action?()
                print("isSelected now is \(self.buttonStyle.isSelected ? "true" : "false")")
            }) {
                label?()
            }
            .buttonStyle(buttonStyle)
        }    
    }
    

    如果这个解决方案不好,请告诉我为什么,我真的很感激。而且我还在为一个非常微不足道的问题而苦苦挣扎:如何将我的模型的数组元素映射到按钮(即如何检测到底点击了哪个按钮),但我认为我必须为此创建另一个问题。

    【讨论】:

    • 感觉工作量很大,但我想 UIButton 有这么多功能。为了让它在工具栏中工作,我必须将协议一致性更改为 PrimitiveButtonStyle。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-20
    • 2020-05-16
    • 2021-11-17
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    相关资源
    最近更新 更多