Andrew
Andrew

Reputation: 25

How to set different font size for UIButton when it is pressed

I am trying to change font size of button itself after it was pressed.

class ViewController: UIViewController {
   @IBOutlet weak var buttonToResize: UIButton!

   @IBAction func buttonTapped(_ sender: UIButton) {
        buttonToResize.titleLabel!.font = UIFont(name: "Helvetica", size: 40)
// Also tried buttonToResize.titleLabel?.font = UIFont .systemFont(ofSize: 4)
}

However the changes are not applied.

What is interesting, to me, that if I try to resize some other button (second one) after pressing on initial (first one), it works as expected.

Like this:

class ViewController: UIViewController {
@IBOutlet weak var buttonToResize: UIButton!
@IBOutlet weak var secondButtonToResize: UIButton!

@IBAction func buttonTapped(_ sender: UIButton) {
    secondButtonToResize.titleLabel!.font = UIFont(name: "Helvetica", size: 40)
}

Other properties like backgroundColor seems to apply, however with font size I face problem.

Upvotes: 1

Views: 2038

Answers (4)

claude31
claude31

Reputation: 884

Cowirrie analysis made me think of this solution (tested)

@IBAction func testX(_ sender: UIButton) {
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1)  { 
        sender.titleLabel?.font = sender.titleLabel?.font.withSize(32) 
    }
}

Upvotes: 0

omokagbo
omokagbo

Reputation: 1

class ViewController: UIViewController {
     @IBOutlet weak var buttonToResize: UIButton!
  
    @IBAction func buttonTapped(_ sender: UIButton) {
    sender.titleLabel?.font = .systemFont(ofSize: 30)
    }
  }

This should solve the problem. Use the sender tag instead of the IBOutlet.

Upvotes: 0

Cowirrie
Cowirrie

Reputation: 7226

First, here's the sequence of events when you tap on a UIButton.

  1. The button sets its own isHighlighted property to true.
  2. The button fires any Touch Down actions, possibly multiple times if you drag your finger around.
  3. The button fires any Primary Action Triggered actions (like your buttonTapped).
  4. The button fires any Touch Up actions.
  5. The button sets its own isHighlighted property to false.

Every time isHighlighted changes, the button updates its styling to how it thinks it should look. So a moment after buttonTapped, the button you pressed overwrites your chosen font with its own font.

It's worth exploring this to make sure you understand it by creating a UIButton subclass. Don't use this in production. Once you start overriding parts of UIButton, you need to override all of it.

// This class is to demonstrate the sequence of events when you press a UIButton.
// Do not use in production.
// To make this work properly, you would also have to override all the other properties that effect UIButton.state, and also UIButton.state itself.
class MyOverrideHighlightedButton : UIButton {
    // Define a local property to store our highlighted state.
    var myHighlighted : Bool = false
    
    override var isHighlighted: Bool {
        get {
            // Just return the existing property.
            return myHighlighted
        }
        
        set {
            print("Setting MyOverrideHighlightedButton.isHighlighted from \(myHighlighted) to \(newValue)")
            
            myHighlighted = newValue
            
            // Since the UIButton remains unaware of its highlighted state changing, we need to change its appearance here.
            // Use garish colors so we can be sure it works during testing.
            if (myHighlighted) {
                titleLabel!.textColor = UIColor.red
            } else {
                titleLabel!.textColor = titleColor(for: .normal)
            }
        }
    }
}

So where does it keep pulling its old font from? On loading a view it will apply UIAppearance settings, but those will get discarded when you press the button too. iOS 15+, it looks like it uses the new UIButton.Configuration struct. So you could put this in your buttonTapped:

// The Configuration struct used here was only defined in iOS 15 and
// will fail in earlier versions.
// See https://developer.apple.com/documentation/uikit/uibutton/configuration
sender.configuration!.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
    var outgoing = incoming
    // We only want to change the font, but we could change other properties here too.
    outgoing.font = UIFont(name: "Zapfino", size: 20)
    return outgoing
}

I'd like to think there's a simpler way to do this. Whichever way you work, make sure it will also work in the event of other changes to your button, such as some other event setting isEnabled to false on it.

Upvotes: 4

aeskreis
aeskreis

Reputation: 1973

You probably want something like this

struct MyView: View {
  @State var pressed: Bool = false

  var body: some View {
    Button(action: {
      withAnimation { 
        pressed = true 
      }
    }) {
      Text("Hello")
    }
    Button(action: {
    }) {
      Text("Hello")
         .font(pressed ? .system(size: 40) : .system(size: 20))
    }
  }
}

Upvotes: 0

Related Questions