Câu hỏi Tự động sửa trên UILabel với nhiều dòng


Có thể sử dụng thuộc tính autoshrink kết hợp trên nhiều dòng trên một UILabel? ví dụ: kích thước văn bản lớn có thể có trên 2 dòng có sẵn.


51
2018-01-30 05:12


gốc




Các câu trả lời:


Những người này đã tìm thấy một giải pháp:

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

Giải pháp của họ như sau:

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;

Để làm việc này, IBOutlet phải được chỉ định trong trình xây dựng giao diện cho UILabel.

"IBOutlet UILabel * msg;"

Tất cả công đức là của những người ở 11pixel.


39
2018-01-30 07:51



Không làm việc cho tôi. - Iulian Onofrei
Đừng lãng phí thời gian của bạn nó không hoạt động. - user7097242


Tôi đã sửa đổi mã trên một chút để biến nó trở thành một danh mục UILabel:

Tập tin tiêu đề:

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

Và tệp triển khai:

@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

46
2017-07-27 19:49



Tuyệt vời, tôi đã chỉ vấp vào câu hỏi này bản thân mình và điều này giải quyết nó trong thời gian không :-) Chỉ cần hai ghi chú: (1) hai dòng đầu tiên bên trong if mệnh đề là thừa, vì chúng sẽ được thực hiện ngay dưới for chu kỳ. (2) nếu cũng cần văn bản của UILabel được căn chỉnh theo chiều dọc lên trên (trong trường hợp nó đang sử dụng ít dòng hơn thực tế có thể được hiển thị trong nhãn), nó đủ để đặt chiều cao của nhãn thành labelSize.height. Lưu ý rằng sizeToFit không thể được sử dụng cho mục đích này, vì nó phá vỡ văn bản được định dạng trước đó và kích cỡ nó thành kích thước phông chữ gốc. - FurloSK
Điều này là hoàn hảo, nhưng minimalFontSize không được chấp nhận trong iOS6 - làm thế nào điều này có thể được thay đổi để làm việc với minimumScaleFactor thay thế? - bmueller
Đúng thứ tôi cần. Cảm ơn. +1 - Jay Slupesky
@bmueller: Ở trên cùng của hàm, khai báo float minFontSize = self.font.pointSize * self.minimumScaleFactor;. Sau đó thay thế >= self.minimumFontSize với >= minFontSize. - ToolmakerSteve


Tôi đã tìm thấy liên kết này http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

Vấn đề có thể được giải quyết bằng cách sử dụng bộ dựng giao diện trong 3 bước đơn giản:

  1. Đặt “Tự động sửa” thành “Kích thước phông chữ tối thiểu”.
  2. Đặt phông chữ cho kích thước phông chữ mong muốn lớn nhất (20) và đặt Đường thành, ví dụ: 10, trong trường hợp của tôi là nhiều dòng như sẽ phù hợp với nhãn ở kích thước phông chữ đó.
  3. Sau đó, thay đổi “Line Breaks ”từ“ Word Wrap ”thành“ Truncate Tail ”.

Hy vọng nó giúp!


34
2017-07-01 22:38



Tôi chọn Truncate Tail và các dòng vô hình của tôi bây giờ có thể nhìn thấy. - EFE
Giải pháp tốt hơn nhiều so với mã tùy chỉnh. Làm tốt lắm. - Kris
Cảm ơn bạn đã chỉ ra "Truncate Tail", đó là những gì tạo nên sự khác biệt. - Nils Hott
Theo phản xạ lắc đầu của tôi khi thay đổi Line Break để Truncate Tail làm việc. Cảm ơn vì điều này, điều này tốt hơn nhiều so với bất kỳ giải pháp mã nào. Thuộc tính được đặt tên kém trong Xcode, IMO. - Tim
Đây sẽ là giải pháp được chấp nhận; không yêu cầu mã hóa. - wroluk


Đây là giải pháp thể loại được cập nhật lên iOS 7 dựa trên các bản cập nhật của itecedor cho iOS 6.

Tập tin tiêu đề:

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

Và tệp triển khai:

@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

24
2017-12-11 18:53



Bạn không cần phải áp dụng minimumScaleFactor cho điểm ban đầu? (ví dụ: nếu hệ số là 0,5, bạn có thể nhận được các phông chữ rất nhỏ ở đây). - iceydee
Bạn đúng! Tôi sẽ chỉnh sửa câu trả lời để phản ánh điều đó. - stevenpaulr
Hoạt động như một nét duyên dáng, đừng quên đặt adjustsFontSizeToFitWidth thành YES cho UILabel - Vlad Smoc
@stevenpaulr THANK YOU SWEET BABY CHÚA GIÊSU !!!! - DaynaJuliana


Câu trả lời được đánh dấu là giải pháp là hacky và không chính xác. UILabel sẽ xử lý nó tự động nếu bạn đặt các thuộc tính sau một cách chính xác:

