จัดแนวข้อความไปด้านบนภายใน UILabel


2175

ฉันมีUILabelช่องว่างสำหรับข้อความสองบรรทัด บางครั้งเมื่อข้อความสั้นเกินไปข้อความนี้จะปรากฏที่กึ่งกลางแนวตั้งของฉลาก

ฉันจะจัดแนวข้อความในแนวตั้งให้อยู่ด้านบนสุดของเสมอได้UILabelอย่างไร

รูปภาพที่แสดง UILabel พร้อมข้อความกึ่งกลางแนวตั้ง

คำตอบ:


2702

ไม่มีวิธีตั้งค่าการจัดแนวตั้งบน a UILabelแต่คุณสามารถได้รับผลกระทบเดียวกันโดยการเปลี่ยนเฟรมของฉลาก ฉันทำให้ป้ายกำกับเป็นสีส้มเพื่อให้คุณสามารถมองเห็นได้ชัดเจนว่าเกิดอะไรขึ้น

นี่เป็นวิธีที่ง่ายและรวดเร็วในการทำสิ่งนี้:

    [myLabel sizeToFit];

ขนาดเหมาะสำหรับบีบป้าย


หากคุณมีป้ายกำกับที่มีข้อความยาวที่จะสร้างมากกว่าหนึ่งบรรทัดให้ตั้งค่าnumberOfLinesเป็น0(ศูนย์ที่นี่หมายถึงไม่ จำกัด จำนวนบรรทัด)

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

ข้อความป้ายกำกับอีกต่อไปด้วย sizeToFit


รุ่นที่ยาวกว่า

ฉันจะทำป้ายกำกับของฉันในรหัสเพื่อให้คุณสามารถเห็นสิ่งที่เกิดขึ้น คุณสามารถตั้งค่าส่วนใหญ่ได้ในเครื่องมือสร้างส่วนต่อประสาน การตั้งค่าของฉันเป็นแอพ View-Based ที่มีภาพพื้นหลังที่ฉันทำใน Photoshop เพื่อแสดงระยะขอบ (20 คะแนน) ฉลากเป็นสีส้มที่น่าดึงดูดดังนั้นคุณสามารถดูว่าเกิดอะไรขึ้นกับขนาด

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 20 point top and left margin. Sized to leave 20 pt at right.
    CGRect labelFrame = CGRectMake(20, 20, 280, 150);
    UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
    [myLabel setBackgroundColor:[UIColor orangeColor]];

    NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
    [myLabel setText:labelText];

    // Tell the label to use an unlimited number of lines
    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    [self.view addSubview:myLabel];
}

ข้อ จำกัด บางประการของการใช้งานsizeToFitมาพร้อมกับข้อความกึ่งกลางหรือชิดขวา นี่คือสิ่งที่เกิดขึ้น:

    // myLabel.textAlignment = NSTextAlignmentRight;
    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

ป้อนคำอธิบายรูปภาพที่นี่

ป้ายยังคงมีขนาดพร้อมมุมบนซ้ายคงที่ คุณสามารถบันทึกความกว้างของฉลากดั้งเดิมในตัวแปรและตั้งค่าตามหลังsizeToFitหรือให้ความกว้างคงที่เพื่อแก้ไขปัญหาเหล่านี้:

    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    CGRect myFrame = myLabel.frame;
    // Resize the frame's width to 280 (320 - margins)
    // width could also be myOriginalLabelFrame.size.width
    myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
    myLabel.frame = myFrame;

การจัดตำแหน่งฉลาก


โปรดทราบว่าsizeToFitจะเคารพความกว้างต่ำสุดของป้ายกำกับเริ่มต้นของคุณ หากคุณเริ่มต้นด้วยป้ายชื่อกว้าง 100 และเรียกsizeToFitใช้มันจะให้ป้ายกลับ (อาจสูงมาก) ที่มีความกว้าง 100 (หรือน้อยกว่า) คุณอาจต้องการตั้งค่าความกว้างต่ำสุดที่คุณต้องการก่อนปรับขนาด

แก้ไขการจัดแนวฉลากโดยปรับขนาดความกว้างของเฟรม

สิ่งอื่น ๆ ที่ควรทราบ:

การlineBreakModeเคารพนั้นขึ้นอยู่กับวิธีการตั้งค่า NSLineBreakByTruncatingTail(ค่าเริ่มต้น) จะถูกข้ามหลังจากsizeToFitนั้นเช่นเดียวกับโหมดการตัดอีกสองโหมด (หัวและกลาง) NSLineBreakByClippingจะถูกละเว้นเช่นกัน NSLineBreakByCharWrappingทำงานได้ตามปกติ ความกว้างของเฟรมยังคงแคบลงเพื่อให้พอดีกับตัวอักษรที่อยู่ด้านขวาสุด


