गतिशील रूप से 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 यह आज का एकमात्र वास्तविक समाधान है।
फेटी

जवाबों:


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;

आईओएस 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 (स्विफ्ट 5):

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

लेकिन यह पाठ को एक पंक्ति में रखता है। और अगर मैं factLabel.numberOfLines को बदलता हूं, तो फ़ॉन्ट आकार गतिशील रूप से नहीं बदलता है।
कोडग्यु

@ reising1: आप सही कह रहे हैं। यह सिर्फ आपके लिए आकार परिवर्तन करने के लिए ढांचा बनाने का तरीका है।
मार्टिन बाबकेव

तो मेरे प्रश्न का उत्तर यह है कि प्रदान किए गए ढांचे का उपयोग करने का कोई तरीका नहीं है?
कोडगुय

1
@ reising1: इस मामले में आप NSString UIKit की विधि का भी उपयोग कर सकते हैं: sizeWithFont:constrainedToSize:lineBreakMode:लेकिन यह तरीका थोड़ा मुश्किल है
मार्टिन बाबाकेव

6
यह iOS6 के बाद से पदावनत है। इसे बदलेंmyLabel.minimumScaleFactor:10.0/[UIFont labelFontSize];
Norbert

72

minimumFontSizeiOS 6 के साथ पदावनत किया गया है minimumScaleFactor। आप उपयोग कर सकते हैं ।

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

यह लेबल और पाठ की चौड़ाई के अनुसार आपके फ़ॉन्ट आकार का ध्यान रखेगा।


मैं आमतौर पर 0.8 का उपयोग करता हूं, क्योंकि यहां तक ​​कि 0.7 बहुत छोटा दिखता है। बेशक कुछ पाठ न्यूनतम स्केल फैक्टर 0.8 के साथ फिट नहीं हो सकते हैं, यह तय करने की बात है कि बेहतर क्या दिखता है और जहां चीजें अप्राप्य हो जाती हैं। OTOH से मेरे ऐप्स को घुमाया जा सकता है जो बहुत मदद करता है।
gnasher729

adjustsFontSizeToFitWidthकेवल पाठ को कम कर देता है अगर यह कंटेनर के भीतर फिट नहीं होता है
user25

24

@ ईयाल बेन डोव के जवाब के आधार पर आप अपने अन्य ऐप्स के भीतर उपयोग करने के लिए इसे लचीला बनाने के लिए एक श्रेणी बनाना चाहते हैं।

अवलोकन करें: मैंने 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 की सामग्री अब कट गई है।
एड्रियन

1
यदि यह आपके लिए काम नहीं कर रहा है, तो संभवतः यह इसलिए है क्योंकि लेबल का फ्रेम अभी तक सेट नहीं किया गया है। इसे कॉल करने से पहले फ्रेम सेट करने का प्रयास करें (या कॉल करें setNeedsLayout/ layoutIfNeededयदि आप ऑटोलेयआउट का उपयोग कर रहे हैं)।
ब्यूमेलर

यह निम्नलिखित दुर्घटना देता है "" NSInvalidArgumentException ', कारण:' NSConcreteAttributedString initWithString :: nil value '"
मोहम्मद सालेह

इसका मतलब है कि आपका NSString शून्य नहीं हो सकता। मैं यह मान रहा हूं कि यदि आप एक टेक्स्ट प्रदान करने के लिए कम से कम UILabel की सामग्री को भरने के लिए फ़ॉन्ट आकार समायोजित करना चाहते हैं।
पाउलो मिगुएल अल्मेडा

इसकी एक खामी है। यह वर्णों के बीच की रेखा को तोड़ता है, इसलिए आप शब्दों को विभिन्न रेखाओं में विभाजित करते हुए देखते हैं। क्या इसे दरकिनार करने का कोई तरीका है?
02zgür

23

सिंगल लाइन - दो तरीके हैं, आप बस बदल सकते हैं।

1- व्यावहारिक रूप से (स्विफ्ट 3)

बस निम्नलिखित कोड जोड़ें

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

