ProgramingTip

여러 줄이있는 UILabel에서 자동 축소

bestdevel 2020. 12. 26. 15:59
반응형

여러 줄이있는 UILabel에서 자동 축소


의 여러 줄에서 autoshrink 속성을 함께 사용할 수 UILabel있습니까? 예를 들어, 사용 가능한 두 줄에서 가능한 큰 텍스트 크기입니다.


이 사람들은 해결책을 찾았습니다.

http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/

해결책은 다음과 적응합니다.

int maxDesiredFontSize = 28;
int minFontSize = 10;
CGFloat labelWidth = 260.0f;
CGFloat labelRequiredHeight = 180.0f;
//Create a string with the text we want to display.
self.ourText = @"This is your variable-length string. Assign it any way you want!";

/* This is where we define the ideal font that the Label wants to use.
   Use the font you want to use and the largest font size you want to use. */
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize];

int i;
/* Time to calculate the needed font size.
   This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
   Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = maxDesiredFontSize; i > minFontSize; i=i-2)
{
    // Set the new font size.
    font = [font fontWithSize:i];
    // You can log the size you're trying: NSLog(@"Trying size: %u", i);

    /* This step is important: We make a constraint box 
       using only the fixed WIDTH of the UILabel. The height will
       be checked later. */ 
    CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT);

    // This step checks how tall the label would be with the desired font.
    CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    /* Here is where you use the height requirement!
       Set the value in the if statement to the height of your UILabel
       If the label fits into your required height, it will break the loop
       and use that font size. */
    if(labelSize.height <= labelRequiredHeight)
        break;
}
// You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i);

// Set the UILabel's font to the newly adjusted font.
msg.font = font;

// Put the text into the UILabel outlet variable.
msg.text = self.ourText;

이 작업을 수행 할 광고주 인터페이스 빌더에서 IBOutlet을 UILabel에 할당해야합니다.

"IBOutlet UILabel * msg;"

모든 장점은 11 픽셀의 사람들입니다.


위의 코드를 약간 수정하여 카테고리로 만들었습니다 UILabel.

헤더 파일 :

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

그리고 구현 파일 :

@implementation UILabel (MultiLineAutoSize)

- (void)adjustFontSizeToFit
{
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumFontSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

@end

이 링크를 찾았습니다 http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

이 문제는 Interface Builder를 사용하여 간단한 3 단계를 실행할 수 있습니다.

  1. "Autoshrink"를 "최소 글꼴 크기"로 설정합니다.
  2. 글꼴을 원하는 가장 큰 글꼴 크기 (20)로 설정하고 Lines를 예를 들어 10으로 설정합니다. 제 경우에는 해당 글꼴 크기의 레이블에 수있는 줄 수입니다.
  3. 그런 다음 "줄 바꿈"을 "단어 줄 바꿈"에서 "꼬리 자르기"로 변경합니다.

도움이 되셨기를 바랍니다.


다음은 itecedor의 iOS 6 업데이트를 기반으로 iOS 7로 업데이트 된 카테고리 솔루션입니다.

헤더 파일 :

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

그리고 구현 파일 :

@implementation UILabel (MultiLineAutoSize)


- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);

        CGRect textRect = [self.text boundingRectWithSize:constraintSize
                                             options:NSStringDrawingUsesLineFragmentOrigin
                                          attributes:@{NSFontAttributeName:font}
                                             context:nil];

        CGSize labelSize = textRect.size;


        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout]; }


@end

대답으로 대답은 엉망이고 부정확합니다. UILabel은 다음 속성을 설정하면 자동으로 처리됩니다.

numberOfLines 0이 아니어야합니다

adjustsFontSizeToFitWidth 반드시 YES

lineBreakMode하지NSLineBreakByCharWrapping또는NSLineBreakByWordWrapping


@DaGaMs에서 채택한 방식 버전.

SWIFT 2 :

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) {
            let proposedFont = font.fontWithSize(size)
            let constraintSize = CGSizeMake(bounds.size.width, CGFloat(MAXFLOAT))
            let labelSize = ((text ?? "") as NSString).boundingRectWithSize(constraintSize,
                options: .UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: proposedFont],
                context: nil)
            if labelSize.height <= bounds.size.height {
                font = proposedFont
                setNeedsLayout()
                break;
            }
        }
    }
}