Mark Ameryให้การแก้ไขสำหรับ NIB และกระดานเรื่องราวโดยใช้เค้าโครงอัตโนมัติในความคิดเห็น:

หากป้ายกำกับของคุณรวมอยู่ในปลายปากกาหรือกระดานเรื่องราวเป็นมุมมองย่อยviewของ ViewController ที่ใช้การกำหนดเวลาอัตโนมัติการsizeToFitโทรของคุณviewDidLoadจะไม่ทำงานเนื่องจากขนาดและตำแหน่งของการviewDidLoadเรียกอัตโนมัติหลังจากการเรียกอัตโนมัติและจะยกเลิกผลกระทบของคุณทันทีsizeToFitโทร. อย่างไรก็ตามการโทรsizeToFitจากภายในviewDidLayoutSubviews จะใช้งานได้


คำตอบเดิมของฉัน (สำหรับลูกหลาน / การอ้างอิง):

วิธีนี้ใช้NSStringวิธีsizeWithFont:constrainedToSize:lineBreakMode:การคำนวณความสูงของเฟรมที่ต้องการเพื่อให้พอดีกับสตริงจากนั้นตั้งค่าต้นกำเนิดและความกว้าง

ปรับขนาดเฟรมสำหรับเลเบลโดยใช้ข้อความที่คุณต้องการแทรก ด้วยวิธีนี้คุณสามารถรองรับจำนวนบรรทัดใด ๆ

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

self.dateLabel.frame = dateFrame;

10
คุณต้องลบการ
ชำระอัตโนมัติ

4
ต่อไปนี้เป็นวิธีง่ายๆในการแก้ปัญหา: stackoverflow.com/a/26632490/636559
AboulEinein

หากคุณใช้เลย์เอาต์อัตโนมัติและกระดานเรื่องราวการเพิ่มข้อ จำกัด ด้วยตัวเลือก "ลบที่เวลาสร้าง" จะช่วยให้คุณได้รับการตรวจสอบ
JK ABC

หากคุณต้องการใช้งานด้วยadjustsFontSizeToFitWidthsizeToFit แล้วกำหนดเฟรมของป้ายกำกับเป็น 0, 0, theWidthYouWant, label.frame.size.height (ซึ่งเป็นความสูงใหม่ที่กำหนดโดยขนาด ToFit) จากนั้นadjustsFontSizeToFitWidth
Albert Renshaw

3
คำตอบนี้มีความซับซ้อนเกินจำเป็นและใช้คำว่า "word around" โปรดดูคำแนะนำด้านล่างเพื่อเปลี่ยนลำดับความสำคัญของการแฮ็กเนื้อหาในแนวตั้ง ไม่ต้องใช้รหัสใด ๆ ...
beetree

335
  1. ตั้งค่าข้อความใหม่:

    myLabel.text = @"Some Text"
  2. ตั้งค่าmaximum numberของบรรทัดเป็น 0 (อัตโนมัติ):

    myLabel.numberOfLines = 0
  3. กำหนดเฟรมของฉลากเป็นขนาดสูงสุด:

    myLabel.frame = CGRectMake(20,20,200,800)
  4. โทรsizeToFitเพื่อลดขนาดเฟรมเพื่อให้เนื้อหาพอดี:

    [myLabel sizeToFit]

เฟรมป้ายผนึกตอนนี้สูงและกว้างพอที่จะใส่ข้อความของคุณ มุมซ้ายบนไม่ควรเปลี่ยนแปลง ฉันทดสอบสิ่งนี้ด้วยข้อความที่ชิดซ้ายบนเท่านั้น สำหรับการจัดแนวอื่นคุณอาจต้องแก้ไขเฟรมหลังจากนั้น

นอกจากนี้ป้ายกำกับของฉันยังเปิดใช้งานการตัดคำด้วย


เฮ้เบ็นฉันเพิ่งดูรหัสเก่าของฉันอีกครั้งและอัปเดตคำตอบของฉันด้วยขั้นตอนที่ถูกต้องที่จำเป็น
Jakob Egger

มันใช้ได้ดีสำหรับฉัน ฉันตั้งค่าขนาดของ UILabel ของฉันและเปลี่ยน numberOfLines เป็น 0 ใน IB จากนั้นหลังจากตั้งค่าข้อความที่เรียกว่า [myLabel sizeToFit]
Dan Ellis

