Scrolling to the end of UITextView's text - ios

I have some contents in a view (such as images, labels) and the last item is a description (UITextView). Now I am trying to scroll the contents dynamically based on UITextView text. Here is my code:
- (void)viewDidAppear:(BOOL)animated {
_descriptions.scrollEnabled = NO;
[_descriptions sizeToFit];
_infoScrollView.contentSize = CGSizeMake(_contentsOnInfoView.frame.size.width,
_contentsOnInfoView.frame.size.height + _descriptions.frame.size.height);
}
Here is the result:
As you can see, there is lots of empty space. I need to scroll to the end of text.

I'd suggest you to try this.
[myTextView scrollRangeToVisible:NSMakeRange([myTextView.text length], 0)]

You should write you code in
-(void) viewDidLayoutSubviews {}
In this method,All components have frame according to running device size. and execute before appear the view.

//may be it will work for you
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
//set the line break mode
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
NSDictionary *attrDict = [NSDictionary dictionaryWithObjectsAndKeys: description.font,
NSFontAttributeName,
paragraphStyle,
NSParagraphStyleAttributeName,
nil];
CGRect rect = [description.text boundingRectWithSize:CGSizeMake(description.size.width, FLT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attrDict
context:nil];
CGSize size = rect.size;
_infoScrollView.contentSize = CGSizeMake(_contentsOnInfoView.frame.size.width,description.frame.origin.y + size.height + 20)

I just found the answer,in the UI there is line that separates descriptions with the some infos ! I just calculate the line's y and sum up with the descriptions height :
_descriptions.scrollEnabled = NO;
[_descriptions sizeToFit];
_infoScrollView.contentSize = CGSizeMake(_infoView.frame.size.width, _line.frame.origin.y + _descriptions.bounds.size.height);
now it works fine !

Related

how to do truncation of text in UILabel

I have problem with truncation of text in UILabel even I have set lineBreakMode = NSLineBreakByWordWrapping perfectly.
Here is my code snippet :
lblSelectedText = [[UILabel alloc] init];
lblSelectedText.numberOfLines = 0;
lblSelectedText.lineBreakMode = NSLineBreakByWordWrapping;
lblSelectedText.font = [UIFont fontWithName:#"MyriadPro-Regular" size:(IS_IPAD_PRO?13.0:9.0)];
lblSelectedText.textAlignment = NSTextAlignmentCenter;
lblSelectedText.textColor = [UIColor lightGrayColor];
lblSelectedText.text = strKey; // Here text will be dynamic
CGFloat width = 150;
CGSize strSize = [self findHeightForText:strKey havingWidth:width andFont:lblSelectedText.font];
lblSelectedText.frame = CGRectMake(12, 10, CGRectGetWidth(aContainerController.view.frame)-20, strSize.height+15);
- (CGSize)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font
{
CGSize size = CGSizeZero;
if (text)
{
if (IS_ENGLISH) {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 10);
}
else {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 1);
}
}
return size;
}
Please note that these labels are in collection view cell. Here are some reference images.
If anyone have solution of this problem please share with me...
Thanks.
As you have mentioned in comment that some characters goes in to next line that means there is not enough width to fill every letter in single line thats why it is going to second line as you set number of line to 0(i.e. multiple lines). So there is nothing is wrong in it. It is normal behavior according to your setup made in code.
now if you want that it not goes to second line then set numberOfLines property to 1.
Another option is you can set minimunScaleFactor from 0 to 1 to resize your font to fit in available width.
You can do it something like,
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.5f;
So, It will reduce font size to half of the actual to fit it in availabel width.
And once try by changing linebreakmode to NSLineBreakByTruncatingTail also instead of NSLineBreakByWordWrapping.
Check this:-
label.minimumScaleFactor = 0.5f;
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
[label sizeToFit];

UILabel Text Multi Line given width of text

