简体   繁体   中英

SwiftUI Button selection

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 (ie how to detect what button exactly has been tapped), but I think I have to create another question for this.

I have a simple way to do this.

    @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)
        )
    }

You can create a custom ButtonStyle and modify the configuration's label based on isPressed

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM