Resize font size to fill UITextView?

2019-01-08 19:05发布

问题:

How would I set the font size of text in a UITextView such that it fills the entire UITextView? I'd like the user to type in their text, then have the text fill the entire UITextView.

Any help is appreciated!

回答1:

I have converted dementiazz's answer to Swift:

func updateTextFont() {
    if (textView.text.isEmpty || CGSizeEqualToSize(textView.bounds.size, CGSizeZero)) {
        return;
    }

    let textViewSize = textView.frame.size;
    let fixedWidth = textViewSize.width;
    let expectSize = textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT)));

    var expectFont = textView.font;
    if (expectSize.height > textViewSize.height) {
        while (textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT))).height > textViewSize.height) {
            expectFont = textView.font!.fontWithSize(textView.font!.pointSize - 1)
            textView.font = expectFont
        }
    }
    else {
        while (textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT))).height < textViewSize.height) {
            expectFont = textView.font;
            textView.font = textView.font!.fontWithSize(textView.font!.pointSize + 1)
        }
        textView.font = expectFont;
    }
}


回答2:

This, in a category on UITextView, should do the trick. For why you need the fudgefactor, see this post

#define kMaxFieldHeight 9999 

-(BOOL)sizeFontToFit:(NSString*)aString minSize:(float)aMinFontSize maxSize:(float)aMaxFontSize 
{   
float fudgeFactor = 16.0;
float fontSize = aMaxFontSize;

self.font = [self.font fontWithSize:fontSize];

CGSize tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

while (stringSize.height >= self.frame.size.height)
       {
       if (fontSize <= aMinFontSize) // it just won't fit
           return NO;

       fontSize -= 1.0;
       self.font = [self.font fontWithSize:fontSize];
       tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
       stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
       }

return YES; 
}


回答3:

Similar approach to Arie Litovsky's answer but without sub-classing (or use of a category) and not using contentSize which didn't return the correct height of the rendered text for me. Tested on iOS 7:

while (((CGSize) [_textView sizeThatFits:_textView.frame.size]).height > _textView.frame.size.height) {
    _textView.font = [_textView.font fontWithSize:_textView.font.pointSize-1];
}

The approach is to keep reducing the font size until the text just fits inside the frame of the text view.

If you were going to use this in production you would still need to:

  • Handle the case where even with the smallest-possible font size the text still won't fit.
  • Use a similar approach to increase the font size if you would also like to scale text up to fit the frame.


回答4:

Try this, it's a lot simpler:

while (self.contentSize.height > self.frame.size.height)
{
    self.font = [self.font fontWithSize:self.font.pointSize -1];
}


回答5:

Here is my sample code. Basically, I check the expect size to know if font size need to increase or decrease. You need to add UITextViewDelegate to your class to make sure it workings

- (void)updateTextFont:(UITextView *)textView
{
    // Only run if has text, otherwise it will make infinity loop
    if (textView.text.length == 0 || CGSizeEqualToSize(textView.bounds.size, CGSizeZero)) return;

    /*
     - Update textView font size
     If expectHeight > textViewHeight => descrease font size n point until it reach textViewHeight
     If expectHeight < textViewHeight => inscrease font size n point until it reach textViewHeight
     */
    CGSize textViewSize = textView.frame.size;
    CGFloat fixedWidth = textViewSize.width;
    CGSize expectSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];

    UIFont *expectFont = textView.font;
    if (expectSize.height > textViewSize.height) {
        while ([textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)].height > textViewSize.height) {
            expectFont = [textView.font fontWithSize:(textView.font.pointSize-1)];
            textView.font = expectFont;
        }
    } else {
        while ([textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)].height < textViewSize.height) {
            expectFont = textView.font;
            textView.font = [textView.font fontWithSize:(textView.font.pointSize+1)];
        }
        textView.font = expectFont;
    }
}


回答6:

This property is only available on UITextFields. To do this in a UITextView, you'd have to constantly watch the text and manually adjust the font size as that changed.



回答7:

I have converted dementiazz's & Matt Frear's answer to Swift 3:

