UILabel의 글꼴 크기를 동적으로 변경


188

나는 현재 UILabel:

factLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 100)];
factLabel.text = @"some text some text some text some text";
factLabel.backgroundColor = [UIColor clearColor];
factLabel.lineBreakMode = UILineBreakModeWordWrap;
factLabel.numberOfLines = 10;
[self.view addSubview:factLabel];

내 iOS 응용 프로그램의 수명 동안 factLabel다양한 가치를 얻습니다. 문장이 여러 개이고 단어가 5 ~ 6 개만있는 경우도 있습니다.

UILabel텍스트가 항상 정의한 범위에 맞도록 글꼴 크기가 변경되도록 어떻게 설정할 수 있습니까?


2
2016 년에는 유일하게 좋은 해결책은 "자동 축소 사용"방법을 사용하는 것입니다. UILabel 상자를 원하는 실제 크기로 만들고, 글꼴을 UILabel로 채우고, 자동 축소를 선택하고, 거대한 거대한 글꼴 크기 (300)를 설정하고, 가장 작거나 가장 큰 시뮬레이터에서 테스트해야합니다. (따라서 현재 4s / PadPro입니다.) 전체 설명 : stackoverflow.com/a/35154493/294884 오늘날 유일한 솔루션입니다.
Fattie

답변:


370

한 줄:

factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;

위의 코드는 텍스트의 글꼴 크기를 (예 : 8 레이블에 맞게 에 맞게 조정합니다. numberOfLines = 1필수입니다.

여러 줄 :

내용 numberOfLines > 1을 마지막 텍스트의 크기를 파악하는 방법이 있는 NSString의 sizeWithFont ... UIKit 첨가 방식, 예를 들어 :

CGSize lLabelSize = [yourText sizeWithFont:factLabel.font
                                  forWidth:factLabel.frame.size.width
                             lineBreakMode:factLabel.lineBreakMode];

그런 다음 lLabelSize, 예를 들어, (단, 레이블의 높이 만 변경한다고 가정) 레이블을 사용하여 레이블의 크기를 조정할 수 있습니다 .

factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);

iOS6

한 줄:

iOS6부터는 minimumFontSize더 이상 사용되지 않습니다. 라인

factLabel.minimumFontSize = 8.;

다음으로 변경할 수 있습니다.

factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;

IOS 7

여러 줄 :

iOS7부터는 sizeWithFont더 이상 사용되지 않습니다. 여러 줄 경우 :

factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);

iOS 13 (Swift 5) :

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

그러나 이것은 텍스트를 한 줄에 모두 넣습니다. factLabel.numberOfLines를 변경하면 글꼴 크기가 동적으로 변경되지 않습니다.
CodeGuy

@ reising1 : 맞습니다. 이것은 크기 조정 작업을 위해 프레임 워크를 만드는 방법입니다.
Martin Babacaev

그렇다면 내 질문에 대한 대답은 제공된 프레임 워크를 사용하여 할 수있는 방법이 없다는 것입니다.
CodeGuy

1
@ reising1 :이 경우 NSString UIKit 추가 방법도 사용할 수 있습니다. sizeWithFont:constrainedToSize:lineBreakMode:그러나이 방법은 조금 어렵습니다
Martin Babacaev

6
iOS6부터는 더 이상 사용되지 않습니다. 다음으로 교체하십시오myLabel.minimumScaleFactor:10.0/[UIFont labelFontSize];
Norbert

72

minimumFontSizeiOS 6에서는 더 이상 사용되지 않습니다 minimumScaleFactor.

yourLabel.adjustsFontSizeToFitWidth=YES;
yourLabel.minimumScaleFactor=0.5;

레이블 및 텍스트 너비에 따라 글꼴 크기를 관리합니다.


0.7도 너무 작게 보이기 때문에 보통 0.8을 사용합니다. 물론 일부 텍스트는 최소 스케일 팩터 0.8에 맞지 않을 수 있습니다. 더 나은 모양과 읽을 수없는 부분을 결정해야합니다. OTOH 내 앱을 회전시켜 많은 도움을 줄 수 있습니다.
gnasher729

