Pertanyaan Menyesuaikan teks secara vertikal ke atas dalam UILabel


Saya punya UILabel dengan ruang untuk dua baris teks. Kadang-kadang, ketika teks terlalu pendek, teks ini ditampilkan di pusat vertikal label.

Bagaimana cara menyesuaikan teks secara vertikal agar selalu berada di atas UILabel?

image representing a UILabel with vertically-centered text


1984
2018-06-28 08:54


asal


Jawaban:


Tidak ada cara untuk mengatur garis vertikal pada UILabel, tetapi Anda bisa mendapatkan efek yang sama dengan mengubah bingkai label. Saya telah membuat label saya berwarna oranye sehingga Anda dapat melihat dengan jelas apa yang terjadi.

Inilah cara cepat dan mudah untuk melakukan ini:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


Jika Anda memiliki label dengan teks yang lebih panjang yang akan membuat lebih dari satu baris, atur numberOfLines untuk 0 (nol di sini berarti jumlah baris yang tidak terbatas).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Versi Lebih Lama

Saya akan membuat label saya dalam kode sehingga Anda dapat melihat apa yang terjadi. Anda dapat mengatur sebagian besar ini di Interface Builder juga. Pengaturan saya adalah Aplikasi Berbasis Tampilan dengan gambar latar belakang yang saya buat di Photoshop untuk menunjukkan margin (20 poin). Label adalah warna oranye yang menarik sehingga Anda dapat melihat apa yang terjadi dengan dimensi.

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

Beberapa batasan penggunaan sizeToFit ikut bermain dengan teks tengah atau kanan rata. Inilah yang terjadi:

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

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

enter image description here

Label masih berukuran dengan sudut kiri-kiri tetap. Anda dapat menyimpan lebar label asli dalam variabel dan mengaturnya setelah sizeToFit, atau berikan lebar tetap untuk mengatasi masalah ini:

    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;

label alignment


Perhatikan itu sizeToFit akan menghormati lebar minimum label awal Anda. Jika Anda mulai dengan label 100 lebar dan panggilan sizeToFit di atasnya, ia akan mengembalikan label (mungkin sangat tinggi) dengan lebar 100 (atau sedikit lebih sedikit). Anda mungkin ingin mengatur label Anda ke lebar minimum yang Anda inginkan sebelum mengubah ukuran.

Correct label alignment by resizing the frame width

Beberapa hal lain yang perlu diperhatikan:

Apakah lineBreakMode dihormati tergantung pada bagaimana itu diatur. NSLineBreakByTruncatingTail (default) diabaikan setelahnya sizeToFit, seperti dua mode pemotongan lainnya (kepala dan tengah). NSLineBreakByClipping juga diabaikan. NSLineBreakByCharWrapping bekerja seperti biasa. Lebar bingkai masih menyempit agar pas dengan huruf paling kanan.


Mark Amery memberi perbaikan untuk NIB dan Storyboard menggunakan Tata Letak Otomatis di komentar:

Jika label Anda termasuk dalam nib atau storyboard sebagai subview dari view dari ViewController yang menggunakan autolayout, kemudian menempatkan Anda sizeToFit panggilan ke viewDidLoad tidak akan berfungsi, karena ukuran autolayout dan posisi subview setelahnya viewDidLoad dipanggil dan akan segera membatalkan efek dari Anda sizeToFit panggilan. Namun, menelepon sizeToFit dari dalam viewDidLayoutSubviews  akan kerja.


Jawaban Asli Saya (untuk anak cucu / referensi):

Ini menggunakan NSString metode sizeWithFont:constrainedToSize:lineBreakMode: untuk menghitung tinggi frame yang diperlukan agar sesuai dengan string, lalu setel asal dan lebar.

Ubah ukuran bingkai untuk label menggunakan teks yang ingin Anda sisipkan. Dengan cara itu Anda dapat mengakomodasi sejumlah baris.

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;