I want to scale a UILabel exactly how snapchat does. I have a textfield where I insert the text. When tapping done the textfield goes and the label's text is set. I want to insert multiple lines when the text is larger than width of screen and truncate the frame of label so that the text fits.
Here is my code
if(isCaption){
//Begin Edit Text
_textlabel.hidden = NO;
_textlabel.text = currentText;
_textFieldOutlet.hidden = YES;
[_textFieldOutlet setTextAlignment:NSTextAlignmentLeft];
[_textlabel setTextAlignment:NSTextAlignmentLeft];
[self.screenShotView bringSubviewToFront:_textlabel];
_textlabel.frame = CGRectMake(10,
_textlabel.frame.origin.y,
[currentText sizeWithAttributes:#{NSFontAttributeName:[_textlabel font]}].width,
[currentText sizeWithAttributes:#{NSFontAttributeName:[_textlabel font]}].height);
isEditing = YES;
isCaption = NO;
}
The problem is that the result is a huge line of text and I want it spreads on multiline. How can this be accomplished? How can I separate the lines given width?
If you want multiple lines you should not calculate your width with sizeWithAttributes: . You should fix your width for the label and then calculate the height with boundingRectWithSize: method.
You can create a helper method as follows:
- (CGSize)suggestedSizeWithFont:(UIFont *)font size:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode forString:(NSString *)text {
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = lineBreakMode;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text attributes:#{NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle}];
CGRect bounds = [attributedString boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin context:nil];
return bounds.size;
}
Or you can create a category and get rid of that extra text parameter.
Then you can call the method for you label's text as follows:
CGSize requiredSize = [self suggestedSizeWithFont:_textLabel.font size:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX) lineBreakMode:_textLabel.lineBreakMode forString:_textLabel.text];
_textLabel.frame = CGRectMake(0, _textlabel.frame.origin.y, requiredSize.width, requiredSize.height);
You can set the width to whatever you want your label to fit in. The height would calculated accordingly. But remember to set numberOfLines to 0.
Try to insert following line of code:
_textLabel.numberOfLines = 0;

Problems with sizes and lines in UILabel

I have a little question. I developed an application that automatically fills a data set obtained from a SQLite database. These data are drawn from dynamic way, and between the data I have a frame where I insert labels dynamically. I never know the exact number of labels inside these frame because I take data from different tables of my Database. The problem I have with the labels which texts within them do not fill within the width of the label. I tried to use label.linebreakmode but still makes the break. I post the code:
There I have many objects taken from previous code, like widthFormato and widthImageFormato
if([tipoVino length]!=0){
UILabel *lblFormato = [[UILabel alloc] init];
labelX = ((widthFormato-widthImageFormatos) / 2)+10;
CGRect labelFrame = lblFormato.frame;
labelFrame.size.width = widthImageFormatos;
labelFrame.origin.x = labelX;
labelFrame.origin.y = labelY+25;
lblFormato.frame = labelFrame;
lblFormato.numberOfLines = 0;
lblFormato.lineBreakMode = NSLineBreakByWordWrapping;
[lblFormato setText:[NSString stringWithFormat:#"- %#",tipoVino]];
lblFormato.textColor = [UIColor whiteColor];
labelY = lblFormato.frame.origin.y;
[formatosImageView addSubview:lblFormato];
}
I think that you want to create labels with flexible height (not all have the same size), and must fix the width of formatosImageView.
EDITED FOR iOS7
I was using sizeWithFont that is deprecated in iOS7, I changed it for boundingRectWithSize
Try this:
UILabel *lblFormato = [[UILabel alloc] init];
lblFormato.numberOfLines = 0;
lblFormato.lineBreakMode = NSLineBreakByWordWrapping;
[lblFormato sizeToFit];
NSString *string = [NSString stringWithFormat:#"- %#", tipoVino];
[lblFormato setText: string];
//Calculate the size of the container of the lblFormato
CGSize size = [string boundingRectWithSize:CGSizeMake(widthImageFormatos, 2000) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName: [UIFont fontWithName:#"customFont" size:fontSize]} context:nil];
lblFormato.frame = CGRectMake(labelX, labelY + 25, size.width, size.height);
and you must update the labelY with:
labelY = lblFormato.frame.size.height;
Maybe it helps you.
With regards #spinillos answer, for iOS 7:
NSDictionary *attributes = #{ NSFontAttributeName : [UIFont systemFontOfSize:<#fontSize#>] };
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
initWithString: <#string#>,
attributes:attributes];
CGRect frame = [attributedString boundingRectWithSize:CGSizeMake(<#width#>, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

UILabel shows fewer lines then expected with multiple lines mode

I'd like my UILabel to show my data in multiple lines, and the data is fetch from txt file.
I've searched online for this question, and all the answers show that I just need to set lineBreakMode to NSLineBreakByWordWrapping and numberOfLines = 0. However, the problem is that, even though I added these settings, the labels shows fewer lines than expected (my data has 4 lines, however the label only shows 2 lines). Here's my code:
-(void)updateFileContentLabel:(NSString*)content{
self.fileContentLabel.text = content;
self.fileContentLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.fileContentLabel.font = [UIFont systemFontOfSize:17.0f];
self.fileContentLabel.numberOfLines = 0;
[self.fileContentLabel sizeToFit];
NSLog(#"file Label: %#",self.fileContentLabel.text);
}
As you see, I have a NSLog to show the content of label's text. And the text of label in NSLog is correct (4 lines). However on the phone or simulator, it only shows 2 lines instead of 4. Does anyone know where is the problem? Thanks!
Probably your UILabel is just not big enough. Solutions:
1.Increase a label size.
2.Add following code to allow UILabel to decrease the font size if needed.
self.fileContentLabel.minimumScaleFactor = 0.5;
I was only able to replicate your problem when I was using auto layout and didn't have constraints set up for fileContentLabel, so check that out.
Use the following method to calculate the height of text and set the frame of label accordingly.
- (CGSize)boundingSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode
{
CGSize stringSize;
if ([self respondsToSelector:#selector(boundingRectWithSize:options:attributes:context:)]) {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = lineBreakMode;
NSDictionary * stringAttributes = #{ NSFontAttributeName: font, paragraphStyle: NSParagraphStyleAttributeName};
stringSize = [self boundingRectWithSize:size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:stringAttributes context:nil].size;
stringSize = CGSizeMake(ceil(stringSize.width), ceil(stringSize.height) + 2);
} else {
stringSize = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
}
return stringSize;
}

How to make NSStringDrawingContext shrink text?

I'm trying to use the attributed string API of iOS 6 to calculate the size of text and shrink the font size if necessary. However, I can't get it to work as the documentation says.
NSString *string = #"This is a long text that doesn't shrink as it should";
NSStringDrawingContext *context = [NSStringDrawingContext new];
context.minimumScaleFactor = 0.5;
UIFont *font = [UIFont fontWithName:#"SourceSansPro-Bold" size:32.f];
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = NSLineBreakByClipping;
NSDictionary *attributes = #{ NSFontAttributeName: font,
NSParagraphStyleAttributeName: paragraphStyle };
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:self.title attributes:attributes];
CGRect rect = [attributedString boundingRectWithSize:CGSizeMake(512.f, 512.f) options:NSStringDrawingUsesLineFragmentOrigin context:context];
NSLog(#"rect: %#, context: %#", NSStringFromCGRect(rect), context.debugDescription);
But the text doesn't shrink and is truncated. actualScaleFactor is always 1. The log results are:
rect:{{0, 0}, {431.64801, 80.447998}}, context:<NSStringDrawingContext: 0x14e85770> minimumScaleFactor:0.500000 minimumTrackingAdjustment:0.000000 actualScaleFactor:1.000000 actualTrackingAdjustment:0.000000 totalBounds:{{0, 0}, {431.64801, 80.447998}}
The result is the same if I use the actual drawing method and not the measuring method. If I remove the paragraph style, it makes the text wrap and doesn't shrink it. If I remove the paragraph style AND I choose a size that only allows one line of text, the text is truncated too instead of being shrunk. What is wrong? There is very little documentation or online resources dealing with NSStringDrawingContext. And I'm trying to avoid the use of sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: which is deprecated in iOS 7.
NSStringDrawingContext's minimumScaleFactor appears to be broken in iOS 7.
As far as I can make out, even in iOS 6, it didn't work for drawing; it worked for measuring, so you could work out what would happen in a context where it does work for drawing, like a UILabel. That way, you know the correct minimum height for the label.
Or, you could use the resulting scale factor to shrink the text yourself, in the knowledge that now it will fit.
Example:
- (void)drawRect:(CGRect)rect
{
// rect is 0,0,210,31
NSMutableAttributedString* s =
[[NSMutableAttributedString alloc] initWithString: #"This is the army Mister Jones."];
[s addAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"GillSans" size:20]}
range:NSMakeRange(0,s.length)];
NSMutableParagraphStyle* para = [[NSMutableParagraphStyle alloc] init];
para.lineBreakMode = NSLineBreakByTruncatingTail;
[s addAttributes:#{NSParagraphStyleAttributeName:para}
range:NSMakeRange(0,s.length)];
NSStringDrawingContext* con = [[NSStringDrawingContext alloc] init];
con.minimumScaleFactor = 0.5;
CGRect result =
[s boundingRectWithSize:rect.size
options:NSStringDrawingUsesLineFragmentOrigin context:con];
CGFloat scale = con.actualScaleFactor;
// ...(could have a check here to see if result fits in target rect)...
// fix font to use scale factor, and draw
[s addAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"GillSans" size:20*scale]}
range:NSMakeRange(0,s.length)];
[s drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin context:nil];
}
In iOS 6, scale is about 0.85 and you can use it as shown to shrink the text. But in iOS 7, scale remains at 1, suggesting that no shrinkage is happening and this feature of NSStringDrawingContext is now useless. I can't tell whether that's a bug or whether the feature has been deliberately abandoned.
After googling for a long time I did not find a solution working under iOS7. Right now I use the following workaround, knowing that it is very ugly. I render a UILabel in memory, take a screenshot and draw that. UILabel is able to shrink the text correctly.
But perhaps someone finds it useful.
UILabel *myLabel = [[UILabel alloc] initWithFrame:myLabelFrame];
myLabel.font = [UIFont fontWithName:#"HelveticaNeue-BoldItalic" size:16];
myLabel.text = #"Some text that is too long";
myLabel.minimumScaleFactor = 0.5;
myLabel.adjustsFontSizeToFitWidth = YES;
myLabel.backgroundColor = [UIColor clearColor];
UIGraphicsBeginImageContextWithOptions(myLabelFrame.size, NO, 0.0f);
[[myLabel layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[screenshot drawInRect:myLabel.frame];
Just wanted to post this solution as I have been battling with this for a couple hours. I could never get the text area to scale down and would always have the last lines of text cut off.
The solution for me was to not add a context and just set it to nil. I got this when looking at the example on this site. https://littlebitesofcocoa.com/144-drawing-multiline-strings
Note after getting the size the box would draw at using
pageStringSize = [myString boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrsDictionary context:nil];
I still needed to loop through scaling down the font manually:
while (pageStringSize.size.height > 140 && scale > 0.5) {
scale = scale - 0.1;
font = [UIFont fontWithName:#"Chalkboard SE" size:24.0 *scale];
attrsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName,[NSNumber numberWithFloat:1.0], NSBaselineOffsetAttributeName, nil];
pageStringSize = [myString boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrsDictionary context:nil];
}

Resources