ทำงานได้อย่างสมบูรณ์แบบสำหรับฉันหลังจากกำหนดจำนวนบรรทัดใน Attr ผู้ตรวจ
d2burke

ไม่ทำงานในกรณีที่มีจำนวนบรรทัดมากกว่า 1
Tom

มันไม่ทำงานเมื่อคุณต้องการป้ายชื่อของสองบรรทัด แต่ข้อความที่ต้องการบรรทัดเพิ่มเติม
Jose Manuel Abarca Rodríguez

159

อ้างอิงถึงโซลูชันส่วนขยาย:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

ควรถูกแทนที่ด้วย

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

จำเป็นต้องมีพื้นที่เพิ่มเติมในการขึ้นบรรทัดใหม่ทุกครั้งเนื่องจากการขึ้นบรรทัดใหม่ของ iPhone UILabelsจะถูกละเว้น :(

ในทำนองเดียวกัน alignBottom ควรได้รับการอัปเดตด้วย@" \n@%"แทนที่"\n@%"(สำหรับการกำหนดค่าเริ่มต้นของรอบจะต้องแทนที่ด้วย "for (int i = 0 ... " ด้วย)

ส่วนขยายต่อไปนี้ใช้งานได้สำหรับฉัน:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

จากนั้นโทร[yourLabel alignTop];หรือ[yourLabel alignBottom];หลังการมอบหมายข้อความแต่ละข้อความของคุณ


@DS ผมสังเกตเห็นว่าคุณกำลังเพิ่มระหว่างวงเล็บหลังVerticalAlign @implementation UILabelเป็นสิ่งใหม่สำหรับ Objective-C ฉันไม่ได้พบกับไวยากรณ์นี้มาก่อน สิ่งนี้เรียกว่าอะไร?
Julian

น่าทึ่งไม่ทราบเกี่ยวกับหมวดหมู่สิ่งนี้ทำให้ฉันซาบซึ้งมากขึ้นสำหรับภาษา Objective-c การเรียนรู้ภาษาอื่น ๆ มีความสำคัญมากในการเป็นโปรแกรมเมอร์ที่ดี
JeroenEijkhof

ให้ upvote แต่ iirc นี้จะไม่ทำงานหากคุณไม่ทราบจำนวนของสายซึ่งเป็นข้อเสีย
Tjirp

ฉันจะแสดงข้อความ 3 บรรทัดและจัดแนวข้อความขึ้นไปด้านบน ดังนั้นฉันต้องกำหนดจำนวนบรรทัดเป็น 3 เมื่อฉันตั้งเป็น 3 ฉันกำลังเห็น "... " ถ้าข้อความมีค่าน้อยกว่า (เหมาะกับหนึ่งบรรทัด) วิธีหลีกเลี่ยงสิ่งนี้ "... "
Satyam

1
ฉันโพสต์การแก้ไขหมวดหมู่นี้หวังว่าจะได้รับการอนุมัติในไม่ช้า เมธอดsizeWithFont:constrainedToSize:lineBreakMode:และ sizeWithFont: ทั้งค่าเสื่อมราคาใน iOS7 นอกจากนี้หมวดหมู่นี้ใช้งานได้กับป้ายกำกับเมื่อ numberOfLines มากกว่า 0
timgcarlson

146

ในกรณีที่เป็นความช่วยเหลือกับทุกคนใด ๆ ที่ฉันมีปัญหาเดียวกัน แต่ก็สามารถที่จะช่วยแก้ปัญหาได้ง่ายๆโดยการเปลี่ยนจากการใช้กับการใช้UILabel UITextViewฉันชื่นชมสิ่งนี้ไม่ได้มีไว้สำหรับทุกคนเพราะฟังก์ชั่นแตกต่างกันเล็กน้อย

หากคุณสลับไปใช้UITextViewคุณสามารถปิดคุณสมบัติ Scroll View ทั้งหมดรวมถึง User Interaction Enabled ... ซึ่งจะเป็นการบังคับให้ทำหน้าที่เหมือนป้ายกำกับมากขึ้น

ป้อนคำอธิบายรูปภาพที่นี่


1
ไม่แน่ใจว่าสิ่งนี้จะส่งผลกระทบต่อประสิทธิภาพการทำงานอย่างไรหากมีการแปลง UILabels จำนวนมากเป็นมุมมองข้อความ
ninjaneer

2
โซลูชันอื่น ๆ ทั้งหมดในเธรดนี้ใช้ไม่ได้กับฉันใน iOS 7 (ไม่ว่าจะด้วยเหตุผลใดก็ตาม) แต่เพียงใช้UITextViewผลลัพธ์ที่ต้องการในทันที
Clifton Labrum

1
มันเป็นวิธีแก้ปัญหา แต่ก็ยังต้องมีการปรับเปลี่ยนเพื่อให้ดูสมจริง
Itai Spector

1
ฉันชอบวิธีนี้ จริงอยู่ที่อาจมีปัญหาเรื่องประสิทธิภาพและสำหรับป้ายกำกับแบบธรรมดาในมุมมองที่ค่อนข้างเรียบง่ายนี่คือสิ่งที่สมบูรณ์แบบสำหรับสิ่งที่ฉันต้องการ (และฉันไม่สามารถสังเกตเห็นผลกระทบต่อประสิทธิภาพการทำงาน)
JCutting8

1
ข้อเสียเปรียบเล็กน้อยของวิธีนี้คือมันจะแนะนำการเสริมภายในที่พิเศษให้กับข้อความ การแก้ไขด่วนคือการแนะนำข้อ จำกัด เชิงลบ
ศิระลำ

122

ไม่มีความวุ่นวายไม่มีความยุ่งยาก

@interface MFTopAlignedLabel : UILabel

@end


@implementation MFTopAlignedLabel

- (void)drawTextInRect:(CGRect) rect
{
    NSAttributedString *attributedText = [[NSAttributedString alloc]     initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
    rect.size.height = [attributedText boundingRectWithSize:rect.size
                                            options:NSStringDrawingUsesLineFragmentOrigin
                                            context:nil].size.height;
    if (self.numberOfLines != 0) {
        rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
    }
    [super drawTextInRect:rect];
}

@end

ไม่มี muss, no Objective-c, ไม่ยุ่งยาก แต่ Swift 3:

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

สวิฟท์ 4.2

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

เวอร์ชันที่รวดเร็วทำงานให้ฉันโดยไม่มีผลข้างเคียงใด ๆ ! การทำงานที่ดี!
l.vasilev

2
อาจเป็นคำตอบที่ดีที่สุดที่นี่ทำงานได้ในทุกสถานการณ์ sizeToFit ไม่ทำงานหากฉลากอยู่ใน UITableviewCell การทำงานที่ดี.
rajat chauhan

79

เช่นเดียวกับคำตอบข้างต้น แต่มันไม่ถูกต้องหรือง่ายที่จะตบเป็นรหัสดังนั้นฉันจึงทำความสะอาดมันเล็กน้อย เพิ่มส่วนขยายนี้ลงในไฟล์. h และ. m ของตัวเองหรือเพียงวางไว้เหนือการติดตั้งที่คุณต้องการใช้:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

จากนั้นให้ใช้ใส่ข้อความของคุณลงในป้ายกำกับแล้วเรียกวิธีการที่เหมาะสมเพื่อจัดแนว:

[myLabel alignTop];

หรือ

[myLabel alignBottom];

sizeWithFont เลิก
tdios

68

วิธีที่เร็วกว่า (และสกปรกกว่า) ในการทำสิ่งนี้ให้สำเร็จคือการตั้งค่าโหมดการแบ่งบรรทัดของ UILabel เป็น "คลิป" และเพิ่มจำนวนบรรทัดใหม่คงที่

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

โซลูชันนี้จะไม่ทำงานสำหรับทุกคนโดยเฉพาะถ้าคุณยังต้องการแสดง "... " ที่ท้ายสตริงของคุณหากเกินจำนวนบรรทัดที่คุณแสดงคุณจะต้องใช้หนึ่งใน รหัสที่ยาวขึ้น - แต่สำหรับหลาย ๆ กรณีคุณจะได้รับสิ่งที่คุณต้องการ


3
การตั้งค่าโหมดตัวแบ่งบรรทัดเป็น 'คลิป' ดูเหมือนจะทำให้การปรับขนาดฉลากอัตโนมัติ ใช้UILineBreakModeWordWrapแทน
Niels van der Rest

และเพิ่มช่องว่าง "\ n \ n" ดีกว่า
djdance

68

วิธีที่ง่ายที่สุดในการใช้ Storyboard:

Embed LabelในStackViewและตั้งค่าสองแอตทริบิวต์ต่อไปนี้ของ StackView ในตัวตรวจสอบแอตทริบิวต์:

1- AxisไปHorizontal,

2- AlignmentถึงTop

ป้อนคำอธิบายรูปภาพที่นี่


1
เพื่อผลลัพธ์ที่ดีกว่าคุณสามารถทำ StackView นี้> ดู> UILabel เพราะเมื่อคุณฝัง UILabel ใน StackView StackView จะปรับขนาดให้พอดีกับ UILabel ให้มีขนาดเล็กที่สุด
Daniel Beltrami

ความคิดที่ดีUILabelในการวางลงในUIViewคลาสย่อย ( UIViewโดยปกติจะเพียงพอ) และปล่อยให้ฉลากนั้นเติบโตในทิศทางลง ขอบคุณ!
Viktor Kucera

1
! น่ากลัว นอกจากนี้ยังเป็นมูลค่าการกล่าวขวัญว่าคุณจำเป็นต้องล้างข้อ จำกัดในการUILabelและให้ StackView ทำงานของมัน ขอบคุณ!
Luiz Dias

ด้วยคำสั่งเมนู Editor-> ฝังที่เลือกเลเบลของคุณข้อ จำกัด เลเบลจะถูกล้างสำหรับคุณด้วย Xcode จากนั้นคุณสามารถตั้งค่าข้อ จำกัด สำหรับ StackView ได้ วิธีนี้ใกล้เคียงกับวิธีการจัดวางแบบ 'SwiftUI' ซึ่งเป็นวิธีที่ฉันค้นพบ
Rocket Garden

ทำไมจึงใช้งานได้
Novellizator

60

แทนที่จะเป็นเช่นนั้นUILabelคุณสามารถใช้UITextFieldซึ่งมีตัวเลือกการจัดแนวตั้ง:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction

7
Caveat: UITextField อนุญาตเฉพาะข้อความบรรทัดเดียวเท่านั้น
David James

2
หากต้องการเติมเต็มความคิดเห็น @DavidJames: UITextView จะเหมาะสมกว่า
CedricSoubrie

49

ฉันต่อสู้กับอันนี้มานานแล้วและฉันต้องการแบ่งปันวิธีแก้ปัญหาของฉัน

นี่จะให้ข้อความUILabelที่จะเชื่อมโยงกับคุณอัตโนมัติถึง 0.5 สเกลและจัดกึ่งกลางข้อความในแนวตั้ง ตัวเลือกเหล่านี้มีอยู่ใน Storyboard / IB

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];

มันทำงานได้สมบูรณ์แบบท่ามกลางคำตอบทั้งหมดที่มีให้ ขอบคุณ @David Greco พร้อมกับคุณสมบัติเหล่านี้ถ้าเราตั้งค่า adjustSFontSizeToFitWidth เป็น YES ข้อความจะพอดีกับเฟรมโดยไม่ต้องแก้ไขเฟรมของฉลาก
Ashok

43

สร้างคลาสใหม่

LabelTopAlign

ไฟล์. h

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

ไฟล์. m

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

แก้ไข

ต่อไปนี้เป็นการใช้งานที่ง่ายกว่าซึ่งทำได้เหมือนกัน:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end

+1 สำหรับคำตอบที่แท้จริง ซึ่งแตกต่างจากsizeToFitการแก้ปัญหานี้จริงทำให้UILabelใส่ใด ๆข้อความที่ด้านบนแม้ว่าคุณแบบไดนามิกแทนที่ข้อความสั้นกับอีกหนึ่งหรือในทางกลับกัน
SnakE

38

ป้อนคำอธิบายรูปภาพที่นี่

ในเครื่องมือสร้างส่วนต่อประสาน

  • กำหนดUILabelขนาดของข้อความที่ใหญ่ที่สุดที่เป็นไปได้
  • ตั้งค่าLinesเป็น '0' ในตัวตรวจสอบแอททริบิว

ในรหัสของคุณ

  • ตั้งค่าข้อความของฉลาก
  • โทรหาsizeToFitป้ายกำกับของคุณ

ตัวอย่างโค้ด:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];

ทำงานได้ดียกเว้นในกรณีของฉันฉันจำเป็นต้องตั้งค่าบรรทัดเป็น 2 - มี UILabel ภายใน UITableViewCell และการตั้งค่าเป็น 0 ทำให้มันทับซ้อนกัน แต่การตั้งค่าเป็น 2 ทำงาน (เซลล์มีห้องเพียงพอสำหรับ 2 บรรทัด)
eselk

34

สำหรับ Adaptive UI (iOS8 หรือหลังจากนั้น) การจัดแนวแนวตั้งของ UILabel จะต้องตั้งค่าจากกระดานเรื่องราวด้วยการเปลี่ยนคุณสมบัติ noOfLines= 0` และ

ข้อ จำกัด

  1. การปรับ UILabel LefMargin, RightMargin และข้อ จำกัด ด้านบน

  2. เปลี่ยนContent Compression Resistance Priority For Vertical= 1,000` ดังนั้นแนวตั้ง> แนวนอน

ข้อ จำกัด ของ UILabel

แก้ไข:

noOfLines=0

และข้อ จำกัด ต่อไปนี้ก็เพียงพอที่จะบรรลุผลลัพธ์ที่ต้องการ

ป้อนคำอธิบายรูปภาพที่นี่


มันยอดเยี่ยมมาก คุณช่วยอธิบายได้ไหมว่าทำไมแนวตั้ง> แนวนอนทำงานได้หรือไม่ ขอบคุณ
Gabriel

