I have an addition to NSString
which automatically resizes a UILabel
depending on the text that's being read into it (I have a simple app showing quotations, so some are a few words, some a couple sentences). Below that quote
label, I also have an author
label, which (oddly enough) has the author of the quote in it.
I'm trying to position that author
label directly beneath the quote
label (as in, its y
coordinate would be the quote
label's y
coordinate plus the quote
label's height
. What I'm seeing is some space being placed between the two labels, that depending on the length of the quote, changes size. Smaller quotes have more space, while longer quotes have less space. Here's a quick diagram of what I'm seeing:
Note the gap between the red and blue boxes (which I've set up using layer.borderColor/borderWidth
so I can see them in the app), is larger the shorter the quote is.
If anyone can sift through the code below and help point me towards exactly what's causing the discrepancy, I'd be really grateful. From what I can see, the author
label should always be 35 pixels beneath the quote
label's y + height
value.
Just to confirm: everything is hooked up correctly in Interface Builder, etc. The content of the quote's getting in there fine, everything else works, so it's hooked up, that isn't the issue.
To clarify, my question is: Why is the gap between the labels changing dependant on the quote's length, and how can I get a stable, settable gap of 35 pixels correctly?
Here's the code I'm using to position the labels:
// Fill and format Quote Details
_quoteLabel.text = [NSString stringWithFormat:@"\"%@\"", _selectedQuote.quote];
_authorLabel.text = _selectedQuote.author;
[_quoteLabel setFont: [UIFont fontWithName: kScriptFont size: 28.0f]];
[_authorLabel setFont: [UIFont fontWithName: kScriptFontAuthor size: 30.0f]];
// Automatically resize the label, then center it again.
[_quoteLabel sizeToFitMultipleLines];
[_quoteLabel setFrame: CGRectMake(11, 11, 298, _quoteLabel.frame.size.height)];
// Position the author label below the quote label, however high it is.
[_authorLabel setFrame: CGRectMake(11, 11 + _quoteLabel.frame.size.height + 35, _authorLabel.frame.size.width, _authorLabel.frame.size.height)];
Here's my custom method for sizeToFitMultipleLines
:
- (void) sizeToFitMultipleLines
{
if (self.adjustsFontSizeToFitWidth) {
CGFloat adjustedFontSize = [self.text fontSizeWithFont: self.font constrainedToSize: self.frame.size minimumFontSize: self.minimumScaleFactor];
self.font = [self.font fontWithSize: adjustedFontSize];
}
[self sizeToFit];
}
And here's my fontSizeWithFont:constrainedToSize:minimumFontSize:
method:
- (CGFloat) fontSizeWithFont: (UIFont *) font constrainedToSize: (CGSize) size minimumFontSize: (CGFloat) minimumFontSize
{
CGFloat fontSize = [font pointSize];
CGFloat height = [self sizeWithFont: font constrainedToSize: CGSizeMake(size.width, FLT_MAX) lineBreakMode: NSLineBreakByWordWrapping].height;
UIFont *newFont = font;
// Reduce font size while too large, break if no height (empty string)
while (height > size.height && height != 0 && fontSize > minimumFontSize) {
fontSize--;
newFont = [UIFont fontWithName: font.fontName size: fontSize];
height = [self sizeWithFont: newFont constrainedToSize: CGSizeMake(size.width, FLT_MAX) lineBreakMode: NSLineBreakByWordWrapping].height;
};
// Loop through words in string and resize to fit
for (NSString *word in [self componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]) {
CGFloat width = [word sizeWithFont: newFont].width;
while (width > size.width && width != 0 && fontSize > minimumFontSize) {
fontSize--;
newFont = [UIFont fontWithName: font.fontName size: fontSize];
width = [word sizeWithFont: newFont].width;
}
}
return fontSize;
}
After you called size to fit on both labels, calculate the distance between their frames and change them accordingly:
[quoteLabel sizeToFit];
[authorLabel sizeToFit];
float distance = authorLabel.frame.origin.y - quoteLabel.frame.size.height;
float difference = distance - 35;
authorLabel.frame = CGRectMake(authorLabel.frame.origin.x,(authorLabel.frame.origin.y - difference),authorLabel.frame.size.width,authorLabel.frame.size.height);
The reason the gap changes is that the quote label frame changes its height dependent on its content when you call sizeToFit.
UPDATE
Given the recent developments in the comments, I think you have 3 possibilities: