I'm trying to grasp SwiftUI concepts (finished Apple's SwiftUI tutorials) but it seems hard for me after UIKit decade.
I need to switch state of multiple buttons in HStack by clicking on them (UIKit's isSelected
), and change their font and text (in UIKit world i would use attributedText
property in if
statement examinig isSelected
property, all in @IBAction
on TouchUpInside
).
My first thought was to get "reference" of Button in its action block, but it feels like it's not the SwiftUI way (and is not even possible). I found the solution that's using Configurator and its isPressed property (which is not what I searching for), but i need the Button to behave like toggle actually. Is there any built-in isSelected substitution in SwiftUI, or I have to make my own View implementation with @State or @BindableObject that will encapsulate some gesture recognizer (seems pretty ugly). Thanks in advance!
I came up with the custom View, that's encapsulating Button like this:
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)
}
}
Please let me know if this solution is not good and why, I really appreciate it. And also I'm struggling with pretty trivial problem: how to map my model's array elements to buttons (i.e. how to detect what button exactly has been tapped), but I think I have to create another question for this.