Multiline UILabel with right-to-left text and auto adjusted font size - ios

Below is the code in Swift I used for a 2 line UILabel with adjustsFontSizeToFitWidth set to true, working properly for left-to-right text. I have used EasyPeasy library for setting layout constraints.
let contactLabel = UILabel()
contactLabel.text = "Tell us how we can contact you".localized()
contactView.addSubview(contactLabel)
contactLabel.easy.layout([Leading(), Trailing(), Top(20), Height(60)])
contactLabel.numberOfLines = 2
contactLabel.lineBreakMode = .byTruncatingHead
contactLabel.adjustsFontSizeToFitWidth = true
When I changed the language to Arabic, the text will be broken to two lines properly but shown in LTR mode instead of RTL. How should manage a multiline label to show Arabic text?
I also checked this behavior on iOS 11 and it is working, maybe there is a trick to it in iOS 12.

Don't set a specific height because of that is not expanding to your amount of text.
Steps 1 - Set top, leading, trailing and height constraint and change height relation to Greater Than or Equal to
Step 2 - label.numberOfLines = 0
Step 3 - label.sizeToFit()
step 4 - label.lineBreakMode = .byTruncatingTail

Although setting the label alignment to "natural" works in most cases, iOS sometimes gets it wrong. If you're out of ideas, you can always set it manually in the code based on the current layout direction of the application.
if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
resultLabel.textAlignment = .left
} else {
resultLabel.textAlignment = .right
}

Related

Splitting a string truncates the word in UILabel

I try to setup a custom button with UIImage and UILabel
After setting up constraints, I started testing this button and noticed strange behavior
UILabel in UIButton code:
private var title: UILabel = {
var label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 14)
label.numberOfLines = 0
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5
return label
}()
When I set title for example "Hfpdktxtybz", UILabel works amazing!
One word takes one line:
But if I try set title for example "Развлечения", UILabel truncates the word.
One word is split into two lines:
Why for English language label work is correctly, but for Russian language truncates the word? How to fix it?
The number of characters is the same
The problem is, as said in the comments, that characters don't necessarily have the same width.
lllll
AAAAA
aaaaa
The above example clearly shows characters do not have the same width although they have same character count.
So Autolayout calculates the UILabel real width and it has only one option in order to satisfy your constraints. That is to split it into 2 lines.
If you don't want this to happen consider changing UILabel priority numberOfLines.
if you use storyboard
if you use swift programmatically.
label.numberOfLines = 2

How do I offset UILabel text alignment?

