Home > Software design >  How can I define the size of button depending on its font size in SwiftUI?
How can I define the size of button depending on its font size in SwiftUI?

Time:07-12

If I already have a button whose font size is defined by the .font() modifier like below:

Button("Hello"){}
    .font(.system(size: 10))

How can I use a ButtonStyle with .buttonStyle() to decide the size of this button?

struct CustomButtonStyle: ButtonStyle {
    
    func makeBody(configuration: Configuration) -> some View {
        let size = 2 * configuration.label.fontSize       // Something like this
        
        configuration.label
            .frame(width: size, height: size)
            .background(.red)
    }
    
}

Or is there some alternatives to this approach? I tried using .padding() directly. But it don't work properly. As you can see in above screenshot, different sizes were generated because the different sizes of SF Symbols.

func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .background(.red)
    }

enter image description here

CodePudding user response:

SwiftUI allows to create Font but does not allow to read font properties, so you have to store that at some model layer (say as UIFont) and inject it from outside. Or don't use that at all but some dynamic things, like padding, etc., because Text/Label adopts font sizes-to-frames automatically.

Here is what I meant:

private let uiFont = UIFont.preferredFont(forTextStyle: .title1)
private var font: Font { Font(uiFont as CTFont) }

var body: some View {
    HStack {
        Button(action: {}) {
            Image(systemName: "star")
        }

        Button(action: {}) {
            Image(systemName: "bolt.horizontal")
        }
    }
    .buttonStyle(CustomButtonStyle(font: uiFont)) // << !!
    .font(font)                                   // << !!

and style

struct CustomButtonStyle: ButtonStyle {
    var font = UIFont.preferredFont(forTextStyle: .body)  // << default !!

    func makeBody(configuration: Configuration) -> some View {
        let size = font.lineHeight * 2.0 // << can use any param and/or factor !!
        configuration.label
            .frame(width: size, height: size)
            .background(.red)
    }
}

That gives (Xcode 13.4 / iOS 15.5):

demo

Test code on GitHub

CodePudding user response:

The frame of the button will adapt to fit the content of the button, in our case the text with it's font. Try:

func makeBody(configuration: Configuration) -> some View {        
        configuration.label
            .padding()
            .background(.red)
}

You can leave the .padding() out, I added it just for visual purpose.

  • Related