iOS 5: UILabel change size dynamically - ios

I am using storyboard and custom cells. In one of my labels I drugged on custom cell I need to print date. If date is arabic one, then I need to make label wider and print both dates -> arabic and christian.
My problem is that I am trying to access my label and change size:
if(str.length==ARABIC_DATE)
{
cell.lblYears.layer.frame = CGRectMake(0.0, 0.0, 50.0, 10.0);
cell.lblYears.backgroundColor=[UIColor blackColor];
cell.lblYears.text=str;
}
else
{
cell.lblYears.text=str;
}
The result is an additional label in wrong place (0.0, 0.0..). How to make that code will not produce an additional label, but will change the existing.
Thanx in advance.

You are not creating a second label in this code. You are placing an existing label in the (0,0) coordinate and setting 50 to the width and 10 to the height.
I don't know what your problem is exactly, but there is nothing wrong in that piece of code.

Related

How to make multi-line UILabel text fit within predefined width without wrapping mid-word

I have a UILabel carefully laid out in Interface Builder with proper height and width constraints. The number of lines is set to 4. The wrapping is set to word wrap. The text is "CHECKED". The font size is very large and thus it only fits "CHECKE" and the "D" is on the second line. Writing "Checked" instead of "CHECKED" lets the font shrink (as intended) so that the whole word fits. But (the text is user given and it can be expected that the user writes fully uppercase words) having uppercase words the label does not break it/shrink the font as expected.
Do you have a suggestion as to what I might have missed? Capitalising the words (thusly only having the first letter uppercase) does work, but is not what the client wants.
Updated question
The problem seems to be unrelated to having uppercase or lowercase text. My problem could be solved by an answer to the following question:
How to make (ideally with the help of only Interface Builder) the UILabel text shrink trying to fit full words within all available lines without wrapping the text mid-word?
If the text "CHECKED" is too wide for a label (with more than 1 line available) it should shrink the font size instead of breaking the "D" and wrapping the single letter to the next line.
If the text is "one CHECKED two" and the single word "CHECKED" is already too wide for a label (with more than 1 line available) it should break between all words and shrinking the font size so that "CHECKED" still fits the middle line.
Avoiding:
one
CHECKE
D two
Thank you very much!
Here is a UILabel subclass that will find the largest word in the labels text, use the boundingRect function of NSString to see how large that one word will be with the current font, and drop the font size until it fits the width.
class AutosizingMultilineLabel: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
self.adjustFontToFitWidth()
}
func adjustFontToFitWidth() {
guard let currentFont = self.font else { return }
let minimumFontSize: CGFloat = floor(self.minimumScaleFactor * currentFont.pointSize)
var newFontSize = currentFont.pointSize
var theNewFont = currentFont
if let text = self.text, let longestWord = text.components(separatedBy: " ").max(by: {$1.count > $0.count})?.replacingOccurrences(of: "\n", with: "") {
let nsString = longestWord as NSString
while newFontSize > minimumFontSize {
theNewFont = currentFont.withSize(newFontSize)
let boundingRect = nsString.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude),
options: NSStringDrawingOptions.usesLineFragmentOrigin,
attributes: [.font: theNewFont],
context: nil)
if ceil(boundingRect.size.width) <= self.bounds.size.width {
break
}
newFontSize -= 1
}
self.font = theNewFont
}
}
}
When the word is bigger than the line, word wrap doesn't work. If it doesn't fit on this line, it won't fit on the next line. (same word, same size, same line size). To make it fit, the label will start putting letters on the next line.
If you allow multiple lines on your label, the OS will try to fill the lines before adjusting the font size.
I think you're just running into a limitation on Autoshrink.
In Interface Builder:
add a new UILabel with Width: 230 and Height: 280
set the Font to System 44.0
set Line Break: Truncate Tail
set Autoshrink: Minimum Font Scale at 0.15
set the text of the label to test CHECKED lines
Now, drag the handle on the right edge of the label left and right... when it gets too narrow, the word CHECKED will break onto the next line.
Change CHECKED to checked and do the same thing. You should see the same behavior.
Now, try dragging the Bottom edge up and down. With either CHECKED or checked, you should see the Font Size auto shrink.
So... to do what you're trying to do, you might have to skip Autoshrink and instead do some code calculations.
Edit: further visual of what goes on...
Start with above values, but set the Height of the label to 170 - gives it just a little vertical padding.
Now, drag the left edge to make it narrower.
When you reach the end of the word CHECKED, and keep going, you will see the font shrink until it gets small enough that there is space for it to wrap to a 4th line.
I think you're going to need some code to get exactly what you need.

