I have to make iPad application.
There are three questions textfields. I have to set width UITextField dynamically, text is coming from webservice. and I have to set UITextField width same as questions text..
when texts question size is small then UITextField size is small,
when texts question size is large then UITextField size is large,
I have following code.....
txtQuestionOne.hidden=NO;
txtQuestionTwo.hidden=NO;
txtQuestionThree.hidden=NO;
imgQueone.hidden=NO;
imgQueTwo.hidden=NO;
imgQueThree.hidden=NO;
[txtQuestionOne setPlaceholder:[[appDelegate.questions objectAtIndex:0] objectForKey:#"question"]];
appDelegate.FirstQues =[[appDelegate.questions objectAtIndex:0] objectForKey:#"question"];
NSLog(#"current q1 %#", [[appDelegate.questions objectAtIndex:0] objectForKey:#"question"]);
if ([[[appDelegate.questions objectAtIndex:0] objectForKey:#"permission"] isEqualToString:#"1"]) {
ratingButton1.hidden=NO;
ratingLabel1.hidden=NO;
}
[txtQuestionTwo setPlaceholder:[[appDelegate.questions objectAtIndex:1] objectForKey:#"question"]];
appDelegate.SecondQues =[[appDelegate.questions objectAtIndex:1] objectForKey:#"question"];
NSLog(#"current q2 %#", [[appDelegate.questions objectAtIndex:1] objectForKey:#"question"]);
if ([[[appDelegate.questions objectAtIndex:1] objectForKey:#"permission"] isEqualToString:#"1"]) {
ratingButton2.hidden=NO;
ratingLabel2.hidden=NO;
}
[txtQuestionThree setPlaceholder:[[appDelegate.questions objectAtIndex:2] objectForKey:#"question"]];
appDelegate.ThridQues =[[appDelegate.questions objectAtIndex:2] objectForKey:#"question"];
NSLog(#"current q3 %#", [[appDelegate.questions objectAtIndex:2] objectForKey:#"question"]);
if ([[[appDelegate.questions objectAtIndex:2] objectForKey:#"permission"] isEqualToString:#"1"]) {
ratingButton3.hidden=NO;
ratingLabel3.hidden=NO;
}
Please help me i dont know what can i do?
Use this to get size for a NSString of specified font style. And use the returned CGSize to set size of UI element can be label, textfield.
(comments from apple documentation)
// Single line, no wrapping. Truncation based on the UILineBreakMode.
- (CGSize)sizeWithFont:(UIFont *)font; // Uses UILineBreakModeWordWrap
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode;
// for multi lined
// Wrapping to fit horizontal and vertical size. Text will be wrapped and truncated using the UILineBreakMode. If the height is less than a line of text, it may return
// a vertical size that is bigger than the one passed in.
// If you size your text using the constrainedToSize: methods below, you should draw the text using the drawInRect: methods using the same line break mode for consistency
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size; // Uses UILineBreakModeWordWrap;
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode;
Eg:
NSString *valueString = #"This is example";
CGSize newSize = [valueString sizeWithFont: [UIFont fontWithName: #"TrebuchetMS" size: 12] ];
// assign new size
CGRect textFrame = textbox. frame;
textFrame. size = newSize;
did you try this
CGRect frame= yourTextField.frame;
frame.size.width=your_required_width;
yourTextField.frame=frame;
Have a look at this post
It shows you the use of sizeWithFont which gives you a CGSize object from the size of your text. Then edit your textfields frame with the data of this CGSize object.
Related
I'm making my app transition to iOS 7 and have this method (already modified for iOS 7, using boundingRectWithSize...):
+ (CGSize)messageSize:(NSString*)message {
NSDictionary *attributes = #{NSFontAttributeName : [UIFont fontWithName:#"Futura-Medium" size:13]};
CGRect frame = [message boundingRectWithSize:CGSizeMake([PTSMessagingCell maxTextWidth], CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:attributes context:nil];
return frame.size;
}
I am getting this appearance:
The message UILabel is being cut. It feels like line spacing is too big. It tried many other answers I found but none of them work.
If someone knows how to help me, I appreciate! ;)
Thanks!
Try changing NSStringDrawingUsesFontLeading as your option to NSStringDrawingUsesLineFragmentOrigin.
If you were only supporting iOS 6 and iOS 7, then I would definitely change all of your NSString's sizeWithFont:... to the NSAttributeString's boundingRectWithSize. Starting in iOS 6, the NSAttributedString's NSStringDrawing functions were introduced and they're threadsafe unlike the old NSString+UIKit methods we're used to (eg. sizeWithFont:..., etc), which were UIStringDrawing functions (and act unpredictably when you use them from a non-main thread. It'll save you a lot of headache if you happen to have a weird multi-threading corner case! Here's how I converted NSString's sizeWithFont:constrainedToSize::
What used to be:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Can be replaced with:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
[[NSAttributedString alloc]
initWithString:text
attributes:#
{
NSFontAttributeName: font
}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
Please note the documentation mentions:
In iOS 7 and later, this method returns fractional sizes (in the size
component of the returned CGRect); to use a returned size to size
views, you must use raise its value to the nearest higher integer
using the ceil function.
So to pull out the calculated height or width to be used for sizing views, I would use:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
I think you are updating your label frame from either viewDidLoad or viewWillAppear, so it is not working.
if you will update frame of label from viewDidAppear method then you will get updated frame of label.
I am not sure why this is happened, I think it is iOS 7 bug.
Try this
+ (CGSize)messageSize:(NSString*)message {
CGSize nameSize = [message sizeWithFont:[UIFont fontWithName:#"Futura-Medium" size:13]
constrainedToSize:CGSizeMake(maxWidth, maxHeight) lineBreakMode:NSLineBreakByWordWrapping];
NSLog(#"width = %f, height = %f", nameSize.width, nameSize.height);
return nameSize;
}
I need to work out the height of a UITextView from the top down to the cursor. I am trimming the text it contains (so it only goes up to the cursor) and then using NSString's sizeWithFont:constrainedToSize:lineBreakMode: method to work out the height, like so:
NSRange range;
range.location = noteTextView.selectedRange.location;
range.length = noteTextView.text.length - range.location;
NSString *string = [noteTextView.text stringByReplacingCharactersInRange:range withString:#""];
CGSize size = [string sizeWithFont:noteTextView.font
constrainedToSize:noteTextView.frame.size
lineBreakMode:UILineBreakModeWordWrap];
NSLog(#"height is: %f \n", size.height);
It does this every time I type anything.
The problem is, when I watch the NSLog as I type, it doesn't register a change of height until I have typed 4 characters on the new line. It is as if the sizeWithFont method is exactly four characters out. Here's a couple of screenshots showing what I mean:
Can anyone tell me what is going on?
#Vladimir's comment is right I think - an NSString doesn't take into account the margins of a UITextField.
You could try getting the text preceding the cursor and creating a new UITextField that only contains that text.
Then if you call [tempTextField sizeToFit] on your new text field then it's bounds should be the size you are looking for.
I am using the method [string sizeWithFont:constrainedToSize:lineBreakMode:] to estimate the height of a textView that I am resizing. However, it seems to consistently return the incorrect size. To debug, I wrote the following code:
self.textView.font = [UIFont systemFontOfSize:14.0]; // It was this before, anyways
NSLog(#"Real width: %lf %lf", self.textView.contentSize.width, self.textView.frame.size.width);
NSLog(#"Real height: %lf", self.textView.contentSize.height);
NSLog(#"Estimated width: %lf", kOTMessageCellTextWidth);
NSLog(#"Estimated height: %lf", ([message.message sizeWithFont:[UIFont systemFontOfSize:14.0]
constrainedToSize:CGSizeMake(kOTMessageCellTextWidth, CGFLOAT_MAX)
lineBreakMode:UILineBreakModeWordWrap].height));
However, the above code reveals that I am getting inconsistent results:
Real width: 223.000000 223.000000
Real height: 52.000000
Estimated width: 223.000000
Estimated height: 36.000000
Real width: 223.000000 223.000000
Real height: 142.000000
Estimated width: 223.000000
Estimated height: 126.000000
Real width: 223.000000 223.000000
Real height: 142.000000
Estimated width: 223.000000
Estimated height: 126.000000
I noticed in this similar question that (apparently) textView has some padding that constrains its actual width. The recommendation there was the decrease the width passed to sizeWithFont: by some number. The recommended number was 11.
My question: is there any way to actually retrieve this value programmatically, or is there some documentation that I missed specifying this number? It seems like this number should be available and shouldn't have to be guess-and-checked, but I can't find a reliable way to identify it.
Thanks in advance.
OK, after a bit of (re)search, I've come to this.
UITextView has 8px of padding on each side. But also line-height is not the same with UILabel (and sizeWithFont methods' result)
in my case the font was Arial and the size was 16pt and line heights of textview is 4.5points more than uilabel's line heights. So;
I get the result (cSize) from sizeWithFont method, with giving width reduced by 16 pixels
I calculated the lineCount by cSize.height / font.lineHeight
and used cSize.height + (lineCount * 4.5) + 16.0 as the final height for textview
code (not the exact code):
CGSize constraintSize = CGSizeMake(250.0 - 16.0, MAXFLOAT);
CGSize labelSize = [message.text sizeWithFont:[UIFont fontWithName:#"Arial" size:16.0] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
CGFloat lineCount = labelSize.height / [UIFont fontWithName:#"Arial" size:16.0].lineHeight;
CGFloat additional = lineCount * 4.5; // for 16.0 pt Arial for now
return labelSize.height + additional + 16.0; // TextView fix
I'm still having a little problems and do not like the way i solved it. But seems ok for this problem. And It would be great if someone comes with a reasonable solution for this.
The fix is simple, since UITextView has 8px of padding on each side, so when you are calculating text's true size, you should minus this 16px padding (8px on double sides) first, then the result is right. Please see following code snippet:
// self.descView is an UITextView
// UITEXTVIEW_TEXT_PADDING is 8.0
CGSize constrainedSize = CGSizeMake(self.descView.contentSize.width-UITEXTVIEW_TEXT_PADDING*2, MAXFLOAT);
CGSize trueSize = [self.descView.text sizeWithFont:self.descView.font
constrainedToSize:constrainedSize
lineBreakMode:UILineBreakModeWordWrap];
CGSize contentSize = self.descView.contentSize;
contentSize.height = trueSize.height;
self.descView.contentSize = contentSize;
frame = self.descView.frame;
frame.size.height = contentSize.height ;
self.descView.frame = frame;
The result should be right.
NSString sizeWithFont is computed using Core Text. UITextView uses a Webview (internally) to render its contents.
This discrepancy leads to all sorts of headaches. Such as choosing to break lines at different locations — you'll notice comma delimited lists, and certain mathematical expression strings will break on different symbols between Core Text and UITextView. This often leads to out-by-one-line errors when measuring spaces for your strings to fit.
And if you want international character support — well, you can forget about Core Text line heights matching UITextView (no matter how many combinations of paragraph style and line height you try!).
I have found that the only way to reliably estimate the size for a UITextView given an NSString is to... actually construct the UITextView and read its fitted size (minus the 8px padding).
Here's a UIKitLineMetrics class that does exactly that.
It keeps two "dummy" text views. You update the instance with your desired font and layout width, and you can read the single and multi-line sizes out of it.
UIKitLineMetrics.h
#import <UIKit/UIKit.h>
#interface UIKitLineMetrics : NSObject
#property (nonatomic, strong) NSMutableAttributedString *attributedString;
- (CGSize) UIKitLineSizeForText:(NSString*)text;
- (CGSize) UIKitSingleLineSizeForText:(NSString*)text;
- (void) updateWithFont:(UIFont*)font andWidth:(CGFloat)width;
#end
UIKitLineMetrics.m
#import "UIKitLineMetrics.h"
#interface UIKitLineMetrics ()
#property (nonatomic, strong) UITextView *measuringTextView;
#property (nonatomic, strong) UITextView *measuringSingleTextView;
#end
#implementation UIKitLineMetrics
#synthesize measuringTextView;
#synthesize measuringSingleTextView;
#synthesize attributedString;
- (id) init
{
self = [super init];
if( self )
{
attributedString = [[NSMutableAttributedString alloc] init];
measuringTextView = [[UITextView alloc] initWithFrame:CGRectZero];
measuringSingleTextView = [[UITextView alloc] initWithFrame:CGRectZero];
}
return self;
}
- (CGSize) UIKitLineSizeForText:(NSString*)text
{
measuringTextView.text = [text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
CGSize sz = [measuringTextView sizeThatFits:CGSizeMake(measuringTextView.frame.size.width, CGFLOAT_MAX)];
return CGSizeMake(sz.width - 16, sz.height - 16);
}
- (CGSize) UIKitSingleLineSizeForText:(NSString*)text
{
measuringSingleTextView.text = [text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
CGSize sz = [measuringSingleTextView sizeThatFits:CGSizeMake(measuringSingleTextView.frame.size.width, CGFLOAT_MAX)];
return CGSizeMake(sz.width - 16, sz.height - 16);
}
- (void) updateWithFont:(UIFont*)font andWidth:(CGFloat)width
{
measuringTextView.font = font;
measuringSingleTextView.font = font;
measuringTextView.frame = CGRectMake(0, 0, width, 500);
measuringSingleTextView.frame = CGRectMake(0, 0, 50000, 500);
}
#end
You could try checking the contentInset value (a property of UIScrollView).
I've also struggled with the problem. I've usually gotten by by passing the sizeWithFont method a size that's smaller than the actual size of the textView. Even when adding the textview's content insets to the size, it doesn't work. The size returned is always smaller.
charlie
I use following function without much problem:
+(float) calculateHeightOfTextFromWidth:(NSString*) text: (UIFont*)withFont: (float)width :(UILineBreakMode)lineBreakMode
{
[text retain];
[withFont retain];
CGSize suggestedSize = [text sizeWithFont:withFont constrainedToSize:CGSizeMake(width, FLT_MAX) lineBreakMode:lineBreakMode];
[text release];
[withFont release];
return suggestedSize.height;
}
I know there is this one:
sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:
But since the CGSize always has the same height and doesn't adjust to any shrinked text or whatsoever, the CGSize is not telling how heigh the text is.
Example: Make a UILabel with 320 x 55 points and put a loooooooooooooong text in there. Let the label shrink the text down. Surprise: CGSize.height remains the same height even if the text is so tiny that you need a microscope.
Ok so after banging my head against my macbook pro which is half way broken now, the only think that can help is that nasty actualFontSize. But the font size is in pica I think, it's not really what you get on the screen, isn't it?
When that font size is 10, is my text really 10 points heigh at maximum? Once in a while I tried exactly that, and as soon as the text had a y or some character that extends to below (like that tail of an y does), it is out of bounds and the whole text is bigger than 10 points.
So how would you calculate the real text height for a single line uilabel without getting a long beard and some hospital experience?
Try this code:
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = #"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont
constrainedToSize:maximumSize
lineBreakMode:self.myLabel.lineBreakMode];
from my answer here
It uses a different method, and sets up a very high CGSize at the start (which is then shrunk to fit the string)
Important: As of iOS 7.0 the following method is deprecated.
sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:
Use the below code instead
CGRect frame = [cellText boundingRectWithSize:CGSizeMake(568,320) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:32.0f]} context:nil];
float height = frame.size.height;
Sounds like after you get the actual font size from that function call, you need to call again with that new size:
NSString* yourString = #"SomeString";
float actualSize;
[yourString sizeWithFont:yourFont
minFontSize:minSize
actualFontSize:&actualSize
forWidth:rectWidth
lineBreakMode:breakMode];
CGSize size = [yourString sizeWithFont:[UIFont fontWithName:fontName size:actualSize]];
Also have you set label.numberOfLines = 0; ?
After running this code frame.size will have the height and width of your nsstring exactly..
NSString *text = #"This is my Mac";
textFont = [NSFont fontWithName:#"HelveticaNeue-Medium" size: 80.f];
textColor = [NSColor yellowColor];
NSDictionary *attribs = #{ NSForegroundColorAttributeName:textColor,
NSFontAttributeName: textFont };
CGRect frame = [text boundingRectWithSize:CGSizeMake(0,0) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesDeviceMetrics attributes:attribs context:nil];
In this question I asked for a good way to truncate a string to fit a given UITextView. Since there was no way provided by the SDK directly, I've ended up writing the recursive method below (only called by the following public method). However, this doesn't work unless I subtract a fudge factor of 15 (kFudgeFactor) from the field width when calculating the string's height. If I don't do that, the string returned is actually too long for the field, and displays in an extra line below it. Anyone any idea why, and what I should really use instead of this fudge factor?
#pragma mark Size string to fit the new view
#define kFudgeFactor 15.0
#define kMaxFieldHeight 9999.0
// recursive method called by the main API
-(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax
{
if ((aMax-aMin) <= 1)
{
NSString* subString = [aString substringToIndex:aMin];
return subString;
}
int mean = (aMin + aMax)/2;
NSString* subString = [aString substringToIndex:mean];
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
if (stringSize.height <= self.frame.size.height)
return [self sizeStringToFit:aString min:mean max:aMax]; // too small
else
return [self sizeStringToFit:aString min:aMin max:mean];// too big
}
-(NSString*)sizeStringToFit:(NSString*)aString
{
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
// if it fits, just return
if (stringSize.height < self.frame.size.height)
return aString;
// too big - call the recursive method to size it
NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]];
return smallerString;
}
UIScrollView seems to use a fixed 8-pixel inset on both sides. This is independent of alignment or font size (based on testing & observation, not any explicit knowledge of the internals).
So it seems you are right to use your fudge factor, but it should probably be 16.0, not 15.0.
This is probably because the frame of the UIView is not the same size as the content view.
UITextView subclasses from UIScrollView.