func updateTextFont() {
        if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
            return
        }

    let textViewSize = textView.frame.size
    let fixedWidth = textViewSize.width
    let expectSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))

    var expectFont = textView.font
    if (expectSize.height > textViewSize.height) {
        while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
            expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
            textView.font = expectFont
        }
    }
    else {
        while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
            expectFont = textView.font
            textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
        }
        textView.font = expectFont
    }
}


回答8:

for swift 3

 func updateTextFont(textView : UITextView) {


    if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
        return;
    }

    let textViewSize = textView.frame.size;
    let fixedWidth = textViewSize.width;

    let expectSize = textView.sizeThatFits(CGSize(width : fixedWidth, height : CGFloat(MAXFLOAT)));

    var expectFont = textView.font;
    if (expectSize.height > textViewSize.height) {
        while (textView.sizeThatFits(CGSize(width : fixedWidth, height : CGFloat(MAXFLOAT))).height > textViewSize.height) {
            expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
            textView.font = expectFont
        }
    }
    else {
        while (textView.sizeThatFits(CGSize(width : fixedWidth,height : CGFloat(MAXFLOAT))).height < textViewSize.height) {
            expectFont = textView.font;
            textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
        }
        textView.font = expectFont;
    }
}


回答9:

I have converted Matt Frear's answer to Swift 4.1 as extension for UITextView:

extension UITextView {
func updateTextFont() {
    if (self.text.isEmpty || self.bounds.size.equalTo(CGSize.zero)) {
        return;
    }

    let textViewSize = self.frame.size;
    let fixedWidth = textViewSize.width;
    let expectSize = self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))


    var expectFont = self.font
    if (expectSize.height > textViewSize.height) {

        while (self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
            expectFont = self.font!.withSize(self.font!.pointSize - 1)
            self.font = expectFont
        }
    }
    else {
        while (self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
            expectFont = self.font
            self.font = self.font!.withSize(self.font!.pointSize + 1)
        }
        self.font = expectFont
    }
}

}



回答10:

An updated version of @Arie Litovsky's code. This works in iOS7 and later and stretches the font size both up and down so the text fits.

- (void) stretchFontToFit:(UITextView*)textView
{

    while( textView.contentSize.height < textView.frame.size.height )
    {
        textView.font = [textView.font fontWithSize:textView.font.pointSize +1];
        [textView layoutIfNeeded];
    }

    while( textView.contentSize.height > textView.frame.size.height )
    {
        textView.font = [textView.font fontWithSize:textView.font.pointSize -1];
        [textView layoutIfNeeded];
    }
}


回答11:

In viewDidLoad:

textView.textContainer.lineFragmentPadding = 0;
textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0);

You need to add UITextViewDelegate:

- (void)updateTextFont:(UITextView *)textView {

    CGSize textViewSize = textView.frame.size;
    CGSize sizeOfText = [textView.text sizeWithAttributes:@{NSFontAttributeName: textView.font}];

    CGFloat fontOfWidth = floorf(textView.font.pointSize / sizeOfText.height * textViewSize.height);
    CGFloat fontOfHeight = floorf(textView.font.pointSize / sizeOfText.width * textViewSize.width);

    textView.font = [textView.font fontWithSize:MIN(fontOfHeight, fontOfWidth)];
}


回答12:

U can easily do this by using

  • self.textview.font =

self.textview.font = UIFont(name: self.textview.font!.fontName,
size: self.textview.frame.size.height / 10)!

divide textview.frame.size.height upon some constant based on your requirement..



回答13:

Here is a solution for Swift 4 (based on Arie Litovsky answer), you can put this code into textViewDidChange(_ textView: UITextView) delegate method :

Scaling down the font :

    while (textView.contentSize.height > textView.frame.size.height) {
        guard let fontName = textView.font?.fontName, let fontSize = textView.font?.pointSize else {return}
        if fontSize < 12 {
            return
        }
        textView.font = UIFont(name: fontName, size: fontSize - 1)
        textView.layoutIfNeeded()
    }

And scaling up the font:

        while (textView.contentSize.height < textView.frame.size.height) {
        guard let fontName = textView.font?.fontName, let fontSize = textView.font?.pointSize else {return}
        if fontSize > 15 {
            return
        }
        textView.font = UIFont(name: fontName, size: fontSize + 1)
        textView.layoutIfNeeded()
    }

You can change the fontSize < 12 and fontSize > 15 to fit your needs in minimum and maximum font size.