2561
2018-06-28 10:36



  1. Setel teks baru:

    myLabel.text = @"Some Text"
    
  2. Mengatur maximum number dari garis ke 0 (otomatis):

    myLabel.numberOfLines = 0
    
  3. Atur bingkai label ke ukuran maksimum:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Panggilan sizeToFit untuk mengurangi ukuran bingkai sehingga isinya pas:

    [myLabel sizeToFit]
    

Bingkai label sekarang cukup tinggi dan cukup lebar untuk menyesuaikan teks Anda. Bagian kiri atas tidak akan berubah. Saya telah menguji ini hanya dengan teks rata kiri atas. Untuk keberpihakan lainnya, Anda mungkin harus memodifikasi bingkai sesudahnya.

Juga, label saya memiliki pembungkusan kata yang diaktifkan.


315
2017-08-27 16:24



Mengacu pada solusi ekstensi:

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

harus diganti oleh

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

Ruang tambahan diperlukan di setiap baris baru yang ditambahkan, karena iPhone UILabels'Pengembalian carriage trailing tampaknya diabaikan :(

Demikian pula, alignBottom harus diperbarui juga dengan @" \n@%" di tempat "\n@%" (untuk inisialisasi siklus harus diganti dengan "untuk (int i = 0 ..." juga).

Ekstensi berikut berfungsi untuk saya:

// -- 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

Lalu telepon [yourLabel alignTop]; atau [yourLabel alignBottom]; setelah setiap tugas teks label Anda.


151
2017-09-09 13:01



Untuk berjaga-jaga kalau itu membantu siapa pun, saya memiliki masalah yang sama tetapi mampu memecahkan masalah hanya dengan beralih dari menggunakan UILabel untuk menggunakan UITextView. Saya menghargai ini bukan untuk semua orang karena fungsinya sedikit berbeda.

Jika Anda beralih menggunakan UITextView, Anda dapat mematikan semua properti Tampilan Gulir serta Interaksi Pengguna Diaktifkan ... Ini akan memaksa untuk bertindak lebih seperti label.

enter image description here


126
2017-10-05 12:46



Tidak ada muss, tidak repot

@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

Tidak ada muss, tidak Objective-c, tidak repot tapi 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)
    }

}

80
2018-05-21 07:47



Seperti jawaban di atas, tetapi itu tidak benar, atau mudah untuk menampar kode sehingga saya membersihkannya sedikit. Tambahkan ekstensi ini baik ke file itu sendiri .h dan .m atau tempel tepat di atas penerapan yang ingin Anda gunakan:

#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

Dan kemudian gunakan, masukkan teks Anda ke label, dan kemudian panggil metode yang sesuai untuk menyelaraskannya:

[myLabel alignTop];

atau

[myLabel alignBottom];

76
2018-03-04 02:44



Cara yang lebih cepat (dan lebih kotor) untuk mencapai hal ini adalah dengan mengatur mode jeda baris UILabel ke "Klip" dan menambahkan jumlah baris baru yang tetap.

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

Solusi ini tidak akan berfungsi untuk semua orang - khususnya, jika Anda masih ingin menampilkan "..." di akhir string Anda jika melebihi jumlah baris yang Anda tunjukkan, Anda harus menggunakan salah satu dari bit kode yang lebih panjang - tetapi untuk banyak kasus, ini akan membuat Anda mendapatkan apa yang Anda butuhkan.


66
2018-04-18 21:08



Dari pada UILabel Anda dapat menggunakan UITextField yang memiliki opsi perataan vertikal:

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

56
2018-02-10 10:36



Saya telah berjuang dengan yang satu ini untuk waktu yang lama dan saya ingin berbagi solusi saya.

Ini akan memberi Anda UILabel yang akan menghapus teks otomatis menjadi 0,5 skala dan secara vertikal memusatkan teks. Pilihan ini juga tersedia di Storyboard / IB.

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

47
2017-10-16 16:38



Buat kelas baru

LabelTopAlign

.h file

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m file

#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

Edit

Berikut ini implementasi yang lebih sederhana yang melakukan hal yang sama:

#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

42
2017-08-04 08:07