numberOfLines phải là nonzero

adjustsFontSizeToFitWidth cần phải YES

lineBreakMode phải không phải được NSLineBreakByCharWrapping hoặc là NSLineBreakByWordWrapping


9
2018-04-27 15:19



Tôi đã thành công khi sử dụng: numberOfLines = 0, lineBreakMode = NSLineBreakByTruncatingTail (hoặc NSLineBreakByTruncatingHead hoặc NSLineBreakByTruncatingMiddle) và có giới hạn chiều cao trên nhãn. - Martyn Davis
Đây sẽ là câu trả lời được chấp nhận. - Iulian Onofrei


Tôi không thể bình luận bài viết của MontiRabbit do thiếu uy tín, vì vậy tôi sẽ làm một câu trả lời mới. Giải pháp mà anh ta (và người giới thiệu của cô ấy) đề xuất không hoạt động trên Xcode 7.3 hoặc tốt hơn, nó không chính xác. Để làm cho nó hoạt động, trong bảng phân cảnh, tôi phải:

  1. Đặt giới hạn chiều rộng (chiều rộng hoặc đuôi và chiều rộng thuần túy)
  2. SET HEIGHT CONSTRAINT (điều này rất quan trọng, thông thường với autoresize không thiết lập chiều cao nhãn)
  3. Đặt thuộc tính "Tự động xác thực" thành "Tỷ lệ phông chữ tối thiểu" hoặc "Kích thước phông chữ tối thiểu" (hoạt động trong cả hai trường hợp)
  4. Đặt thuộc tính "Line Breaks" thành "Truncate Tail"
  5. Đặt thuộc tính "Lines" thành giá trị khác 0

Hy vọng nó giúp! ;)


7
2017-07-21 09:07



Đặt Line Breaks thành "Truncate Tail" là phản trực giác, không cần thiết, và là những gì làm cho ma thuật đột nhiên xảy ra khi bạn có mọi thứ khác thiết lập theo cách bạn mong muốn. Cảm ơn! Có thể xác nhận giới hạn chiều cao không phải là một chiều cao cố định, chỉ có thể được để đính kèm nó vào kích thước container của nó hoặc một tỷ lệ của nó. - Duncan Babbage
@ DuncanBabbage, bạn được chào đón! Vì vậy, chúng ta có thể nói rằng chiều cao của nhãn phải được tính toán bởi trình biên dịch, bằng cách nào đó, với một ràng buộc chiều cao hoặc với tham chiếu của cha mẹ! - Nem


Một phiên bản swifty được điều chỉnh từ @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;
            }
        }
    }
}

7
2018-03-18 21:53



Không làm việc gì cả - Paul Bénéteau
Tương tự - không hoạt động - gabuchan


Tôi thích câu trả lời của DaGaMs, nhưng khi sử dụng các nhãn như trong UITableViewCells có thể được trả về dequeueReusableCell :, kích thước phông chữ thông thường sẽ tiếp tục thu nhỏ ngay cả khi kích thước phông chữ ban đầu vẫn được mong muốn cho một số ô tableView có ít văn bản hơn và có thể tận dụng kích thước phông chữ gốc của nhãn gốc.

vì vậy, tôi bắt đầu với danh mục của DaGaMs như một điểm nhảy, tôi đã tạo một lớp riêng biệt thay vì một danh mục riêng biệt và tôi đảm bảo các UILabels trong bảng phân cảnh của tôi sử dụng lớp mới này:

#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

6
2017-08-03 02:20



1 để giao dịch với UITableViewCells. Nhưng đâu là mã cho giao diện của bạn MultilineAutoShrinkLabel.h? - Rhubarb
@Rhubarb, nó chỉ là tầm thường: lớp con của UILabel với một hàm, - (void)quoteAutoshrinkUnquote; ... và thực sự, tôi đã chuyển sang sử dụng thứ gì đó tương tự nhưng phức tạp hơn một chút so với accessoryView ở bên phải và thực tế là nó có thể có 2 kích thước khác nhau, cho phép nhiều hoặc ít màn hình bất động sản trên mỗi ô. - john.k.doe
Tôi đã sử dụng câu trả lời này để trả lời qeustion của riêng tôi và cũng đã cập nhật mã để loại bỏ các phương pháp không dùng nữa stackoverflow.com/a/30898604/758083 - Hackmodford


câu trả lời của itedcedor có một vấn đề mà pwightman đã chỉ ra. Ngoài ra, không cần phải cắt khoảng trắng. Đây là phiên bản sửa đổi:

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

6
2018-03-18 18:19



Vấn đề tôi đang phải đối mặt bằng cách sử dụng này là văn bản dường như được căn trái bất kể bạn làm gì. Cập nhật: Dường như bỏ chọn "Thắt chặt khoảng cách thư" giải quyết vấn đề đó. - Pierre