33

สร้างคลาสย่อยของ UILabel ทำงานเหมือนมีเสน่ห์:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

ตามที่กล่าวไว้ที่นี่


27

ฉันเขียนฟังก์ชัน util เพื่อให้บรรลุวัตถุประสงค์นี้ คุณสามารถดู:

// ปรับความสูงของป้ายกำกับแบบหลายบรรทัดเพื่อให้จัดแนวแนวตั้งกับด้านบน
+ (เป็นโมฆะ) alignLabelWithTop: (UILabel *) ฉลาก {
  CGSize maxSize = CGSizeMake (label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // รับส่วนสูงจริง
  CGSize actualSize = [label.text sizeWithFont: label.font constrainedToSize: maxSize lineBreakMode: label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}

.วิธีใช้? (ถ้า lblHello ถูกสร้างขึ้นโดยตัวสร้างส่วนต่อประสานดังนั้นฉันจะข้ามรายละเอียดแอตทริบิวต์ UILabel บางส่วน)

lblHello.text = @ "Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!";
lblHello.numberOfLines = 5;
[Utils alignLabelWithTop: lblHello];

ฉันยังเขียนมันลงในบล็อกของฉันเป็นบทความ: http://fstoke.me/blog/?p=2819


27

ฉันใช้เวลาสักครู่เพื่ออ่านโค้ดรวมถึงรหัสในหน้าที่แนะนำและพบว่าพวกเขาทั้งหมดพยายามแก้ไขขนาดเฟรมของฉลากเพื่อให้การจัดแนวแนวตั้งศูนย์เริ่มต้นจะไม่ปรากฏขึ้น

อย่างไรก็ตามในบางกรณีเราต้องการให้ป้ายกำกับใช้ช่องว่างเหล่านั้นทั้งหมดแม้ว่าป้ายกำกับจะมีข้อความมากมาย (เช่นหลายแถวที่มีความสูงเท่ากัน)

ที่นี่ฉันใช้วิธีอื่นในการแก้ปัญหาโดยเพียงแค่ขึ้นบรรทัดใหม่ไปยังจุดสิ้นสุดของป้ายกำกับ (โปรดทราบว่าฉันได้รับมรดกจริง ๆ แล้วUILabelแต่ไม่จำเป็น):

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width;    //expected width of label

CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];

int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

for(int i = 0; i < newLinesToPad; i++)
{
    self.text = [self.text stringByAppendingString:@"\n "];
}

22

สิ่งที่ฉันทำในแอพของฉันคือการตั้งค่าคุณสมบัติเส้นของ UILabel เป็น 0 เช่นเดียวกับการสร้างข้อ จำกัด ด้านล่างของ UILabel และตรวจสอบให้แน่ใจว่ามันถูกตั้งค่าเป็น> = 0 ดังแสดงในภาพด้านล่าง ป้อนคำอธิบายรูปภาพที่นี่


19

ฉันทำตามคำแนะนำที่นี่และสร้างมุมมองที่สามารถตัด UILabel และจะปรับขนาดและกำหนดจำนวนบรรทัดเพื่อให้มีการจัดตำแหน่งสูงสุด เพียงใส่ UILabel เป็นมุมมองย่อย:

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end

19

คุณสามารถใช้TTTAttributedLabelซึ่งรองรับการจัดตำแหน่งแนวตั้ง

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;

16

ฉันพบว่าคำตอบสำหรับคำถามนี้ล้าสมัยไปแล้วดังนั้นการเพิ่มสิ่งนี้สำหรับแฟน ๆ เลย์เอาต์อัตโนมัติที่นั่น

เลย์เอาต์อัตโนมัติทำให้ปัญหานี้เล็กน้อย สมมติว่าเรากำลังเพิ่มป้ายกำกับให้UIView *viewรหัสต่อไปนี้จะทำให้สำเร็จ:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

ความสูงของป้ายจะถูกคำนวณโดยอัตโนมัติ (ใช้มันintrinsicContentSize) และฉลากจะถูกวางตำแหน่ง viewEdge-to-ขอบแนวนอนที่ด้านบนของ


15

ฉันใช้วิธีการด้านบนมากมายและต้องการเพิ่มวิธีที่รวดเร็วและสกปรกที่ฉันใช้:

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

ตรวจสอบให้แน่ใจว่าจำนวนบรรทัดใหม่ในสตริงจะทำให้ข้อความใด ๆ เติมเต็มช่องว่างในแนวดิ่งที่มีอยู่และตั้งค่า UILabel ให้ตัดทอนข้อความที่ล้นออกมา

เพราะบางครั้งพอที่ดีคือดีพอ


อย่างไรก็ตามเนื่องจากความผันแปรของความสูงของขนาดหน้าจอของอุปกรณ์ iOS จึงจำเป็นต้องมีหมายเลขตัวแปร '\ n' เพื่ออธิบายความสูงเปลี่ยน uilabel (ซึ่งเป็นไปได้) ดังนั้นวิธีนี้จึงไม่เป็นประโยชน์ในระยะยาว
Rambatino

หมายเหตุ: "รวดเร็วและสกปรก" ไม่ใช่ "โซลูชั่นที่สมบูรณ์แบบตลอดเวลา" เพียงแค่พูดว่า
รหัส Roadie

2
@CodeRoadie เคล็ดลับที่รวดเร็วและสกปรกสำหรับฉันฉันมีปัญหาเรื่องเลย์เอาต์สองสามข้อพร้อมคำตอบที่แท้จริง ฉันทำได้ "ถูกต้อง" แต่ขอบคุณที่ช่วยฉันสักพัก!
Séraphin Hochart

@dGambit โปรดทราบ: "รวดเร็วและสกปรก "
รหัส Roadie

1
บางสิ่งที่ฉันเรียนรู้เมื่อเร็ว ๆ นี้เมื่อโหลดมุมมองแบบไดนามิกUITextViewคือมันสามารถโทรdlopenเพื่อรองรับการป้อนข้อความ สิ่งนี้อาจทำให้เกิดความล่าช้าที่สำคัญในเธรด UI ดังนั้นวิธีนี้จึงมีประสิทธิภาพมากกว่า!
yano

14

ฉันต้องการมีป้ายกำกับที่สามารถมีหลายบรรทัดขนาดตัวอักษรขั้นต่ำและจัดกึ่งกลางทั้งแนวนอนและแนวตั้งในมุมมองหลัก ฉันเพิ่มป้ายกำกับของฉันโดยทางโปรแกรมในมุมมองของฉัน:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

และเมื่อฉันต้องการเปลี่ยนข้อความบนฉลากของฉัน ...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

หวังว่าจะช่วยใครบางคน!


14

FXLabel (บน GitHub)ไม่ออกจากกล่องนี้โดยการตั้งค่าไปlabel.contentMode UIViewContentModeTopฉันไม่ได้ทำส่วนประกอบนี้ แต่เป็นส่วนประกอบที่ฉันใช้บ่อยและมีคุณสมบัติมากมายและดูเหมือนว่าจะทำงานได้ดี


11

สำหรับทุกคนที่อ่านข้อความนี้เนื่องจากข้อความในป้ายกำกับของคุณไม่ได้อยู่กึ่งกลางแนวตั้งโปรดทราบว่าแบบอักษรบางประเภทไม่ได้รับการออกแบบอย่างเท่าเทียมกัน ตัวอย่างเช่นถ้าคุณสร้างป้ายกำกับที่มี zapfino ขนาด 16 คุณจะเห็นข้อความไม่อยู่กึ่งกลางในแนวตั้งอย่างสมบูรณ์

อย่างไรก็ตามการทำงานกับ helvetica จะทำให้ข้อความของคุณอยู่ตรงกลาง


แบบอักษรที่กำหนดเองจำนวนมากไม่ตรงกลางแนวตั้ง UILabel หรือ UITextView จะจัดกึ่งกลางแนวตั้งเสมอ ไม่จำเป็นต้องคิดถึงการจัดแนวตั้งในการเขียนโปรแกรม iOS
Amit Singh

11

textRect(forBounds:limitedToNumberOfLines:)ใช้

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}