Swift UILabel with horizontal lines on both sides

I am trying to create a UILabel that has 2 horizontal lines on the left and right side like this:
Does anyone know the best approach for doing this in Swift? The content text in the center will change so I want to make sure it can adapt. I'd really like to create some kind of reusable UIView class but I'm not sure where to start?
Thank you!
You can take two UIview of height 1 or 2 pixels of both side of the label. so it's look likes line!!
And you should set background color to black of that view!
Hope this will help :)
Take one UIView with height of 2. Set leading & Trailing according to Super View.
Now take one UILabel with background color white and put Vertically Center to line view.
Make both Center same.
Your work done.
For more help please refer below image.
You can use an extension on UILabel
public extension UILabel {
func drawLineOnBothSides(labelWidth: CGFloat, color: UIColor) {
let fontAttributes = [NSFontAttributeName: self.font]
let size = self.text?.size(attributes: fontAttributes)
let widthOfString = size!.width
let width = CGFloat(1)
let leftLine = UIView(frame: CGRect(x: 0, y: self.frame.height/2 - width/2, width: labelWidth/2 - widthOfString/2 - 10, height: width))
leftLine.backgroundColor = color
self.addSubview(leftLine)
let rightLine = UIView(frame: CGRect(x: labelWidth/2 + widthOfString/2 + 10, y: self.frame.height/2 - width/2, width: labelWidth/2 - widthOfString/2 - 10, height: width))
rightLine.backgroundColor = color
self.addSubview(rightLine)
}
}
This will add a horizontal line of width of 1.0 on the both side of your label. If you don't add text for your label, it will show two horizontal lines through center with some spaces in between them.
As others have mentioned, you can achieve this using three views:
Add a View to your scene to use as a container. I called this view "Lined Label Holder."
To that container, add two Views, one to produce the line on either side of the label.
Add the label in between the two views, and give it some text. Due to the "height = Test.height" constraint on the Lined Label Holder, The intrinsic height of this label is used to calculate the container's height.
The label is allowed to grow with added text and the lines will always start 5px away from the edges of the text and extended to the edges of the container, whose width can be set independently.
This image shows the required constraints:
Use one UIView with black background and height of 1px, set label background to white, align its text to center and align UILabel to center of UIView (there is no need for 2 views since label white background will cover UIView).
Not necessary 2 UIView's.
Take 1 UIView and give background black color.Add the constraints necessary with: height=2.
place 1 label on the center and give required constraints

How to get UILabel to resize better?

I am trying to make my multiline UILabel as small as possible with given max-width, but the sizeToFit() and sizeThatFits(_,_) methods aren't giving the results I want.
Take a look at this image:
The red rectangle represents the width that I pass in sizeThatFits (while height being Max). Obviously, as you can see, this method does in fact return a size that fits, but it does not give me the smallest size possible, which I want.
Let's say I specified max-width: 300. This actual result is giving me a size of ca. 280*50.
As you can see in the image, the text is now written like this:
Here is some text that is supposed to
align nicely
What I want to achieve is this:
Here is some text that is
supposed to align nicely
This result would've had the same height, but a much smaller width, e.g 200*50
I realize that it's difficult to define "smallest size possible", as it could return this:
Here
is
some
text
that
...
Or even just a single letter per line. But given that sizeThatFits returns this, with a given width and height, why doesn't it return my wanted result, which is the same height, but with smaller width. Why isn't the smallest fit returned? Does a function like this exist?
Sti,
You can try this buddy :) I have been using it and seems to do a pretty good job :)
CGRect rect = [yourText boundingRectWithSize:CGSizeMake(maxWidth_you_Can_afford, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:16]}
context:nil];
The rect after executing will have the minimum width and height that will be required to render the text :)
Once you have the frame now you can set the same for your label and set the text as well :)
I have used it in chat bubble :) and it works well :)
Happy coding :)
I made my own solution, which works pretty well:
private func calculateWantedSize(label:UILabel)->CGSize{
var lastAcceptableWidth = label.bounds.width
let currentHeight = label.sizeThatFits(CGSize(width: label.bounds.width, height: CGFloat.max)).height
var tempHeight = currentHeight
while(tempHeight == currentHeight){
let newWidth = lastAcceptableWidth - 1
tempHeight = label.sizeThatFits(CGSize(width: newWidth, height: CGFloat.max)).height
if tempHeight == currentHeight{
lastAcceptableWidth = newWidth
}
}
return CGSize(width: lastAcceptableWidth, height: label.bounds.height)
}
Here I'm sending my label to a function which first calculates the current width and height of the label, then loops through width-1 and checks the resulting height until the height is changed. The height will change when the width is so low that it needs a new line. When this happens, I return the last valid width which still needed the same height as original.
This is perfect for my problem, using attributed text etc.
Of course, when using this, be sure to do some checking before calling. I don't know what will happen if you use this function when the label has a single word, or a single letter, or no text at all. I have only tested this for the cases I know will happen with this app, and it works well.

Change Position Of a UIView programatically

There is an Arabic Page in my app and The "Date Field" in the Arabic Page must align to the right side of the view(right now, it is to the left). I have tried the following code
-(void)changeDatePosition{
if (!_isEnglish) {
CGRect currentDatePostion=_viewForDate.frame;
[_viewForDate removeFromSuperview];
currentDatePostion.origin.x+=currentDatePostion.size.width;
_viewForDate.frame=currentDatePostion;
[_baseView addSubview:_viewForDate];
}
}
But that did not help. The view positioned itself to the top of the navigation bar(no change in the x co-ordinate,either). I have used autolayout to align the left leading space of "ViewForDate"(the date field) to the leading space of "PlacesView"(The View on Top of the Date Field). But I set its priority to 250. HOw can I solve this problem?
Hook an IBOutlet to the leading constraint of the date view and set its value to 0. And then try this code:
-(void)changeDatePosition{
if (!_isEnglish) {
_dateViewLeadConstraint.constant = x;
}
//x - amount by which view should move right, you can calculate based on your view setup
}
-(void)changeDatePosition{
if (!_isEnglish) {
CGRect currentDatePostion=_viewForDate.frame;
[_viewForDate removeFromSuperview];
float ScreenWidth=_viewForDate.frame.size.width;
currentDatePostion.origin.x=ScreenWidth-currentDatePostion.size.width;
_viewForDate.frame=currentDatePostion;
[_baseView addSubview:_viewForDate];
}
}
can you try it please.May be it solve your problem
Try this code.
currentDatePosition = CGRectMake(self.view.frame.size.width - currentDatePosition.size.width, currentDatePosition.frame.origin.y, currentDatePosition.frame.size.width, currentDatePosition.frame.size.height);
I have found a solution to the problem and quite happy about it.
The DateView has a Left Alignment(Leading Space) to Places That is set to 0. I made a right alignment for it too(at 144). Then I created Outlets for them namely, leftAlignment(=0) and rightAlignment(=144) and wrote this method.
-(void)changeDateLocation{
if (!_isEnglish) {
_leftAlignment.priority=UILayoutPriorityDefaultLow;
_rightAlignment.constant=0;
_rightAlignment.priority=UILayoutPriorityDefaultHigh;
}
else{
_leftAlignment.priority=UILayoutPriorityDefaultHigh;
_rightAlignment.priority=UILayoutPriorityDefaultLow;
_leftAlignment.constant=0;
}
}
And this gave me my solution. I thank all you people who have contributed. This method is quite useful I think. I am trying this for the first time

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