boundingRectWithSize不复制UITextView [英] boundingRectWithSize not replicating UITextView
问题描述
我在项目中的要求是 UITextView
的字体大小应该根据 UITextView
的内容减少。所以我想用 boundingRectWithSize
来估算文本的大小。
My requirement in a project is that the font size of the UITextView
should decrease according the content of the UITextView
. So i am trying to do estimate the size of the text using boundingRectWithSize
.
问题是我得到的字体有点太大,文本的某些部分会被剪裁。
The problem is that the font size I get is a bit too big and some part of the text does get clipped.
我的功能:
-(BOOL)updateTextViewFontSizeForText:(NSString*)text{
float fontSize = self.maximumFontSizeInPoints;
self.font = [self.font fontWithSize:fontSize];
CGSize tallerSize ;
CGSize stringSize ;
do
{
if (fontSize <= self.minimumFontSizeInPoints) // it just won't fit
return NO;
fontSize -= 1.0;
self.font = [self.font fontWithSize:fontSize];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = @{ NSFontAttributeName: self.font, NSParagraphStyleAttributeName : paragraphStyle };
tallerSize = CGSizeMake(self.frame.size.width,self.frame.size.height-16);// the 16 is given because uitextview adds some offset
stringSize = [text boundingRectWithSize:CGSizeMake(self.contentSize.width,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
}while(stringSize.height >= tallerSize.height);
if ([self.onTextChangDelegate respondsToSelector:@selector(onTextChangDelegate)]) {
[self.onTextChangDelegate onTextChanged:text];
}
return YES;
}
推荐答案
我遇到了同样的问题当试图做同样的事情时。
I ran into the same issue when trying to do the same thing.
问题是 UITextView
与boundingRectWithSize相比如何运行它的换行符。您可以在此处阅读更多详细信息: https:// developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Concepts/CalcTextLayout.html
The issue is how UITextView
run's its line-breaks compared to boundingRectWithSize. You can read more details here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Concepts/CalcTextLayout.html
但你实际上可以算出确切的大小!基本上有两个 UITextView
的属性,为了获得正确的大小估计,您需要考虑这两个属性。第一个是 textContainer.lineFragmentPadding
,第二个是 textContainerInset
。
But you can actually calculate the exact size! There are basically two properties of a UITextView
that you'll need to take into account in order to get correct size estimates. The first is textContainer.lineFragmentPadding
, the second is textContainerInset
.
首先, textContainer.lineFragmentPadding
:您可能已经注意到您的尺寸通常始终是 10px
,这是因为系统默认值为 5px
。当您计算估计的大小时,您需要从您检查的大小中减去此值,并在获得最终值时将其重新添加。
First, textContainer.lineFragmentPadding
: You may have noticed that your sizing is generally always off by 10px
, this is because the systems default value is 5px
. When you're calculating your estimated size, you'll need to subtract this value from the size you're checking against and add it back when you have your final value.
其次, textContainerInset
。这是一个 UIEdgeInset
,您需要将其添加回最终计算值以匹配系统。
Second, textContainerInset
. This is a UIEdgeInset
that you'll need to add back to your final calculated value to match the systems.
这是基于我如何解决问题的代码:
This is code based on how I solved the issue:
- (CGSize)sizeThatFits:(CGSize)size
CGFloat lineFragmentPaddings = self.textContainer.lineFragmentPadding * 2;
CGFloat horzPadding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings;
CGFloat vertPadding = self.textContainerInset.top + self.textContainerInset.bottom;
size.width -= horzPadding;
CGRect boundingRect = [attributedText boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin context:nil];
size = boundingRect.size;
// I found through debugging that adding 0.25 rounded
// matches sizeThatFits: identically. Not sure why…
size.width += horzPadding + 0.25;
size.height += vertPadding + 0.25;
size = CGSizeRound(size);
return size;
}
注意, CGSizeRound
只是我编写的一个自定义函数,用于围绕 CGSize的
width
和 height
code>到最近的 0.5
。
Note, CGSizeRound
is just a custom function I wrote that rounds the width
and height
of the CGSize
to the nearest 0.5
.
为了比较,如果你创建第二个 UITextView
,并确保 textContainer.lineFragmentPadding
和 textContainerInset
相同,您应该看到几乎与最近的 0.5
相同的值。
For comparison, if you create a second UITextView
, and make sure the textContainer.lineFragmentPadding
and textContainerInset
are the same, you should see the values almost identical to the nearest 0.5
.
关于计算正确pointSize的问题,这是一些伪代码:
And to your question about calculating a proper pointSize, this is some pseudo code for that:
CGFloat pointSize = 64;
CGFloat minPointSize = 32;
CGFloat decrementor = 4;
CGFloat padding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings;
CGFloat actualWidth = self.maxTextViewSize.width - padding * 2;
CGRect boundingRect = CGRectZero;
BOOL isValidPointSize = NO;
do {
if (pointSize < minPointSize) {
pointSize = minPointSize;
boundingRect.size.height = self.maxTextViewSize.height;
isValidPointSize = YES;
} else {
NSDictionary *defaultAttributes = [self.customTextStorage defaultAttributesForPointSize:pointSize];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string attributes:defaultAttributes];
boundingRect = [attrString boundingRectWithSize:CGSizeMake(actualWidth, 1024) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
// is the height to big?
if (boundingRect.size.height > self.maxTextViewSize.height) {
// reduce the point size for next iteration of loop
pointSize -= decrementor;
}
// passes height test
else {
isValidPointSize = YES;
}
}
} while (!isValidPointSize);
return pointSize;
再次,上面是基于我的实现的伪代码(不仅仅意味着替换掉什么你有)。希望这有帮助!
Again, the above is pseudo code based on my implementation (not meant for just drop in replacement for what you have). Hope this helps!
这篇关于boundingRectWithSize不复制UITextView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!