The label (bottom of the picture) and the text field (top) have the same same attributedText. But look at the underlines. The ones in the text field are only one pixel high. This looks terrible. Does anyone know what is causing this or how to prevent it?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UITextField* textField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 600, 200)];
NSMutableAttributedString* string = [[NSMutableAttributedString alloc]initWithString:#"The quick brown fox jumps"];
NSNumber* underlineNumber = [NSNumber numberWithInteger:NSUnderlineStyleSingle];
UIFont* font = [UIFont systemFontOfSize: 50];
[string addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, string.length)];
for (NSInteger i=0; i<20; i++) {
if (i%3==0) {
[string addAttribute:NSUnderlineStyleAttributeName value:underlineNumber range:NSMakeRange(i, 1)];
}
}
textField.backgroundColor = [UIColor whiteColor];
textField.attributedText = string;
[self addSubview:textField];
UILabel* label = [[UILabel alloc]initWithFrame:CGRectMake(100, 400, 600, 200)];
label.attributedText = string;
label.font = font;
label.backgroundColor = [UIColor whiteColor];
[self addSubview:label];
}
return self;
}
The label uses a custom rendering style to draw the underline which is unfortunately distinct from the one used by UITextField, which uses WebKit to render when editing and Core Text to render when it's static. Please file a bug with bugreporter.apple.com. Thanks!
Related
If i set bottomLabel.text = Chinese character,i can't see the aboveLabel when i run it and if i debug view hierarchy i can see it.so what's the problem?
UILabel *bottomLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, 200, 40)];
bottomLabel.backgroundColor = [UIColor redColor];
bottomLabel.text = #"中文";
[self.view addSubview:bottomLabel];
UILabel *aboveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 60, 30)];
aboveLabel.backgroundColor = [UIColor greenColor];
aboveLabel.text = #"aboveLabel";
[bottomLabel addSubview:aboveLabel];
why dont you use NSMutableAttributedString for this with one LABEL.
NSString *text1 = #"Hello";
NSString *date1 = #" 12.05 Pm\n";
NSString *text2 = #"World";
NSString *date2 = #" 11.00 AM";
self.lbl.numberOfLines = 0;
NSString * str = [text1 stringByAppendingString:date1];
NSString * str2 = [text2 stringByAppendingString:date2];
UIFont *text1Font = [UIFont fontWithName:#"HelveticaNeue-Medium" size:10];
NSMutableAttributedString *attributedString1 = [[NSMutableAttributedString alloc] initWithString: str attributes:#{ NSFontAttributeName : text1Font }];
NSMutableParagraphStyle *paragraphStyle1 = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle1 setAlignment: NSTextAlignmentLeft];
[paragraphStyle1 setLineSpacing:1];
[attributedString1 addAttribute:NSParagraphStyleAttributeName value: paragraphStyle1 range:NSMakeRange(0, [attributedString1 length])];
UIFont *text2Font = [UIFont fontWithName:#"HelveticaNeue-Medium" size:10];
NSMutableAttributedString *attributedString2 = [[NSMutableAttributedString alloc] initWithString: str2 attributes:#{NSFontAttributeName : text2Font }];
NSMutableParagraphStyle *paragraphStyle2 = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle2 setLineSpacing:1];
[paragraphStyle2 setAlignment: NSTextAlignmentLeft];
[attributedString2 addAttribute:NSParagraphStyleAttributeName value: paragraphStyle2 range:NSMakeRange(0, [attributedString2 length])];
[attributedString1 appendAttributedString:attributedString2];
[self.lbl setAttributedText:attributedString1];
because above label is overlap on bottom label like above image so you not display that if you see that label above label x position change then it display.
if x value set 50 then you display bottm label.
You are adding aboveLabel as subview of bottomLabel hence it doesnot get displayed when you assign chinese character to it. You can see it view hierarchy as it is assigned a frame and added as subview. If you want to add one UILabel above UILabel you can add both labels as subview of common parent view.
i.e.
[self.view addSubview:bottomLabel];
[self.view addSubview:aboveLabel];
You are trying to adding aboveLabel inside of bottomLabel.Instead add both into one view or self.view.
UILabel *bottomLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, 200, 40)];
bottomLabel.backgroundColor = [UIColor redColor];
bottomLabel.text = #"中文";
[self.view addSubview:bottomLabel];
UILabel *aboveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(bottomLabel.frame)+10, 60, 30)];
aboveLabel.backgroundColor = [UIColor greenColor];
aboveLabel.text = #"aboveLabel";
[self.view addSubview:aboveLabel];
Try this code
Objective - C
UILabel *bottomLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 30)];
bottomLabel.backgroundColor = [UIColor redColor];
bottomLabel.text = #"中文";
[self.view addSubview:bottomLabel];
UILabel *aboveLabel = [[UILabel alloc]initWithFrame:CGRectMake(50, 0, 60, 30)];
aboveLabel.backgroundColor = [UIColor greenColor];
aboveLabel.text = #"abc";
[bottomLabel addSubview:aboveLabel];
Is there any way to reduce font size that can be fit in single segment of UISegmentedControl ?
Have tried many thing something like,
[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] adjustsFontSizeToFitWidth];
[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setMinimumScaleFactor:0.5];
AND
NSArray *arr = segment.subviews; // segment is UISegmentedControl object
for (int i = 0; i < arr.count; i++) {
UIView *aSegment = [arr objectAtIndex:i];
for (UILabel *label in aSegment.subviews) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *myLabel = (UILabel *)label;
[myLabel setNumberOfLines:0];
label.numberOfLines = 0;
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.5;
}
}
}
able to set number of lines of label of segment like,
[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setNumberOfLines:0];
Can set single segment size as per content like,
segment.apportionsSegmentWidthsByContent = YES;
but every segment has different size in this case.
I want to keep same size of every segment and want to reduce font size that can be fit in UISegmentLabel (label) of UISegmentedControl something like minimumscalefactor or minimumfontsize or adjustsFontSizeToFitWidth. These properties is not working for label when contains in UISegmentedControl.
If any one can help to achieve this, it will be appreciated!!
Thanks in advance!!
I found the issue, Actually it was my mistake!!! I was setting numberOfLines,adjustsFontSizeToFitWidth,minimumScaleFactor and TitleTextAttributes toghether. If we set titleTextAttribute then minimumScaleFactor can't work.
Update : (As asked by #HawkEye1194 in comment of another answer)
I have end up with below solution,
//this will allow multiple lines in label contained by every segment in segmentedcontroller
[[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setNumberOfLines:0];
UISegmentedControl *segment = [[UISegmentedControl alloc]initWithItems:option];
segment.frame = CGRectMake(20, 50, self.view.frame.size.width - 40, 50);
segment.tintColor = [UIColor grayColor];
segment.selectedSegmentIndex = 0;
segment.backgroundColor = [UIColor whiteColor];
segment.tag = segmentedControllerBaseTag;
[segment addTarget:self action:#selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
[segment setTitleTextAttributes:#{NSFontAttributeName :[UIFont fontWithName:#"HelveticaNeue" size:17.0], NSForegroundColorAttributeName : [UIColor darkGrayColor] } forState:UIControlStateNormal];
[segment setTitleTextAttributes:#{NSFontAttributeName : [UIFont fontWithName:#"HelveticaNeue" size:17.0],NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];
If your not setting title textattribute as above then you can use below code
// ********** if titletextattributes are not set then below method works ***********
for(uint i=0;i<[segment subviews].count;i++)
{
for(UIView *view in [[[segment subviews] objectAtIndex:i] subviews])
{
if([view isKindOfClass:[UILabel class]])
{
[(UILabel*)view setNumberOfLines:0];
[(UILabel*)view setAdjustsFontSizeToFitWidth:YES];
[(UILabel*)view setMinimumScaleFactor:0.7];
}
}
}
You can adjust single segment's size as per it's content by below code,
//*************** adjust single segment size as per content
segment.apportionsSegmentWidthsByContent = YES;
Try this, I hope this will help you and you will get an idea how this works-
I have a UISegmentedControl i.e. _userProfileSagmentOutlet having three segments. Here is sample code-
CGFloat fontSize = 15;
[_userProfileSagmentOutlet setTitleTextAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Roboto-medium" size:fontSize],
NSForegroundColorAttributeName:[UIColor whiteColor]}
forState:UIControlStateSelected];
[_userProfileSagmentOutlet setTitleTextAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Roboto-medium" size:fontSize],
NSForegroundColorAttributeName:[UIColor whiteColor]}
forState:UIControlStateNormal];
this is the previous code which truncate tail of title like below image-
here is the main logic which fit each title in segments with same font size-
CGFloat fontSize = 15;
NSAttributedString* firstTitle = [[NSAttributedString alloc] initWithString:#"Membership History" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
NSAttributedString* secondTitle = [[NSAttributedString alloc] initWithString:#"Event History" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
NSAttributedString* thirdTitle = [[NSAttributedString alloc] initWithString:#"Booked Classes" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
float maxW=MAX(MAX(firstTitle.size.width, secondTitle.size.width), thirdTitle.size.width);
while (maxW > _userProfileSagmentOutlet.subviews[0].frame.size.width) {
fontSize--;
firstTitle = [[NSAttributedString alloc] initWithString:#"Membership History" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
secondTitle = [[NSAttributedString alloc] initWithString:#"Event History" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
thirdTitle = [[NSAttributedString alloc] initWithString:#"Booked Classes" attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Roboto-medium" size:fontSize]}];
maxW=MAX(MAX(firstTitle.size.width, secondTitle.size.width), thirdTitle.size.width);
}
[_userProfileSagmentOutlet setTitleTextAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Roboto-medium" size:fontSize],
NSForegroundColorAttributeName:[UIColor whiteColor]}
forState:UIControlStateSelected];
[_userProfileSagmentOutlet setTitleTextAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Roboto-medium" size:fontSize],
NSForegroundColorAttributeName:[UIColor whiteColor]}
forState:UIControlStateNormal];
after using this code image look like this(same font size and text fit to segment and works fine)-
Here is Swift extension if someone needed-
var fontSize:CGFloat = 15.0;
var firstTitle = NSMutableAttributedString.init(string: "Membership History", attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)])
var secondTitle = NSMutableAttributedString.init(string: "Events History" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);
var thirdTitle = NSMutableAttributedString.init(string: "Booked Classes" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);
var maxW:CGFloat = max(max(firstTitle.size().width, secondTitle.size().width), thirdTitle.size().width);
while (maxW > userProfileSagmentOutlet.subviews[0].frame.size.width) {
fontSize--;
firstTitle = NSMutableAttributedString.init(string: "Membership History", attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)])
secondTitle = NSMutableAttributedString.init(string: "Events History" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);
thirdTitle = NSMutableAttributedString.init(string: "Booked Classes" ,attributes:[NSFontAttributeName: UIFont.systemFontOfSize(fontSize)]);
maxW = max(max(firstTitle.size().width, secondTitle.size().width), thirdTitle.size().width);
}
userProfileSagmentOutlet.setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(fontSize),NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Normal)
userProfileSagmentOutlet.setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(fontSize),NSForegroundColorAttributeName:UIColor.whiteColor()], forState:UIControlState.Selected)
SWIFT 4
allow multiple lines in label
if #available(iOS 9.0, *) {
UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).numberOfLines = 0
}
The most simple solution in modern Swift would be
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
_ = Your_UISegmentControl.subviews.compactMap { $0.subviews.compactMap {
($0 as? UILabel)?.adjustsFontSizeToFitWidth = true
($0 as? UILabel)?.minimumScaleFactor = 0.5
}}
}
I ran this in the view controller, and called it after viewDidAppear
func autoshrinkSegmentFontSize() {
for subview in segments.subviews {
for label in subview.subviews {
if let myLabel = subview as? UILabel {
myLabel.adjustsFontSizeToFitWidth = true
myLabel.minimumScaleFactor = 0.5
}
}
}
}
I want to change the color of the text in my button to be blue on load. I also need only the first 9 letters (length of userName) of the buttons text to be blue, not all of the text. How do I do this?
Example:
This above image shows "#LisaLisa is following you". This is the buttons text. How do I make just "#LisaLisa" to be blue, with "is following you" staying black?
UIButton *someButton = [UIButton buttonWithType:UIButtonTypeSystem];
NSString *someUsername = #"#LisaLisa";
NSString *buttonText = [NSString stringWithFormat:#"%# is following you.", someUsername];
NSRange rangeToHighlight = [buttonText rangeOfString:someUsername];
NSDictionary *defaultAttributes = #{NSForegroundColorAttributeName: [UIColor blackColor]};
NSDictionary *highlightedAttributes = #{NSForegroundColorAttributeName: [UIColor blueColor]};
NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:buttonText attributes:defaultAttributes];
[attributedTitle addAttributes:highlightedAttributes range:rangeToHighlight];
[someButton setAttributedTitle:attributedTitle forState:UIControlStateNormal];
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
UIColor *color1 = [UIColor redColor];
UIColor *color2 = [UIColor blueColor];
UIFont *font1 = [UIFont fontWithName:#"HelveticaNeue" size:20.0f];
UIFont *font2 = [UIFont fontWithName:#"HelveticaNeue-Light" size:20.0f];
NSDictionary *dict1 = #{NSFontAttributeName:font1,
NSForegroundColorAttributeName:color1 }; // Added line
NSDictionary *dict2 = #{NSFontAttributeName:font2,
NSForegroundColorAttributeName:color2 }; // Added line
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:senderName attributes:dict1]];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:#"posted to" attributes:dict2]];
[cell.profileIDButton setAttributedTitle:attString forState:UIControlStateNormal];
[[cell.profileIDButton titleLabel] setNumberOfLines:0];
[[cell.profileIDButton titleLabel] setLineBreakMode:NSLineBreakByWordWrapping];
This answer worked for me. I wasnt able to test Andre's answers yet.
UILabel * myLabel = [[UILabel alloc] init];//used for whole string
myLabel.numberOfLines = 0;
NSString * myUserName = #"#LisaLisa";//used for userName
//add button on UserName
UIButton * muButton = [[UIButton alloc] init];
myLabel.text = [NSString stringWithFormat:#"%#", myUserName];
myLabel = [self setDynamicLableFrame:myLabel fontSize:fontSize Width:width];
//Here width is your Label's Width. Because we have to make sure that our, our label's width is not greater than our device's width and fontSize is label's fontSize
muButton.frame = myLabel.frame;
myLabel.text = [NSString stringWithFormat:#"%# is following you", myUserName];
myLabel = [self setDynamicLableFrame:myLabel fontSize:fontSize Width:width];//used for making dynamic height of label
//For changing color of UserName
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString: myLabel.attributedText];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0, myUserName.length)];
[myLabel setAttributedText: text];
Following method is used for making label's Dynamic Height & Width. Because we have to set Button's frame only on UserName ("LisaLisa").
//for setting the dynamic height of labels
-(UILabel *)setDynamicLableFrame:(UILabel*)myLabel fontSize:(float)size Width:(float)Width
{
CGSize possibleSize = [myLabel.text sizeWithFont:[UIFont fontWithName:REGULER_FONT size:size] constrainedToSize:CGSizeMake(300, 9999) lineBreakMode:NSLineBreakByWordWrapping];
CGRect newFrame = myLabel.frame;
newFrame.size.height = possibleSize.height;
if (possibleSize.width < Width) {
newFrame.size.width = possibleSize.width;
}else{
newFrame.size.width = Width;
}
myLabel.frame = newFrame;
return myLabel;
}
Hope, This is what you're looking for. Any concern get back to me.
I'm pretty sure this is actually a UIKit bug but want to get some input to see if I'm missing something silly here.
Here is the code I have:
// single line with modified line spacing and 2 colors - broken, line spacing is added to the bottom!
UILabel *brokenLabel = [[UILabel alloc] init];
brokenLabel.backgroundColor = [UIColor greenColor];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"Just some text"];
[attributedString addAttributes:#{NSForegroundColorAttributeName : [UIColor redColor]} range:[attributedString.string rangeOfString:#"text"]];
attributedString = attributedStringFromAttributedStringWithLineSpacing(attributedString, 20, NSTextAlignmentCenter);
brokenLabel.attributedText = attributedString;
[brokenLabel sizeToFit];
brokenLabel.frame = CGRectOffset(brokenLabel.frame, 50, 100);
[self.view addSubview:brokenLabel];
// end
// single line with modified line spacing and 1 color - correct
UILabel *workingLabel = [[UILabel alloc] init];
workingLabel.backgroundColor = [UIColor greenColor];
attributedString = [[NSMutableAttributedString alloc] initWithString:#"Just some text"];
attributedString = attributedStringFromAttributedStringWithLineSpacing(attributedString, 20, NSTextAlignmentCenter);
workingLabel.attributedText = attributedString;
[workingLabel sizeToFit];
workingLabel.frame = CGRectOffset(workingLabel.frame, 200, 100);
[self.view addSubview:workingLabel];
//end
// multiple lines with modified line spacing and 1 color - correct
UILabel *workingLabel2 = [[UILabel alloc] init];
workingLabel2.frame = CGRectMake(0, 0, 100, 0);
workingLabel2.numberOfLines = 0;
workingLabel2.backgroundColor = [UIColor greenColor];
attributedString = [[NSMutableAttributedString alloc] initWithString:#"Just some text"];
attributedString = attributedStringFromAttributedStringWithLineSpacing(attributedString, 20, NSTextAlignmentCenter);
workingLabel2.attributedText = attributedString;
[workingLabel2 sizeToFit];
workingLabel2.frame = CGRectOffset(workingLabel2.frame, 50, 300);
[self.view addSubview:workingLabel2];
//end
// multiple lines with modified line spacing and 2 color - correct
UILabel *workingLabel3 = [[UILabel alloc] init];
workingLabel3.frame = CGRectMake(0, 0, 100, 0);
workingLabel3.numberOfLines = 0;
workingLabel3.backgroundColor = [UIColor greenColor];
attributedString = [[NSMutableAttributedString alloc] initWithString:#"Just some text"];
[attributedString addAttributes:#{NSForegroundColorAttributeName : [UIColor redColor]} range:[attributedString.string rangeOfString:#"text"]];
attributedString = attributedStringFromAttributedStringWithLineSpacing(attributedString, 20, NSTextAlignmentCenter);
workingLabel3.attributedText = attributedString;
[workingLabel3 sizeToFit];
workingLabel3.frame = CGRectOffset(workingLabel3.frame, 200, 300);
[self.view addSubview:workingLabel3];
along with a simple convenience function to change the lineSpacing of an attributed string:
NSMutableAttributedString *attributedStringFromAttributedStringWithLineSpacing(NSAttributedString *string, CGFloat lineSpacing, NSTextAlignment textAlignment)
{
NSMutableAttributedString *mutable = string.mutableCopy;
NSMutableParagraphStyle *par = [NSMutableParagraphStyle new];
par.alignment = textAlignment;
par.lineSpacing = lineSpacing;
[mutable addAttributes:#{NSParagraphStyleAttributeName : par} range:NSMakeRange(0, mutable.length)];
return mutable;
}
However, this is what it looks like
As you can see, the height of the first label is way too big (or the height that it should be + my custom line spacing, to be precise). When simply adding another color to the first attributed string, it causes the sizeToFit size to increase by adding the lineSpacing below it. I also tried using the boundingRectWithSize: methods on the strings directly and the same issue is visible. So this is not specific to the label sizing code but is an issue with the strings themselves. I don't see any possible reason why this should be happening. Does anyone have any insight?
In your Attributes Dictionary add
[attrDic setObject:#0 forKey:NSBaselineOffsetAttributeName];
For some reason this code (the bold text in particular) doesn't change the line spacing of the text at all:
UIFont* customFont = [UIFont fontWithName:#"BebasNeue" size:70];
NSString * text = #"Their \nIdeas";
**NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];
NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];
paragrahStyle.lineSpacing = 30;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [text length])];**
UILabel *lbl1 = [[UILabel alloc] init];
[lbl1 setFrame:CGRectMake(120, 70, viewWidth, 180)];
lbl1.backgroundColor = [UIColor clearColor];
lbl1.textColor = grayColor;
lbl1.numberOfLines = 2;
lbl1.attributedText = attributedString;
lbl1.userInteractionEnabled = NO;
lbl1.text = text;
[lbl1 setFont:customFont];
[view addSubview:lbl1];
[lbl1 setTransform:CGAffineTransformMakeRotation(0.35)];
What am I doing wrong?
The issue is with this line ,
lbl1.text = text;
You are assigning a non attributed string just after assigning the attributed string which contains all line spacing data. Remove above line then your code will work.
And if you are using a large value for line spacing, make sure your label's height is enough to display the second line.