adjustsFontSizeToFitWidth컨테이너에 맞지 않는 경우에만 텍스트를 줄입니다
user25

24

@Eyal Ben Dov의 답변에 따라 카테고리를 만들어 다른 앱에서 유연하게 사용할 수 있습니다.

Obs .: iOS 7과 호환되도록 코드를 업데이트했습니다

헤더 파일

#import <UIKit/UIKit.h>

@interface UILabel (DynamicFontSize)

-(void) adjustFontSizeToFillItsContents;

@end

구현 파일

#import "UILabel+DynamicFontSize.h"

@implementation UILabel (DynamicFontSize)

#define CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE 35
#define CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE 3

-(void) adjustFontSizeToFillItsContents
{
    NSString* text = self.text;

    for (int i = CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE; i>CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE; i--) {

        UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];

        CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

        if (rectSize.size.height <= self.frame.size.height) {
            self.font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
            break;
        }
    }

}

@end

-용법

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

건배


그것은 나를 위해 작동하지 않습니다. 내 UILabel의 내용이 잘립니다.
Adrian

1
작동하지 않는 경우 레이블의 프레임이 아직 설정되지 않았기 때문일 수 있습니다. 이것을 호출하기 전에 프레임을 설정하십시오 (또는 자동 레이아웃을 사용하는 경우 setNeedsLayout/ 호출 layoutIfNeeded).
bmueller

다음과 같은 충돌이 발생합니다. " 'NSInvalidArgumentException', 이유 : 'NSConcreteAttributedString initWithString :: nil value'"
Mohamed Saleh

NSString은 0이 될 수 없습니다. UILabel의 내용을 채우기 위해 글꼴 크기를 조정하려면 최소한 텍스트를 제공해야한다고 가정합니다.
Paulo Miguel Almeida

단점이 있습니다. 문자 사이에 줄 바꿈이 있으므로 단어가 다른 줄로 나뉩니다. 이것을 우회하는 방법이 있습니까?
Özgür

24

한 줄 -두 가지 방법이 있습니다. 간단하게 변경할 수 있습니다.

1- 실용적으로 (Swift 3)

다음 코드를 추가하십시오.

    yourLabel.numberOfLines = 1;
    yourLabel.minimumScaleFactor = 0.7;
    yourLabel.adjustsFontSizeToFitWidth = true;

2-UILabel 속성 관리자 사용

i- Select your label- Set number of lines 1.
ii- Autoshrink-  Select Minimum Font Scale from drop down
iii- Set Minimum Font Scale value as you wish , I have set 0.7 as in below image. (default is 0.5)

여기에 이미지 설명을 입력하십시오


22

2015 년입니다. 여러 줄에서 작동하도록 Swift를 사용하여 최신 버전의 iOS 및 XCode에 대해 수행하는 방법을 설명하는 블로그 게시물을 찾아야했습니다.

  1. "자동 축소"를 "최소 글꼴 크기"로 설정하십시오.
  2. 글꼴을 원하는 가장 큰 글꼴 크기로 설정하십시오 (20을 선택했습니다)
  3. "줄 바꿈"을 "워드 랩"에서 "꼬리 잘라 내기"로 변경하십시오.

출처 : http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/


이것은 진정한 생명의 은인입니다!
bhakti123

2
테일 포인트를 자르는 것이 가장 중요합니다. 자동 줄 바꿈 자동 레이아웃의 경우 Coz는 글꼴 크기를 줄이려는 충동을 느끼지 않지만, 잘릴 때 테일 자동 레이아웃은 블레이드에서 텍스트를 저장해야합니다. 그런 다음 글꼴 크기를 조정합니다.
GKK

12

스위프트 버전 :

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5

감사합니다 .. 여기 순서도 같은 것 같습니다
Pramod

7

UILabel의 Swift 확장 기능은 다음과 같습니다. 이진 검색 알고리즘을 실행하여 레이블 경계의 너비와 높이를 기준으로 글꼴 크기를 조정합니다. iOS 9 및 자동 레이아웃과 작동하도록 테스트되었습니다.

사용법 :<label> 글꼴 크기 조정이 필요한 사전 정의 된 UILabel은 어디에 있습니까?

<label>.fitFontForSize()