คุณเป็นพระเจ้า!
Diogo Antunes

1
คำตอบนี้ควรจะได้รับวิธี upvotes มากขึ้นในขณะที่มันคือไกลโดยที่อร่อยที่สุดและวิธีการแก้ปัญหาที่สะอาด!
Michael Ochs

10

คลาสย่อย UILabel และ จำกัด ขอบเขตการวาดเช่นนี้:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

ฉันลองวิธีแก้ปัญหาที่เกี่ยวข้องกับการขึ้นบรรทัดใหม่และพบพฤติกรรมที่ไม่ถูกต้องในบางกรณี จากประสบการณ์ของผมมันเป็นเรื่องง่ายที่จะ จำกัด การ RECT numberOfLinesในการวาดภาพดังกล่าวกว่ายุ่งกับ

PS คุณสามารถจินตนาการได้อย่างง่ายดายสนับสนุน UIViewContentMode ด้วยวิธีนี้:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}

10

หากคุณกำลังใช้การชำระอัตโนมัติให้ตั้งค่าเนื้อหาแนวดิ่งการใส่ลำดับความสำคัญเป็น 1,000 ไม่ว่าจะเป็นรหัสหรือ IB ใน IB คุณอาจต้องลบข้อจำกัดความสูงโดยการตั้งค่าความสำคัญเป็น 1 แล้วลบออก


