Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize font size in UITextView

Is there a way to shrink the font-size in a UITextView if there is too much text? Similar to the UILabel?

like image 501
Sheehan Alam Avatar asked May 04 '10 01:05

Sheehan Alam


3 Answers

The problem with the accepted answer is that you have to guess the number of characters (the string's length) needed to fill the field, and that differs from font to font. Something like this, a category on UITextView, should work.

#import "UITextView+Size.h"

#define kMaxFieldHeight 1000

@implementation UITextView (Size)

-(BOOL)sizeFontToFitMinSize:(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 = [self.text sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

while (stringSize.height >= self.frame.size.height) {

    if (fontSize <= aMinFontSize) // it just won't fit, ever
        return NO;

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

return YES; 
}

@end
like image 101
Jane Sales Avatar answered Oct 23 '22 19:10

Jane Sales


Try this:

NSInteger lengthThreshold = 200;
if( [ textView.text length ] > lengthThreshold ) {
    NSInteger newSize = ... //calculate new size based on length

    [ textView setFont: [ UIFont systemFontOfSize: newSize ]];
}
like image 28
Jacob Relkin Avatar answered Oct 23 '22 20:10

Jacob Relkin


Swift 4 implementation inspired by @Jane Sales's answer.

When calculating available width and height we must also take into consideration possible vertical and horizontal margins (textContainerInset and textContainer.lineFragmentPadding).

Here's a better explanation of how margins work on UITextView: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TextUILayer/Tasks/SetTextMargins.html

If the text view can resize, then we must also force a layout so we can calculate the font size based on biggest possible text view size. In this case only height is considered (layouts only if required text height is bigger than original available height).

import UIKit

extension UITextView {

    func adjustFontToFitText(minimumScale: CGFloat) {
        guard let font = font else {
            return
        }

        let scale = max(0.0, min(1.0, minimumScale))
        let minimumFontSize = font.pointSize * scale
        adjustFontToFitText(minimumFontSize: minimumFontSize)
    }

    func adjustFontToFitText(minimumFontSize: CGFloat) {
        guard let font = font, minimumFontSize > 0.0 else {
            return
        }

        let minimumSize = floor(minimumFontSize)
        var fontSize = font.pointSize

        let availableWidth = bounds.width - (textContainerInset.left + textContainerInset.right) - (2 * textContainer.lineFragmentPadding)
        var availableHeight = bounds.height - (textContainerInset.top + textContainerInset.bottom)

        let boundingSize = CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude)
        var height = text.boundingRect(with: boundingSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height

        if height > availableHeight {
            // If text view can vertically resize than we want to get the maximum possible height
            sizeToFit()
            layoutIfNeeded()
            availableHeight = bounds.height - (textContainerInset.top + textContainerInset.bottom)
        }

        while height >= availableHeight {
            guard fontSize > minimumSize else {
                break
            }

            fontSize -= 1.0
            let newFont = font.withSize(fontSize)
            height = text.boundingRect(with: boundingSize, options: .usesLineFragmentOrigin, attributes: [.font: newFont], context: nil).height
        }

        self.font = font.withSize(fontSize)
    }

}
like image 3
Crt Gregoric Avatar answered Oct 23 '22 19:10

Crt Gregoric