SWIFT 3 :

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) {
            let proposedFont = font.withSize(size)
            let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT))
            let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize,
                                                                            options: .usesLineFragmentOrigin,
                                                                            attributes: [NSFontAttributeName: proposedFont],
                                                                            context: nil)
            if labelSize.height <= bounds.size.height {
                font = proposedFont
                setNeedsLayout()
                break;
            }
        }
    }
}


평판이 부족해서 몬티 래빗의 게시물에 댓글을 달 수 없으니 새로운 답변을 드리겠습니다. 그가 제안한 솔루션은 Xcode 7.3 이상에서 작동하지 않습니다. 제대로 작동해야하는 작업 스토리 보드에서 다음을 수행해야합니다.

  1. 너비 제한 설정 (순수 너비 또는 꼬리 및 리드)
  2. HEIGHT CONSTRAINT 설정 (매우 중요합니다. 일반적으로 자동 크기 조정은 레이블 높이를 설정하지.)
  3. "Autoshrink"속성을 "최소 글꼴 크기"또는 "최소 글꼴 크기"로 설정합니다 (두 경우 모두 작동).
  4. "줄 바꿈"속성을 "꼬리 자르기"로 설정합니다.
  5. "Lines"속성을 0이 아닌 값으로 설정합니다.

도움이 되셨기를 바랍니다. ;)


나는 DaGaMs의 대답을 좋아했지만 DequeueReusableCell : 반환 될 수있는 UITableViewCells와 같은 레이블을 사용하면 원래 글꼴 크기가 텍스트가 적고 원래 수있는 일부 tableView 셀에 대해 여전히 원해도되지만 일반 글꼴 크기가 계속 축소됩니다. 원래 라벨의 원래 글꼴 크기.

그래서 저는 DaGaMs의 카테고리를 시작점으로 시작하여 별도의 카테고리가 아닌 별도의 클래스를 생성하고 스토리 보드의 UILabels 가이 새로운 클래스를 사용하는지 확인합니다.

#import "MultiLineAutoShrinkLabel.h"

@interface MultiLineAutoShrinkLabel ()
@property (readonly, nonatomic) UIFont* originalFont;
@end

@implementation MultiLineAutoShrinkLabel

@synthesize originalFont = _originalFont;

- (UIFont*)originalFont { return _originalFont ? _originalFont : (_originalFont = self.font); }

- (void)quoteAutoshrinkUnquote
{
    UIFont* font = self.originalFont;
    CGSize frameSize = self.frame.size;

    CGFloat testFontSize = _originalFont.pointSize;
    for (; testFontSize >= self.minimumFontSize; testFontSize -= 0.5)
    {
        CGSize constraintSize = CGSizeMake(frameSize.width, MAXFLOAT);
        CGSize testFrameSize = [self.text sizeWithFont:(font = [font fontWithSize:testFontSize])
                                     constrainedToSize:constraintSize
                                         lineBreakMode:self.lineBreakMode];
        // the ratio of testFontSize to original font-size sort of accounts for number of lines
        if (testFrameSize.height <= frameSize.height * (testFontSize/_originalFont.pointSize))
            break;
    }

    self.font = font;
    [self setNeedsLayout];
}

@end

itedcedor의 답변에는 pwightman이 지적한 문제가 있습니다. 또한 공백을 다듬을 필요가 없습니다. 다음은 수정 된 버전입니다.

- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];

        if(labelSize.height <= size.height) {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }

    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

이 솔루션에 대해 DaGaMs에 감사드립니다.

다음과 같이 업데이트했습니다.

1-iOS 6에서 작업 비용 (minimumFontSize 및 UILineBreakModeWordWrap이 사용하지 않기 때문에) 2- 크기 조정이 실패 할 수 있으므로 레이블 텍스트에서 공백을 제거합니다 (찾았는지 알고 싶지 않습니다)