8

ตราบใดที่คุณไม่ได้ทำงานที่ซับซ้อนคุณสามารถใช้UITextViewแทนUILabelsแทน

ปิดใช้งานการเลื่อน

หากคุณต้องการให้ข้อความปรากฏอย่างสมบูรณ์เพียงแค่ผู้ใช้sizeToFitและsizeThatFits:วิธีการ


8

อย่างรวดเร็ว

let myLabel : UILabel!

เพื่อทำให้ข้อความของฉลากพอดีกับหน้าจอและอยู่ด้านบน

myLabel.sizeToFit()

เพื่อทำให้แบบอักษรของฉลากให้พอดีกับความกว้างของหน้าจอหรือขนาดความกว้างที่เฉพาะเจาะจง

myLabel.adjustsFontSizeToFitWidth = YES

และการจัดแนวข้อความสำหรับป้ายกำกับ:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified


[myLabel sizeToFit]เพียงแค่มีการเปลี่ยนแปลงของไวยากรณ์จากไวยากรณ์เก่า ขอบคุณ!
velkoon

7

นี่เป็นวิธีแก้ไขปัญหาเก่าใช้การชำระอัตโนมัติใน iOS> = 6

ทางออกของฉัน:

  1. แบ่งบรรทัดด้วยตัวเอง (ไม่สนใจการตั้งค่าการตัดป้ายกำกับ)
  2. วาดเส้นด้วยตนเอง (ละเว้นการจัดแนวฉลาก)

