如何在 iOS 7.0 或更高版本中获得自动调整的字体大小?
How do I get auto-adjusted font size in iOS 7.0 or later?
我想获取某些文本在 UILabel 或 UITextField 中缩小后的字体大小。这在 iOS 7.0 之前是可能的:How to get UILabel (UITextView) auto adjusted font size?。但是,iOS 7.0 中已弃用 sizeWithFont。我试过使用它的替代品 sizeWithAttributes,但没有成功。在 iOS 7.0 中有什么方法可以做到这一点吗?
在应用文本后检查(可能先强制重新加载视图)您可以获取字体大小。例如,对于 UITextField,您可以实现 textDidChange 的委托方法,然后从 textField 的字体属性中找出字体大小。对于标签,您可以更新文本然后检查字体大小。
示例我构建了一个从 UITextField 更新 UILabel 的项目
-(void)textFieldDidEndEditing:(UITextField *)textField{
self.label.text = textField.text;
CGSize initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
while ( initialSize.width > _label.frame.size.width ) {
[_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
}
CGFloat actualSize = _label.font.pointSize;
NSLog(@"acutal size %f",actualSize );
}
actualSize 似乎是正确的。 (size calculation source)
这是我为获取 UILabel 的调整字体大小而创建的函数:
Swift
func getApproximateAdjustedFontSizeWithLabel(label: UILabel) -> CGFloat {
if label.adjustsFontSizeToFitWidth == true {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
else {
return label.font.pointSize
}
}
Objective-C
- (CGFloat)getApproximateAdjustedFontSizeWithLabel:(UILabel *)label {
if (label.adjustsFontSizeToFitWidth) {
UIFont *currentFont = label.font;
CGFloat originalFontSize = currentFont.pointSize;
CGSize currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
while (currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor)) {
currentFont = [currentFont fontWithSize:currentFont.pointSize - 1];
currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
}
return currentFont.pointSize;
}
else {
return label.font.pointSize;
}
}
我很喜欢@WaltersGE1 的回答,所以我把它做成了 UILabel 的扩展,使用起来更方便:
extension UILabel {
/// The receiver’s font size, including any adjustment made to fit to width. (read-only)
///
/// If `adjustsFontSizeToFitWidth` is not `true`, this is just an alias for
/// `.font.pointSize`. If it is `true`, it returns the adjusted font size.
///
/// Derived from: [
var fontSize: CGFloat {
get {
if adjustsFontSizeToFitWidth {
var currentFont: UIFont = font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > frame.size.width && currentFont.pointSize > (originalFontSize * minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
return font.pointSize
}
}
}
目前所有的解决方案都采用整数字体大小并且不符合 UILabel
的 minimumScaleFactor
属性.
像这样的东西应该可以工作:
+ (CGFloat)fontSizeForLabel:(UILabel *)label
{
if (label.adjustsFontSizeToFitWidth == NO || label.minimumScaleFactor >= 1.f) {
// font adjustment is disabled
return label.font.pointSize;
}
CGSize unadjustedSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
CGFloat scaleFactor = label.frame.size.width / unadjustedSize.width;
if (scaleFactor >= 1.f) {
// the text already fits at full font size
return label.font.pointSize;
}
// Respect minimumScaleFactor
scaleFactor = MAX(scaleFactor, minimumScaleFactor);
CGFloat newFontSize = label.font.pointSize * scaleFactor;
// Uncomment this if you insist on integer font sizes
//newFontSize = floor(newFontSize);
return newFontSize;
}
Swift 4
上面的答案很有效,但使用了一些已弃用的 values/functions。这是 2018 年可用的固定版本。
func approximateAdjustedFontSizeWithLabel(_ label: UILabel) -> CGFloat {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.withSize(currentFont.pointSize - 1.0)
currentSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
}
return currentFont.pointSize
}
我想获取某些文本在 UILabel 或 UITextField 中缩小后的字体大小。这在 iOS 7.0 之前是可能的:How to get UILabel (UITextView) auto adjusted font size?。但是,iOS 7.0 中已弃用 sizeWithFont。我试过使用它的替代品 sizeWithAttributes,但没有成功。在 iOS 7.0 中有什么方法可以做到这一点吗?
在应用文本后检查(可能先强制重新加载视图)您可以获取字体大小。例如,对于 UITextField,您可以实现 textDidChange 的委托方法,然后从 textField 的字体属性中找出字体大小。对于标签,您可以更新文本然后检查字体大小。
示例我构建了一个从 UITextField 更新 UILabel 的项目
-(void)textFieldDidEndEditing:(UITextField *)textField{
self.label.text = textField.text;
CGSize initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
while ( initialSize.width > _label.frame.size.width ) {
[_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
}
CGFloat actualSize = _label.font.pointSize;
NSLog(@"acutal size %f",actualSize );
}
actualSize 似乎是正确的。 (size calculation source)
这是我为获取 UILabel 的调整字体大小而创建的函数:
Swift
func getApproximateAdjustedFontSizeWithLabel(label: UILabel) -> CGFloat {
if label.adjustsFontSizeToFitWidth == true {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
else {
return label.font.pointSize
}
}
Objective-C
- (CGFloat)getApproximateAdjustedFontSizeWithLabel:(UILabel *)label {
if (label.adjustsFontSizeToFitWidth) {
UIFont *currentFont = label.font;
CGFloat originalFontSize = currentFont.pointSize;
CGSize currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
while (currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor)) {
currentFont = [currentFont fontWithSize:currentFont.pointSize - 1];
currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
}
return currentFont.pointSize;
}
else {
return label.font.pointSize;
}
}
我很喜欢@WaltersGE1 的回答,所以我把它做成了 UILabel 的扩展,使用起来更方便:
extension UILabel {
/// The receiver’s font size, including any adjustment made to fit to width. (read-only)
///
/// If `adjustsFontSizeToFitWidth` is not `true`, this is just an alias for
/// `.font.pointSize`. If it is `true`, it returns the adjusted font size.
///
/// Derived from: [
var fontSize: CGFloat {
get {
if adjustsFontSizeToFitWidth {
var currentFont: UIFont = font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > frame.size.width && currentFont.pointSize > (originalFontSize * minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
return font.pointSize
}
}
}
目前所有的解决方案都采用整数字体大小并且不符合 UILabel
的 minimumScaleFactor
属性.
像这样的东西应该可以工作:
+ (CGFloat)fontSizeForLabel:(UILabel *)label
{
if (label.adjustsFontSizeToFitWidth == NO || label.minimumScaleFactor >= 1.f) {
// font adjustment is disabled
return label.font.pointSize;
}
CGSize unadjustedSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
CGFloat scaleFactor = label.frame.size.width / unadjustedSize.width;
if (scaleFactor >= 1.f) {
// the text already fits at full font size
return label.font.pointSize;
}
// Respect minimumScaleFactor
scaleFactor = MAX(scaleFactor, minimumScaleFactor);
CGFloat newFontSize = label.font.pointSize * scaleFactor;
// Uncomment this if you insist on integer font sizes
//newFontSize = floor(newFontSize);
return newFontSize;
}
Swift 4
上面的答案很有效,但使用了一些已弃用的 values/functions。这是 2018 年可用的固定版本。
func approximateAdjustedFontSizeWithLabel(_ label: UILabel) -> CGFloat {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.withSize(currentFont.pointSize - 1.0)
currentSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
}
return currentFont.pointSize
}