-(void)adjustFontSizeToFit 
{
    self.text = [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

UIButton의 경우 다음 줄만 작동합니다.

self.centerBtn.titleLabel.numberOfLines = 2;
self.centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
self.centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES;

@wbarksdale의 Swift 3 솔루션을 사용했지만 긴 단어가 중간에서 잘리는 것을 발견했습니다. 단어를 그대로 유지 한 다음과 같이 수정해야합니다.

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        let words = self.text?.components(separatedBy: " ")
        var longestWord: String?
        if let max = words?.max(by: {$1.characters.count > $0.characters.count}) {
            longestWord = max
        }
        for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) {
            let proposedFont = font.withSize(size)
            let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT))
            let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize,
                                                                    options: .usesLineFragmentOrigin,
                                                                    attributes: [NSFontAttributeName: proposedFont],
                                                                    context: nil)

            let wordConstraintSize = CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT))
            let longestWordSize = ((longestWord ?? "") as NSString).boundingRect(with: wordConstraintSize,
                                                                    options: .usesFontLeading,
                                                                    attributes: [NSFontAttributeName: proposedFont],
                                                                    context: nil)

            if labelSize.height <= bounds.size.height && longestWordSize.width < constraintSize.width {
                font = proposedFont
                setNeedsLayout()
                break
            }
        }
    }
}

이 기능을 달성하기 위해 위의 "The Dude 's"답변을 기반으로 UILabel에 작은 범주를 작성했습니다.

https://gist.github.com/ayushn21/d87b835b2efc756e859f


에 대한 메소드가 있는데 NSString, -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:이는 iOS 2.0 이후로 존재했던 것으로 보이지만 안타깝게도 글꼴 크기의 자동 축소를 권장하지 않기 때문에 제안 된 대안없이 iOS 7에서 더 이상 사용되지 않습니다. 나는 그들이 기조 연설 등에서 그것을 사용하기 때문에 이것에 대한 Apple의 입장을 정말로 이해하지 못하며 글꼴 크기가 작은 범위 내에 있으면 괜찮다고 생각합니다. 다음은이 방법을 사용한 Swift 구현입니다.

var newFontSize: CGFloat = 30
    let font = UIFont.systemFontOfSize(newFontSize)
    (self.label.text as NSString).sizeWithFont(font, minFontSize: 20, actualFontSize: &newFontSize, forWidth: self.label.frame.size.width, lineBreakMode: NSLineBreakMode.ByWordWrapping)
    self.label.font = font.fontWithSize(newFontSize)

더 이상 사용되지 않는 방법을 사용하지 않고이 작업을 수행 할 수있는 방법을 모르겠습니다.


이 시도:

레이블에 text 속성을 설정 한 후 하위 클래스 UILabel 또는 adjustFontSize 메서드 호출

override var text : String? { didSet { self.adjustFontSize() } }

func adjustFontSize()
{
    var lineCount = self.string.components(separatedBy: "\n").count - 1
    var textArray = self.string.components(separatedBy: " ")
    var wordsToCompare = 1
    while(textArray.count > 0)
    {
        let words = textArray.first(n: wordsToCompare).joined(separator: " ")
        let wordsWidth = words.widthForHeight(0, font: self.font)
        if(wordsWidth > self.frame.width)
        {
            textArray.removeFirst(wordsToCompare)
            lineCount += 1
            wordsToCompare = 1
        }
        else if(wordsToCompare > textArray.count)
        {
            break
        }
        else
        {
            wordsToCompare += 1
        }
    }
    self.numberOfLines = lineCount + 1
}

extension UILabel{

func adjustFont(minSize:Int, maxSize:Int){
    var newFont = self.font
    for index in stride(from: maxSize, to: minSize, by: -1) {
        newFont = UIFont.systemFont(ofSize: CGFloat(index))
        let size = CGSize(width: self.frame.width, height: CGFloat(Int.max))
        let size2 = (self.text! as NSString).boundingRect(with: size, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedStringKey.font:newFont!], context: nil).size
        if size2.height < self.frame.size.height{
            break
        }
    }
    self.font = newFont
}

}

UILabel의 numberOfLines 속성에도 값을 할당해야합니다.

참조 URL : https://stackoverflow.com/questions/9059631/autoshrink-on-a-uilabel-with-multiple-lines

반응형