Find specific characters in UIlabel? - ios

I am having a slight issue at the moment regarding finding specific characters in a UILabel. I tried the simple
if variable == "the string you want it to equal" {
//Do the thing you want
}
The issue is that my UIlabel updates based on the time. This normally would be no issue but I also have a smaller Label next to it as seconds.
This works fine until the main time label hits the double digits of 10, 11, 12. This causes the Label to expand and cuts off the smaller seconds label. I know I could place the smaller label somewhere where the main label doesn't cut it but the design wouldn't be as great.
I tried also to make variables as BOOLEANS
let time10 = "10"
let time11 = "11"
let time12 = "12"
Now this would require me to make many other variables like "10:01, 10:02" which would be highly inefficient.
Is it possible for a feature in swift to look up a specific amount of characters in a string (the first 2 in this case" and let me write the thing I want to do if the condition is met?

Try playing with .minimumScaleFactor and auto layout priorities.
The first one will let one label scales down font size to avoid ....
With auto layout priorities you can make a label shrinks in spite of another.
It should be easier if you are using Interface Builder.
Hope this helps

Try using label.sizeToFit every time you update the label's value. Hopefully it should fix the issue.

To answer your original question, you can use the count function, for example you can do count(string), as explained in this answer.

Related

UILabel line breaks too early on iOS 11

I have an iOS 11 app with a table with cells.
In this cells, I have a UILabel.
The UILabel seems to "decide" to break the line in a way that keeps the bottom line with at least 2 words (no matter what the BreakLineMode is!).
I know about using -
Adding non-breaking space (U+00A0) - TOO EXPENSIVE
and
Using NSAllowsDefaultLineBreakStrategy NO on NSUserDefaults - NOT ALLOWED BY APPLE
What can I do to fix this problem?
In this image, you can see that the first word in the second line, could appear on the first line but got down to the second for some reason...
EDIT:
This is NOT a width issue, this is an issue with iOS 11 NEW UILabel logic(!) that doesn't allow orphans words (one word) on a new line, Only two word because they think it looks better. It doesn't. But there must be a way to make a UILabel act on iOS 11 like it did on iOS 10 and under.
I have found an hack -
Adding a lot of spaces (like 10 - 20) to the end of the string will make the UILabel "think" that the line is long enough so it will leave one word on the bottom line. (instead of 2 so the first line will not break early)
I don't like hacks but this is all I've got at the moment, if anybody has a different answer i will gladly accept it instead of this one
You can add this three line of code -
labelName.adjustsFontSizeToFitWidth = true
labelName.minimumScaleFactor = 0.3
labelName.numberOfLines = 0 // or you can set it 1 or 2
In my case I was able to solve this by using a textview.
UITextView allows orphans, sizes according to intrinsic size if scrolling is disabled and works like label if interaction is disabled, which is also disabled in label so it will forward all the touches.

UILabel wrong word wrap in iOS 11

I have problem with application using XIBs without autolayout. I don't know if this is important information.
I have UILabel with 2 lines using word wrap. In iOS 10 word wrap was working correctly, and first line contained one word + special character, for example ampersand. Example:
Then on iOS 11 word wrap is working somehow wrong and puts ampresand to the second line:
This is problematic as longer words, that normally fitted on second line now are not being shown correctly. Any idea what has changed? I know about safeArea but it doesn't look like reason. Any ideas how to move that ampersand to the top where is plenty of space for it?
Rest of the settings:
This is a change by Apple to prevent widowed lines. From a design perspective, it is preferred to avoid having a single word on a line of text. UILabel now breaks the line in a way that the second line of text always has at least 2 words on it.
See the answer below for an option to disable it.
Also here's a good article about "widowed" and "orphaned" text.
Since iOS 14 you can use lineBreakStrategy property of UILabel instance to control this behavior.
Available values are:
NSParagraphStyle.LineBreakStrategy() // none
NSParagraphStyle.LineBreakStrategy.pushOut
NSParagraphStyle.LineBreakStrategy.hangulWordPriority
NSParagraphStyle.LineBreakStrategy.standard
To disable this behavior using Swift:
if #available(iOS 14.0, *) {
label.lineBreakStrategy = []
}
// Alternatives
// label.lineBreakStrategy = NSParagraphStyle.LineBreakStrategy()
// label.lineBreakStrategy = .init(rawValue: 0)
// label.lineBreakStrategy = .init()
To make it work on lower iOS versions, you can use NSAttributedString:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakStrategy = []
let attributedString = NSAttributedString(string: "Your text here", attributes: [
.paragraphStyle: paragraphStyle
])
let label = UILabel()
label.attributedText = attributedString
Objective-C:
if (#available(iOS 14.0, *)) {
label.lineBreakStrategy = NSLineBreakStrategyNone;
}
Launching the app with the arguments -NSAllowsDefaultLineBreakStrategy NO (an undocumented defaults setting) seems to force back to the old behavior. Alternatively, you can set NSAllowsDefaultLineBreakStrategy to NO in NSUserDefaults at startup (Apple registers a default of YES for that value when UILabel or the string drawing code is initialized, it appears, so you would need to register an overriding value after that, or insert it into the NSArgumentDomain, or just set the default persistently).
Apple may consider that private API and reject apps that use it; I'm not sure. I have not tried this in a shipping app. However, it does work in quick testing -- saw the setting in NSUserDefaults and found changing it altered the behavior.
This is not really an answer, but I want to add an illustration of how it is a general problem, not at all related to ampersands.
Both of these UILabels have identical width constraints, and the text is almost identical. But the second has the word wrap I would expect. The first is incorrect, the "about" can clearly stay on the first line.
A bit of a hack but you can add some zero width spaces to the end of the string to restore the old behaviour, without affecting the layout of the string otherwise that you'd get from normal spaces:
let zeroWidthSpace: Character = "\u{200B}"
let spacingForWordWrapping = String(repeating: zeroWidthSpace, count: 6)
label.text = "oneText & two" + spacingForWordWrapping
It seems that replacing the space before the ampersand with a non-breaking space (U+00A0) keeps the ampersand on the same line. Depending on how you are generating the text for the label, this might not be easy to automate (maybe you really do need the ampersand to be on the second line in some cases).
An option may be to use a UITextView instead -- that does not seem to have this behavior. If you set the NSTextContainer.lineFragmentPadding to 0, the textContainerInset to UIEdgeInsetsZero, and turn off all scrolling (scrollEnabled, bounces, scroll indicators, etc.) it will display similarly to a UILabel, though not with as much constraint flexibility. It's not a drop-in replacement, but in some situations it's acceptable.
As a simple (hacky) workaround, you can often get the correct behaviour with a UILabel by adding spaces at the end of your text. Using your example:
Wraps the new (undesired) way:
"oneText & two."
Wraps the old way:
"oneText & two. " (note the 2 extra spaces at the end of the string)
The obvious downside is if those extra spaces get forced to a new line by themselves, but for something simple like a title it's often enough.

UIsegmentedControl title appearance

HI, i set my uisegmentedcontrol's width manually, but when the width gets too small, the words becomes ...
Is that anyway that it won't behave in this way? Instead, i just want to show the text just like the picture shown below.
I'd suggest changing your design here and going for a different approach.
The design that you seem to want makes readability pretty much impossible.
Plus, what happens if I'm using your app and add another "Active Project". What happens if I have 10 active projects?
Take the fact that the UI does not work as a sign that you are using the wrong UI for the problem you are trying solve.
I'd suggest possibly just have the current project title here with a button to maybe present a list of projects to switch to... or something.
The text has been truncated. If you want it to fit your segment, you need to update the segment control size based on the text length. If you just want to get rid of truncation, you can use the following snippet. However, it's not recommended, as later Apple might change the UISegmentControl hierarchy.
for item in segmentedControl.subviews {
for subview in item.subviews {
if subview.isKind(of: UILabel.self) {
let _label = subview as! UILabel
_label.numberOfLines = 0
_label.lineBreakMode = .byWordWrapping
}
}
}

Break line on max width text UILabel swift 2

I'm currently trying to make an app that takes the usernames of some people and print them out in a custom cell, inside a label.
But if a user has the name "John Goodwilkinson" It's a large name,
so i'm trying to figure out how to make a
/n
Between the 2 words.
Does anyone has any idea?
I've googled but couldnt find anything at all.
Below you can see the screenshots with my code and the suggestions of the fellows :)
Also i have tried to put the code in the view controller that i call the custom cell like this
cell.frndName.numberOfLines = 0
cell.frndName.lineBreakMode = .ByWordWrapping
But it didn't work either
You can do that by setting the number of lines to the label to be 2 or 0 (if you wnat to be any number) and line breaks to be word wrap.
Link this
Update
after checking you UI. It ended up that removing the height/ width constraints and pinning the label from the bottom/ right the other controllers solved the problem.
You have to increase height of your UILabel and apply constant only for its width.
second thing you can add #“\n” by NSString *newUsername = [oldUsername stringByReplacingOccurrencesOfString:#" " withString:#“\n”];
it will replace all spaces between two words by #“\n” and next word will show in next line.

Is the most efficient way to constantly update a label on screen to simply change the label's text property?

Say I have to update a label 1000 times a minute. Completely change its string value. Am I best off making 1000 setText: calls per minute? Or is there a more efficient way? Perhaps doing away with labels completely?
You basically have two options - update the textproperty of a UILabel or draw an NSString directly onto a UIView (after first erasing the previous value). You'll have to run some tests to see which is more efficient.
You can update some local field/variable and use Timer which read value from variable as frequent as it necessary and update Label. You can also use some throttle strategies.
I'm not an iOS expert so I say what my intuition says to me.
I've used this github library in one of my projects https://github.com/dataxpress/UICountingLabel, which basically subclasses a UILabel and counts down from some initial value to some final value with a custom duration that you can specify, and it is quite efficient and smooth. You can have a look at their code and it might help.

Resources