기본적으로이 기능은 5pt 및 300pt 글꼴 크기 범위 내에서 검색하고 해당 범위 내에서 텍스트를 "완벽하게"맞도록 글꼴을 설정합니다 (1.0pt 내 정확함). 예를 들어 다음과 같은 방법으로 1pt레이블의 현재 글꼴 크기0.1pts 내 에서 정확하게 검색하도록 매개 변수를 정의 할 수 있습니다 .

<label>.fitFontForSize(1.0, maxFontSize: <label>.font.pointSize, accuracy:0.1)

다음 코드를 파일에 복사 / 붙여 넣기

extension UILabel {

    func fitFontForSize(var minFontSize : CGFloat = 5.0, var maxFontSize : CGFloat = 300.0, accuracy : CGFloat = 1.0) {
        assert(maxFontSize > minFontSize)
        layoutIfNeeded() // Can be removed at your own discretion
        let constrainedSize = bounds.size
        while maxFontSize - minFontSize > accuracy {
            let midFontSize : CGFloat = ((minFontSize + maxFontSize) / 2)
            font = font.fontWithSize(midFontSize)
            sizeToFit()
            let checkSize : CGSize = bounds.size
            if  checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
                minFontSize = midFontSize
            } else {
                maxFontSize = midFontSize
            }
        }
        font = font.fontWithSize(minFontSize)
        sizeToFit()
        layoutIfNeeded() // Can be removed at your own discretion
    }

}

참고 :layoutIfNeeded()통화는 자신의 재량에 따라 제거 할 수 있습니다


아-그러나 자동 레이아웃과는 실제로 작동하지 않습니다. 이 경우 "sizeToFit"는 아무 작업도 수행하지 않습니다.
Fattie

4

조금 정교하지는 않지만 작동해야합니다. 예를 들어 최대 글꼴 크기는 28 인 uilabel을 120x120으로 제한하고 싶다고 말할 수 있습니다.

magicLabel.numberOfLines = 0;
magicLabel.lineBreakMode = NSLineBreakByWordWrapping;
...
magicLabel.text = text;
    for (int i = 28; i>3; i--) {
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:(CGFloat)i] constrainedToSize:CGSizeMake(120.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
        if (size.height < 120) {
            magicLabel.font = [UIFont systemFontOfSize:(CGFloat)i];
            break;
        }
    }

이것은 다소 비효율적 인 것 같습니다. UILabel은 제공된 공간에 맞게 높이를 동적으로 조정해야합니다. 테이블 뷰 셀의 제목 글꼴 계산과 같은 방법으로 이것을 실행하면 심각한 지연 문제가 발생합니다. 이 접근법은 효과가있을 수 있지만 반드시 권장되지는 않습니다.
Zorayr

실제로 질문에 대답 할 수있는 유일한 사람인 것에 대해 투표하십시오.
Jai

2

sizeToFit 메시지를 UITextView로 보내십시오. 텍스트에 맞게 자체 높이를 조정합니다. 자체 너비 나 원점을 변경하지 않습니다.

[textViewA1 sizeToFit];

텍스트에 맞는 크기가 컨테이너 공간에 비해 너무 크면 어떻게됩니까? 예를 들어, 호출 후, 텍스트보기에 맞게 사용할 수 100 점을 가정 해 봅시다 sizeToFit당신이 textViewA1잘립니다 점점 끝 200 포인트가된다.
Zorayr

0

스위프트 2.0 버전 :

private func adapteSizeLabel(label: UILabel, sizeMax: CGFloat) {
     label.numberOfLines = 0
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping
     let maximumLabelSize = CGSizeMake(label.frame.size.width, sizeMax);
     let expectSize = label.sizeThatFits(maximumLabelSize)
     label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, expectSize.width, expectSize.height)
}

0

이 솔루션은 여러 줄에 적용됩니다.

몇 가지 기사를 따르고 자동으로 텍스트 크기를 조정하고 주어진 레이블 크기에 가장 잘 맞게 줄 수를 조정하는 기능이 필요한 후에 함수를 직접 작성했습니다. (즉, 짧은 줄은 한 줄에 잘 맞고 많은 양의 레이블 프레임을 사용하는 반면, 긴 줄은 2 또는 3 줄로 자동 분할되어 그에 따라 크기를 조정합니다)