2 - UILabel Attributes निरीक्षक का उपयोग करना

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 है। मुझे एक ब्लॉग पोस्ट खोजने के लिए जाना था जो यह बताएगा कि स्विफ्ट के साथ आईओएस और एक्सकोड के नवीनतम संस्करण के लिए यह कैसे करना है ताकि यह कई लाइनों के साथ काम करे।

  1. "ऑटोश्रिंक" को "न्यूनतम फ़ॉन्ट आकार" पर सेट करें।
  2. फ़ॉन्ट को सबसे बड़े वांछित फ़ॉन्ट आकार पर सेट करें (मैंने 20 को चुना)
  3. "लाइन रैप" को "वर्ड रैप" से "ट्रंकट टेल" में बदलें।

स्रोत: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/


यह वास्तव में एक जीवन रक्षक है !!
भक्ति १२

2
सुपर कूल .. वह ट्रंकट टेल पॉइंट सबसे महत्वपूर्ण है .. वर्ड रैप ऑटोलैयट के मामले में कोज फॉन्ट साइज को कम करने की ललक महसूस नहीं करता है, जबकि जब यह ट्रंकैट टेल ऑटोलैयूट को टेक्स्ट को ब्लेड से बचाना होता है और यह तब यह फ़ॉन्ट का आकार बदल देता है।
GKK

12

स्विफ्ट संस्करण:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5

धन्यवाद .. यहाँ अनुक्रम की तरह लगता है भी
प्रमोद

7

यहाँ UILabel के लिए एक स्विफ्ट एक्सटेंशन है। यह लेबल की सीमा की चौड़ाई और ऊंचाई के आधार पर फ़ॉन्ट का आकार बदलने के लिए एक द्विआधारी खोज एल्गोरिथ्म चलाता है। IOS 9 और ऑटोलेयूट के साथ काम करने के लिए परीक्षण किया गया।

उपयोग:<label> आपका पूर्व-परिभाषित यूआईबेल कहां है जिसे फ़ॉन्ट आकार की आवश्यकता है

<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()कॉल को अपने विवेक पर हटाया जा सकता है


आह - लेकिन यह वास्तव में autolayout के साथ काम नहीं करता है; "sizeToFit" उस मामले में कुछ नहीं करता है।
फेटी

4

इसका थोड़ा सा परिष्कृत नहीं है, लेकिन यह काम करना चाहिए, उदाहरण के लिए, आप कह सकते हैं कि आप अपने uilabel को 120x120 पर कैप करना चाहते हैं, जिसमें अधिकतम 28 का आकार है:

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;
        }
    }

यह बजाय अक्षम लगता है - आपको यूआईबेल को गतिशील रूप से ऊंचाई प्रदान करनी चाहिए ताकि कुछ उपलब्ध स्थान में फिट हो सकें। यदि आप इसे टेबल व्यू सेल के शीर्षक फ़ॉन्ट गणना जैसी किसी चीज़ के लिए चलाते हैं, तो आपको बड़े अंतराल के मुद्दे मिलेंगे। दृष्टिकोण काम कर सकता है, लेकिन निश्चित रूप से अनुशंसित नहीं है।
ज़ोराय्र

वास्तव में प्रश्न का उत्तर देने वाला एकमात्र व्यक्ति होने के लिए अप-वोट करें।
जय

2

बस UTextView को sizeToFit संदेश भेजें। यह सिर्फ अपने पाठ को फिट करने के लिए अपनी खुद की ऊंचाई को समायोजित करेगा। यह अपनी खुद की चौड़ाई या उत्पत्ति को नहीं बदलेगा।

[textViewA1 sizeToFit];

क्या होता है जब आकार जो पाठ को फिट करता है वह कंटेनर के स्थान के लिए बहुत बड़ा है? उदाहरण के लिए, मान लें कि आपके पास पाठ बिंदु को फिट करने के लिए 100 अंक उपलब्ध हैं, sizeToFitआपके textViewA1200 अंक बनने के बाद जो समाप्त हो जाता है।
जोरावर

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];
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.