@interface UITopAlignedLabel : UILabel

@end

@implementation UITopAlignedLabel

#pragma mark Instance methods

- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
    float width = self.frame.size.width;

    NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSMutableArray* lines = [NSMutableArray array];

    NSMutableString* buffer = [NSMutableString string];    
    NSMutableString* currentLine = [NSMutableString string];

    for (NSString* word in words) {
        if ([buffer length] > 0) {
            [buffer appendString:@" "];
        }

        [buffer appendString:word];

        if (maxLines > 0 && [lines count] == maxLines - 1) {
            [currentLine setString:buffer];
            continue;
        }

        float bufferWidth = [buffer sizeWithFont:self.font].width;

        if (bufferWidth < width) {
            [currentLine setString:buffer];
        }
        else {
            [lines addObject:[NSString stringWithString:currentLine]];

            [buffer setString:word];
            [currentLine setString:buffer];
        }
    }

    if ([currentLine length] > 0) {
        [lines addObject:[NSString stringWithString:currentLine]];
    }

    return lines;
}

- (void)drawRect:(CGRect)rect {
    if ([self.text length] == 0) {
        return;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, self.textColor.CGColor);
    CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);

    NSArray* lines = [self splitTextToLines:self.numberOfLines];
    NSUInteger numLines = [lines count];

    CGSize size = self.frame.size;
    CGPoint origin = CGPointMake(0.0f, 0.0f);

    for (NSUInteger i = 0; i < numLines; i++) {
        NSString* line = [lines objectAtIndex:i];

        if (i == numLines - 1) {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];            
        }
        else {
            [line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
        }

        origin.y += self.font.lineHeight;

        if (origin.y >= size.height) {
            return;
        }
    }
}

@end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.