How to Dynamically Change the Font Size in Auto Layout iOS

How to dynamically change the font size in auto layout iOS?

You should use autoshrink.

Since all iPhones have the same Compact width size class when in portrait mode, you can't rely on this to handle your label size.


Previews are for iPhone5, iPhone6 and iPhone 6+

iOS Sample Image 55

In the inspector, you must select minimum font scale or minimum font size in front of Autoshrink. This enables the content to change the size of the font to fit in the label.

Here, I set minimum font scale to 0,5 so the minimum size is half of the current size (31.0). The text will try to fit until it reaches the minimum scale/size.

(Generally do not use "Tighten letter spacing" for this purpose. Tighten letter spacing uses the same font size and reduces spacing between letters. It can make the label up to 5% tighter before truncating, but it's not effective when minimum font scale/size is enabled.)


You may want to test with a wide screen device such as the iPad Pro, and also on a smaller screen such as the iPhone 4S. As a good practice you should test with different user system font sizes, you can set them in Settings>General>Accessibility>Larger Text.

Autoshrink will not adjust the font size bigger than the one set on the label, that means if you make the label the same width as the screen but leave the font size to 14, it will try to increase the font size until it reaches that size.

To make it actually work, select a big font size.

You can still combine autoshrink with size classes to change the maximum font size depending on the device/the orientation.


In case you want to use autoshrink with UIButtons, you can still set this behavior with two lines of code.

myButton.titleLabel.minimumScaleFactor = 0.5;
myButton.titleLabel.adjustsFontSizeToFitWidth = YES;

change font size in UILabel based on auto layout (swift)

UILabel has no methods automatically reducing font to fit content size or height - only width.

So you should do it by manually changing font due to size changes (don't forget to test result sizes with UILabel not NSString.sizeWithFont:: results would be slightly different).

You can try to set constraints of your container to preserve UILabel's aspect ratio. This way when you reduce height, width will be reduced too and UILabel.adjustsFontSizeToFitWidth would do it's work. Should be rough, but enough in you case and much easier and faster to implement.

UPDATE

Forgot to mention. I spoke about your concrete example. Behaviour depends on numberOfLines and lineBreakMode. Making the first != 1 and second something like .byTruncatingTail (default value) will display close to necessary (but, for example, will wrap words when width isn't enough - while you expect no wrapping at all).

Dynamically changing font size of UILabel

Single line:

factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;

The above code will adjust your text's font size down to (for example) 8 trying to fit your text within the label.
numberOfLines = 1 is mandatory.

Multiple lines:

For numberOfLines > 1 there is a method to figure out the size of final text through NSString's sizeWithFont:... UIKit addition methods, for example:

CGSize lLabelSize = [yourText sizeWithFont:factLabel.font
forWidth:factLabel.frame.size.width
lineBreakMode:factLabel.lineBreakMode];

After that you can just resize your label using resulting lLabelSize, for example (assuming that you will change only label's height):

factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);

iOS6

Single line:

Starting with iOS6, minimumFontSize has been deprecated. The line

factLabel.minimumFontSize = 8.;

can be changed to:

factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;

iOS7

Multiple lines:

Starting with iOS7, sizeWithFont becomes deprecated.
Multiline case is reduced to:

factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);

iOS 13 (Swift 5):

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

Swift - Adjusting fontSize to fit the width of the layout (programmatically)

Try the following commands for your label:

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2

And try to change the lines of the label to 0 and 1 (check both cases):

label.numberOfLines = 0 // or 1

How to declare different font sizes for same size class in adaptive auto layout in xcode?

This doesn't work with adaptive layout. Apple thinks, you should use the same font size for these different devices if they have the same size class.

You might have to get the screen size and change the font size according to that.

Dynamic font resizing in collectionview

To change the size of a view and have all of it's subviews / buttons / labels / etc scale with it - including label fonts, you are better off using CGAffineTransform for scaling.

Here is a simple example. It can be pasted into a Playground page to see the effect:

import UIKit
import PlaygroundSupport

class TestViewController : UIViewController {

let theStackView: UIStackView = {
let sv = UIStackView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.axis = .vertical
sv.distribution = .equalCentering
sv.alignment = .center
return sv
}()

let theContainerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .green
return v
}()

let btn: UIButton = {
let b = UIButton()
b.setTitle("Tap to Scale", for: .normal)
b.backgroundColor = .red
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()

// on button tap, scale the Container view by 50% both ways
// note that Container view's subviews also scale
func btnTapped(_ sender: Any) {
theContainerView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}

override func viewDidLoad() {
super.viewDidLoad()

// add the button to self.view
self.view.addSubview(btn)

// button position
btn.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
btn.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20.0).isActive = true

// add a target for the button tap
btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)

// add our "Container" view
view.addSubview(theContainerView)

// add our Stack view to the Container view
theContainerView.addSubview(theStackView)

// add 5 labels to the Stack view
for i in 1...5 {

let label = UILabel()
label.font = UIFont.systemFont(ofSize: 20.0)
label.text = "This is Label \(i)"
label.backgroundColor = .cyan
label.translatesAutoresizingMaskIntoConstraints = false

theStackView.addArrangedSubview(label)

}

// pin Container view 20-pts from the bottom of the button, and 8-pts from left, right and bottom
theContainerView.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0).isActive = true
theContainerView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
theContainerView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
theContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true

// pin Stack view 8-pts from top, left, right and bottom of the Container view
theStackView.topAnchor.constraint(equalTo: theContainerView.topAnchor, constant: 8.0).isActive = true
theStackView.leftAnchor.constraint(equalTo: theContainerView.leftAnchor, constant: 8.0).isActive = true
theStackView.rightAnchor.constraint(equalTo: theContainerView.rightAnchor, constant: -8.0).isActive = true
theStackView.bottomAnchor.constraint(equalTo: theContainerView.bottomAnchor, constant: -8.0).isActive = true

}

}

let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc


Related Topics



Leave a reply



Submit