I am trying to offset the center starting point for a UILabel. The problem that I am facing is that I can't make the label text to grow from a point that is offset from center until it reaches one end of the label. Then, I want the text to shift one character to the left with each additional added character until it reaches the the other end. Then it would be acceptable for the text to truncate with an ellipses.
So far, my code looks like this but I don't know where to go from here.
private let amountLabel: UILabel = {
let label = UILabel()
label.textColor = .blue
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
I suggest you put the UILabel into a container view, center horizontally with the offset you want, but set its priority lower than the compression resistance., e.g. 750, compression resistance 999. Then create a trailing constraint >= with priority 1000, and leading constraint >= priority 1000. In that way centering will be the weakest constraint and as the text grows it will shift to the left until it reaches the leading.

Force a view to take as much space as possible inside UIStackView

I'm creating part of my application's UI with Swift and the problem I'm facing is I have a UIStackView with 3 sub views: 2 UILabels and an UIImageView. Here is my first code
let switchview = UISwitch()
let nodelableview = UILabel()
nodelableview.textAlignment = NSTextAlignment.right
nodelableview.numberOfLines = 0
nodelableview.text = nodes[i].type + " " + nodes[i].node_name
let statLabel = UILabel()
statLabel.textAlignment = NSTextAlignment.left
statLabel.text = nodes[i].stat
let stack = UIStackView()
stack.axis = .horizontal
stack.spacing = 16
stack.addArrangedSubview(statLabel)
stack.addArrangedSubview(nodelableview)
stack.addArrangedSubview(switchview)
cell.nodesView.addArrangedSubview(stack)
the problem with this code is that when the nodelabelview has long text the UIStackView not extending to make space for 2 or more lines. So I set the alignment to .center and here is the result
There is empty space left but the first UILabel is using it for nothing. How can I force the second UILabel to use available spaces?
A setup that would give priority to your second label (the one with unlimited number of lines), would be a stackview set to "Fill Proportionally" distribution (which means that views are sized based on their intrinsic size & hugging/resistance priorities)
combined with a horizontal "Content Compression Resistance Priority" of 1000 ('required') for the left label & the switch (which means 'do not compress')
which is resolved to this:
You may need to set the horizontal contentHuggingPriority and contentCompressionResistance for each label / switch to something different from the others, ensuring that the one you wish to expand to fill remaining available space has the lowest hugging value.

How to fit all numbers on my display label? - Basic Calculator

I'm a beginner in Swift and Xcode. As my very first project without tutorials I try to do basic Calculator app. My goal is to make it look like original calculator app on iOS 9. Everything works, but I don't know how to fit all numbers on the screen. In Apple app, if there are more numbers, they're getting smaller. How to do that?
For UITextField:
You have to set the adjustFontSizeToFitWidth property to yes and provide a suitable small value for the minimumFontSize.
Both together will cause the UITextField to reduce its font size to fit the string in its bounds.
let textfield = UITextField()
textfield.adjustsFontSizeToFitWidth = true
textfield.minimumFontSize = 5
// ... more
For UILabel:
You have to set the adjustsFontSizeToFitWidth property to yes and provide a suitable small value for the minimumScaleFactor.
Both together will cause the UILabel to reduce its font size to fit the string in its bounds.
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.05
// ... more

Adjust font size of text to fit in UIButton

I want to make sure the button text fits into a UIButton, while the UIButton has a fixed size.
Of course I can access the titleLabel of the UIButton.
In a label I would set autoshrink to minimum font scale which seems to correspond to
self.myButton.titleLabel.adjustsFontSizeToFitWidth = YES;
, but doesn't really behave the same, since it only makes the text fits horizontally into the bounds, not vertically, thereby not changing the font size.
How can i actually adjust the font size of a label programmatically to make the text fit into the label bounds (as shown in Goal in the picture below) ?
I already tried
self.myButton.titleLabel.numberOfLines = 0;
self.myButton.titleLabel.minimumScaleFactor = 0.5f;
without success, always ended up as in adjustsFontSizeToFitWidth on the left side of the pic above.
Edit: The solution also has to be ios7 compliant
self.mybutton.titleLabel.minimumScaleFactor = 0.5f;
self.mybutton.titleLabel.numberOfLines = 0; <-- Or to desired number of lines
self.mybutton.titleLabel.adjustsFontSizeToFitWidth = YES;
... did the trick, after layoutIfNeeded in viewDidLoad
As it turns out, all those must be set to actually adjust the font-size, not just making it fit into the frame.
Update for Swift 3:
mybutton.titleLabel?.minimumScaleFactor = 0.5
mybutton.titleLabel?.numberOfLines = 0 <-- Or to desired number of lines
mybutton.titleLabel?.adjustsFontSizeToFitWidth = true
Updated code for Swift 3.0:
yourButton.titleLabel?.minimumScaleFactor = 0.5
yourButton.titleLabel?.numberOfLines = 0
yourButton.titleLabel?.adjustsFontSizeToFitWidth = true
You can also set a User Defined Runtime Attribute in Interface Builder for the button where
titleLabel.adjustsFontSizeToFitWidth = true
to make text horizontally and vertically fit with button bounds :
1 - set button alignment like image (* VERY IMPORTANT *)
2 - add this lines of code in your ViewController
btnTest.setTitle("Test for multi line in button show line in button show Test for multi line in button show line in button show", for: .normal)
btnTest.titleLabel!.textAlignment = .center
btnTest.titleLabel!.numberOfLines = 0
btnTest.titleLabel!.adjustsFontSizeToFitWidth = true
btnTest.titleLabel!.minimumScaleFactor = 0.5
// below line to add some inset for text to look better
// you can delete or change that
btnTest.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
note that DON'T using btnTest.titleLabel!.lineBreakMode = NSLineBreakMode.byWordWrapping or other BreakMode in your code . for enable multiline in button . just using from above code
final result :
Try to call the following method.
button.titleLabel?.baselineAdjustment = UIBaselineAdjustment.AlignCenters
try this:
[myButton setFont:[[myButton font] fontWithSize:--originalButtonFontSize]];
textWidth = [text sizeWithFont:[myButton font]].width;
}
In Storyboard, Go to Link Break in Attributes Inspector, see word wrap..or set according to your choice.
In Xcode->Open storyboard->Go to attributes inspector->Control->Alignment->Choose second in both horizontal and vertical.
or
YourButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
If you prefer do in storyboard, just click the button, then show attributes inspector, and set the line break to "Word Wrap".

Resources