자유롭게 재사용하고 필요에 따라 조정하십시오. viewDidLayoutSubviews초기 레이블 프레임이 설정되도록 완료 한 후에 호출해야합니다 .

+ (void)setFontForLabel:(UILabel *)label withMaximumFontSize:(float)maxFontSize andMaximumLines:(int)maxLines {
    int numLines = 1;
    float fontSize = maxFontSize;
    CGSize textSize; // The size of the text
    CGSize frameSize; // The size of the frame of the label
    CGSize unrestrictedFrameSize; // The size the text would be if it were not restricted by the label height
    CGRect originalLabelFrame = label.frame;

    frameSize = label.frame.size;
    textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize: fontSize]}];

    // Work out the number of lines that will need to fit the text in snug
    while (((textSize.width / numLines) / (textSize.height * numLines) > frameSize.width / frameSize.height) && (numLines < maxLines)) {
        numLines++;
    }

    label.numberOfLines = numLines;

    // Get the current text size
    label.font = [UIFont systemFontOfSize:fontSize];
    textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                        options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                     attributes:@{NSFontAttributeName : label.font}
                                        context:nil].size;

    // Adjust the frame size so that it can fit text on more lines
    // so that we do not end up with truncated text
    label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.width);

    // Get the size of the text as it would fit into the extended label size
    unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;

    // Keep reducing the font size until it fits
    while (textSize.width > unrestrictedFrameSize.width || textSize.height > frameSize.height) {
        fontSize--;
        label.font = [UIFont systemFontOfSize:fontSize];
        textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                            options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                         attributes:@{NSFontAttributeName : label.font}
                                            context:nil].size;
        unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;
    }

    // Set the label frame size back to original
    label.frame = originalLabelFrame;
}

0

다음은 애니메이션 글꼴 크기 변경을 구현하는 UILabel 서브 클래스의 채우기 코드입니다.

@interface SNTextLayer : CATextLayer

@end

@implementation SNTextLayer

- (void)drawInContext:(CGContextRef)ctx {
    // We override this to make text appear at the same vertical positon as in UILabel
    // (otherwise it's shifted tdown)
    CGFloat height = self.bounds.size.height;
    float fontSize = self.fontSize;
    // May need to adjust this somewhat if it's not aligned perfectly in your implementation
    float yDiff = (height-fontSize)/2 - fontSize/10;

    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, 0.0, yDiff);
    [super drawInContext:ctx];
     CGContextRestoreGState(ctx);
}

@end

@interface SNAnimatableLabel ()

@property CATextLayer* textLayer;

@end

@interface SNAnimatableLabel : UILabel

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration;

@end



@implementation SNAnimatableLabel


- (void)awakeFromNib {
    [super awakeFromNib];
    _textLayer = [SNTextLayer new];
    _textLayer.backgroundColor = self.backgroundColor.CGColor;
    _textLayer.foregroundColor = self.textColor.CGColor;
    _textLayer.font = CGFontCreateWithFontName((CFStringRef)self.font.fontName);
    _textLayer.frame = self.bounds;
    _textLayer.string = self.text;
    _textLayer.fontSize = self.font.pointSize;
    _textLayer.contentsScale = [UIScreen mainScreen].scale;
    [_textLayer setPosition: CGPointMake(CGRectGetMidX(_textLayer.frame), CGRectGetMidY(_textLayer.frame))];
    [_textLayer setAnchorPoint: CGPointMake(0.5, 0.5)];
    [_textLayer setAlignmentMode: kCAAlignmentCenter];
    self.textColor = self.backgroundColor;
    // Blend text with background, so that it doens't interfere with textlayer text
    [self.layer addSublayer:_textLayer];
    self.layer.masksToBounds = NO;
}

- (void)setText:(NSString *)text {
    _textLayer.string = text;
    super.text = text;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    // Need to enlarge the frame, otherwise the text may get clipped for bigger font sizes
    _textLayer.frame = CGRectInset(self.bounds, -5, -5);
}

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration {
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    _textLayer.fontSize = fontSize;
    [CATransaction commit];
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.