Luruskan teks secara vertikal ke atas dalam label UIL

2175

Saya memiliki UILabelspasi dengan dua baris teks. Terkadang, ketika teks terlalu pendek, teks ini ditampilkan di tengah vertikal label.

Bagaimana cara menyelaraskan teks agar selalu berada di atas UILabel?

gambar yang mewakili UILabel dengan teks berpusat vertikal

Stefan
sumber

Jawaban:

2702

Tidak ada cara untuk mengatur vertikal-align 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 untuk memeras label


Jika Anda memiliki label dengan teks yang lebih panjang yang akan menghasilkan lebih dari satu baris, setel numberOfLineske 0(nol di sini berarti jumlah baris yang tidak terbatas).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Teks label lebih panjang dengan sizeToFit


Versi yang lebih panjang

Saya akan membuat label saya dalam kode sehingga Anda dapat melihat apa yang terjadi. Anda dapat mengatur sebagian besar ini di Interface Builder juga. Setup saya adalah Aplikasi Berbasis Tampilan dengan gambar latar belakang yang saya buat di Photoshop untuk menunjukkan margin (20 poin). Labelnya 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 sizeToFitikut bermain dengan teks rata tengah atau kanan. Inilah yang terjadi:

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

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

masukkan deskripsi gambar di sini

Label masih berukuran dengan sudut kiri atas yang diperbaiki. Anda dapat menyimpan lebar label asli dalam variabel dan mengaturnya setelahnya sizeToFit, atau memberinya 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;

pelurusan label


Perhatikan bahwa sizeToFitakan menghormati lebar minimum label awal Anda. Jika Anda mulai dengan label 100 lebar dan memanggilnya sizeToFit, itu akan memberi Anda kembali label (mungkin sangat tinggi) dengan 100 (atau sedikit kurang) lebar. Anda mungkin ingin mengatur label ke lebar minimum yang Anda inginkan sebelum mengubah ukuran.

Memperbaiki pelurusan label dengan mengubah ukuran lebar bingkai

Beberapa hal lain yang perlu diperhatikan:

Apakah lineBreakModedihormati tergantung pada bagaimana pengaturannya. NSLineBreakByTruncatingTail(default) diabaikan setelahnya sizeToFit, seperti halnya dua mode pemotongan lainnya (kepala dan tengah). NSLineBreakByClippingjuga diabaikan. NSLineBreakByCharWrappingbekerja seperti biasa. Lebar bingkai masih menyempit agar pas dengan huruf paling kanan.


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

Jika label Anda termasuk dalam nib atau storyboard sebagai subview dari viewViewController yang menggunakan autolayout, maka memasukkan sizeToFitpanggilan Anda ke dalam viewDidLoadtidak akan berhasil, karena ukuran autolayout dan posisi subview setelah viewDidLoaddipanggil dan akan segera membatalkan efek dari Anda sizeToFitpanggilan. Namun, panggilan sizeToFitdari dalam viewDidLayoutSubviews akan berhasil.


Jawaban Asli Saya (untuk anak cucu / referensi):

Ini menggunakan NSStringmetode sizeWithFont:constrainedToSize:lineBreakMode:untuk menghitung tinggi bingkai yang dibutuhkan agar pas dengan string, kemudian menetapkan asal dan lebar.

Ubah ukuran bingkai untuk label menggunakan teks yang ingin Anda masukkan. Dengan begitu Anda dapat mengakomodasi sejumlah garis.

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;
raja nevan
sumber
10
Anda perlu menghapus autolayout
hungbm06
4
Berikut cara sederhana untuk menyelesaikan masalah: stackoverflow.com/a/26632490/636559
AboulEinein
Jika Anda menggunakan tata letak otomatis dan papan cerita, menambahkan kendala dengan opsi "Hapus saat membangun" dicentang akan membantu
JK ABC
Jika Anda perlu ini bekerja dengan adjustsFontSizeToFitWidthkemudian gunakan sizeToFit kemudian atur bingkai label ke 0, 0, theWidthYouWant, label.frame.size.height (yang merupakan ketinggian baru ditentukan oleh sizeToFit) MAKA berlakuadjustsFontSizeToFitWidth
Albert Renshaw
3
Jawaban ini tidak perlu rumit dan menggunakan "kata-kata". Silakan lihat saran di bawah ini hanya dengan mengubah prioritas memeluk konten vertikal. Tidak memerlukan kode apa pun ...
beetree
335
  1. Setel teks baru:

    myLabel.text = @"Some Text"
  2. Setel maximum numberbaris ke 0 (otomatis):

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

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

    [myLabel sizeToFit]

Bingkai label sekarang cukup tinggi dan cukup lebar untuk disesuaikan dengan teks Anda. Kiri atas harus tidak berubah. Saya telah menguji ini hanya dengan teks rata kiri atas. Untuk penyejajaran lainnya, Anda mungkin harus memodifikasi frame sesudahnya.

Juga, label saya memiliki pembungkusan kata diaktifkan.

Jakob Egger
sumber
Hei Ben, saya hanya melihat kode lama saya lagi, dan memperbarui jawaban saya dengan langkah-langkah yang benar diperlukan.
Jakob Egger
Ini bekerja dengan baik untuk saya. Saya mengatur dimensi UILabel saya dan mengubah numberOfLines menjadi 0 di IB dan kemudian setelah mengatur teks yang disebut [myLabel sizeToFit].
Dan Ellis
berfungsi dengan baik untuk saya, setelah menetapkan jumlah baris di Attr. Inspektur
d2burke
Tidak berfungsi jika jumlah garis lebih dari 1
Tom
Tidak berfungsi saat Anda menginginkan label dua baris, tetapi teks membutuhkan lebih banyak baris.
Jose Manuel Abarca Rodríguez
159

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 "];

Diperlukan ruang tambahan di setiap baris baru yang ditambahkan, karena UILabelspengembalinya trailing iPhone tampaknya diabaikan :(

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

Ekstensi berikut ini 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

Kemudian panggil [yourLabel alignTop];atau [yourLabel alignBottom];setelah setiap tugas teks Label Anda.

Dmitri Sologoubenko
sumber
@ DS Saya perhatikan bahwa Anda menambahkan VerticalAlignantara kurung setelah @implementation UILabel. Menjadi orang baru di Objective-C saya belum pernah menjalankan sintaks ini sebelumnya. Apa ini namanya?
Julian
Luar biasa, tidak tahu tentang kategori, ini memberi saya penghargaan lebih untuk bahasa Objective-c. Mempelajari lebih banyak bahasa sangat penting untuk menjadi programmer yang baik.
JeroenEijkhof
Memberi upvote. tapi iirc ini tidak akan berfungsi jika Anda tidak tahu jumlah garis yang merupakan penurunan
Tjirp
Saya harus menunjukkan 3 baris teks dan menyelaraskan teks ke atas. Jadi, apakah saya harus mengatur jumlah baris ke 3. Ketika saya mengaturnya menjadi 3, saya melihat "..." jika teksnya kurang (yang cocok dalam satu baris). Bagaimana cara menghindari ini "..."
Satyam
1
Saya memposting hasil edit dari kategori ini, semoga akan segera disetujui. Metode sizeWithFont:constrainedToSize:lineBreakMode:dan sizeWithFont: keduanya disusutkan di iOS7. Juga, kategori ini hanya berfungsi pada label ketika numberOfLines lebih besar dari 0.
timgcarlson
146

Kalau-kalau ada bantuan untuk siapa pun, saya memiliki masalah yang sama tetapi mampu memecahkan masalah hanya dengan beralih dari menggunakan UILabelke menggunakan UITextView. Saya menghargai ini bukan untuk semua orang karena fungsinya sedikit berbeda.

Jika Anda beralih menggunakan UITextView, Anda dapat mematikan semua properti Scroll View dan Interaksi Pengguna Diaktifkan ... Ini akan memaksa itu untuk bertindak lebih seperti label.

masukkan deskripsi gambar di sini

jowie
sumber
1
Tidak yakin bagaimana ini akan mempengaruhi kinerja jika banyak UILabel dikonversi ke tampilan teks.
ninjaneer
2
Semua solusi lain di utas ini tidak berfungsi untuk saya di iOS 7 (untuk alasan apa pun). Tetapi hanya menggunakan UITextViewmemberi saya hasil yang diinginkan segera.
Clifton Labrum
1
Ini solusinya, masih perlu beberapa penyesuaian untuk membuatnya terlihat asli, tetapi memang ini adalah solusi tidak ada kode termudah yang saya lihat, diacungi jempol.
Itai Spector
1
Saya suka solusi ini. Memang, mungkin ada masalah kinerja dan semacamnya, untuk label sederhana pada tampilan yang relatif sederhana, ini sempurna untuk apa yang saya butuhkan (dan saya tidak dapat melihat dampak kinerja apa pun)
JCutting8
1
Kelemahan kecil dari metode ini adalah ia akan memperkenalkan padding intrinsik ekstra untuk teks. Perbaikan cepat adalah dengan memperkenalkan kendala negatif.
Sira Lam
122

Tanpa 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 ada Objective-c, tidak ada keributan selain 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)
    }

}

Cepat 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)
    }

}
jasongregori
sumber
Versi cepat berfungsi untuk saya tanpa efek samping! Kerja bagus!
l.vasilev
2
Mungkin jawaban terbaik di sini, berfungsi di semua skenario. sizeToFit tidak berfungsi jika label ada di UITableviewCell. Kerja bagus.
rajat chauhan
79

Seperti jawaban di atas, tetapi itu tidak benar, atau mudah untuk menampar ke dalam kode jadi saya membersihkannya sedikit. Tambahkan ekstensi ini ke file .h dan .m atau tempelkan tepat di atas implementasi 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 untuk menggunakan, masukkan teks Anda ke label, dan kemudian panggil metode yang sesuai untuk menyelaraskannya:

[myLabel alignTop];

atau

[myLabel alignBottom];
BadPirate
sumber
sizeWithFont tidak digunakan lagi
tdios
68

Cara yang bahkan lebih cepat (dan lebih kotor) untuk melakukannya adalah dengan mengatur mode jeda baris UILabel ke "Klip" dan menambahkan sejumlah baris baru.

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

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

Gadis Ninja Ungu
sumber
3
Mengatur mode jeda baris ke 'klip' ​​tampaknya mengacaukan ukuran otomatis label. Gunakan UILineBreakModeWordWrapsebagai gantinya.
Niels van der Rest
dan lebih baik tambahkan spasi "\ n \ n"
djdance
68

Pendekatan termudah menggunakan Storyboard:

Sematkan Label di StackView dan atur dua atribut berikut dari StackView di Attribute Inspector:

1 Axissampai Horizontal,

2- AlignmentkeTop

masukkan deskripsi gambar di sini

Baig
sumber
1
Untuk hasil yang lebih baik Anda dapat melakukan ini StackView> View> UILabel, karena ketika Anda baru saja menanamkan UILabel di dalam StackView, ukuran StackView agar sesuai dengan UILabel ke ukuran minimum
Daniel Beltrami
Ide bagus untuk menempatkan UILabelke dalam beberapa UIViewsubclass (dataran UIViewbiasanya cukup) dan biarkan label itu tumbuh ke bawah arah. Terima kasih!
Viktor Kucera
1
Luar biasa! Perlu juga disebutkan bahwa Anda perlu menghapus batasan pada UILabeldan biarkan StackView melakukan tugasnya. Terima kasih!
Luiz Dias
Dengan perintah menu Editor-> Embed dengan label Anda dipilih, batasan label dihapus untuk Anda oleh Xcode, Anda kemudian dapat mengatur batasan untuk StackView. Pendekatan ini paling dekat dengan pendekatan tata letak 'SwiftUI' yang merupakan cara saya menemukannya.
Rocket Garden
mengapa ini bekerja?
Novellizator
60

Alih-alih UILabelAnda dapat menggunakan UITextFieldyang memiliki opsi perataan vertikal:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
ivanzoid
sumber
7
Peringatan: UITextField hanya memungkinkan satu baris teks.
David James
2
Untuk melengkapi komentar @DavidJames: UITextView akan lebih sesuai
CedricSoubrie
49

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

Ini akan memberi Anda UILabelyang akan menyusutkan teks secara otomatis ke 0,5 skala dan memusatkan teks secara vertikal. Opsi ini juga tersedia di Storyboard / IB.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
David Greco
sumber
Ini bekerja dengan sempurna di antara semua jawaban yang diberikan. Terima kasih @ David Greco. Bersamaan dengan sifat-sifat ini, jika kita mengatur AdjustsFontSizeToFitWidth ke YES maka teks akan masuk ke dalam bingkai tanpa mengubah bingkai label.
Ashok
43

Buat kelas baru

LabelTopAlign

file .h

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

file .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

Edit

Berikut ini adalah implementasi 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
sebastian friedrich
sumber
+1 untuk jawaban sesungguhnya. Tidak seperti sizeToFitsolusi ini sebenarnya membuat teks UILabelmenempatkan apa pun di atas, bahkan jika Anda secara dinamis mengganti teks yang lebih pendek dengan yang lebih lama atau sebaliknya.
SnakE
38

masukkan deskripsi gambar di sini

Di Interface Builder

  • Setel UILabelke ukuran Teks sebesar mungkin
  • Setel Lineske '0' di Atribut Inspektur

Dalam kode Anda

  • Atur teks label
  • Panggil sizeToFitlabel Anda

Cuplikan Kode:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
bearMountain
sumber
bekerja hebat, kecuali dalam kasus saya, saya perlu mengatur baris ke 2 - memiliki UILabel di dalam UITableViewCell dan pengaturan ke 0 membuatnya tumpang tindih, tetapi pengaturan ke 2 berfungsi (sel memiliki cukup ruang untuk 2 baris)
eselk
34

Untuk UI Adaptif (iOS8 atau setelahnya), Penyelarasan Vertikal UILabel harus diatur dari StoryBoard dengan Mengubah properti noOfLines= 0` dan

Kendala

  1. Menyesuaikan UILabel LefMargin, RightMargin, dan Top Margin Constraints.

  2. Ubah Content Compression Resistance Priority For Vertical= 1000` Sehingga Vertikal> Horisontal.

Batasan UILabel

Diedit:

noOfLines=0

dan kendala-kendala berikut cukup untuk mencapai hasil yang diinginkan.

masukkan deskripsi gambar di sini

Rabindra Nath Nandi
sumber
Ini luar biasa. Bisakah Anda menjelaskan mengapa Vertikal> Horizontal melakukan pekerjaan? Terima kasih.
Gabriel
33

Buat subkelas UILabel. Bekerja seperti pesona:

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

Seperti yang dibahas di sini .

Martin Wickman
sumber
27

Saya menulis fungsi util untuk mencapai tujuan ini. Anda dapat melihatnya:

// sesuaikan ketinggian label multi-garis untuk membuatnya sejajar vertikal dengan atas
+ (void) alignLabelWithTop: (UILabel *) label {
  CGSize maxSize = CGSizeMake (label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = TIDAK;

  // dapatkan tinggi sebenarnya
  CGSize actualSize = [label.text sizeWithFont: label.font constrainedToSize: maxSize lineBreakMode: label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}

.Cara Penggunaan? (Jika lblHello dibuat oleh pembangun Antarmuka, maka saya lewati beberapa detail atribut 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];

Saya juga menulisnya di blog saya sebagai artikel: http://fstoke.me/blog/?p=2819

firestoke
sumber
27

Saya perlu beberapa saat untuk membaca kode, serta kode di halaman yang diperkenalkan, dan menemukan bahwa mereka semua mencoba untuk mengubah ukuran bingkai label, sehingga perataan vertikal pusat default tidak akan muncul.

Namun, dalam beberapa kasus kami ingin label untuk menempati semua ruang itu, bahkan jika label memiliki begitu banyak teks (misalnya beberapa baris dengan tinggi yang sama).

Di sini, saya menggunakan cara alternatif untuk menyelesaikannya, cukup dengan menempelkan baris baru ke akhir label (harap dicatat bahwa saya benar-benar mewarisi UILabel, tetapi tidak perlu):

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 "];
}
Walty Yeung
sumber
22

Apa yang saya lakukan di aplikasi saya adalah untuk mengatur properti garis UILabel ke 0 serta untuk membuat batasan bawah dari UILabel dan pastikan sedang diatur ke> = 0 seperti yang ditunjukkan pada gambar di bawah ini. masukkan deskripsi gambar di sini

Jack Tiong
sumber
19

Saya mengambil saran di sini dan membuat tampilan yang dapat membungkus sebuah UILabel dan akan mengukurnya dan mengatur jumlah baris sehingga bagian atas selaras. Sederhananya UILabel sebagai subview:

@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

sumber
19

Anda dapat menggunakan TTTAttributedLabel , ini mendukung perataan vertikal.

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

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
Andrew Romanov
sumber
16

Saya telah menemukan jawaban atas pertanyaan ini sekarang agak ketinggalan zaman, jadi menambahkan ini untuk penggemar tata letak otomatis di luar sana.

Tata letak otomatis membuat masalah ini cukup sepele. Dengan asumsi kami menambahkan label UIView *view, kode berikut akan menyelesaikan ini:

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

Tinggi label akan dihitung secara otomatis (menggunakannya intrinsicContentSize) dan label akan diposisikan ujung ke ujung secara horizontal, di bagian atas view.

petehare
sumber
15

Saya telah menggunakan banyak metode di atas, dan hanya ingin menambahkan pendekatan cepat dan kotor yang saya gunakan:

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

Pastikan jumlah baris baru dalam string akan menyebabkan teks apa pun mengisi ruang vertikal yang tersedia, dan mengatur label UIL untuk memotong teks yang meluap.

Karena kadang-kadang cukup baik cukup baik .

Kode Roadie
sumber
Namun mengingat tingginya variasi ukuran layar perangkat iOS, maka perlu ada sejumlah variabel '\ n' untuk memperhitungkan perubahan ketinggian uilabel (yang merupakan kemungkinan). Dengan demikian metode ini tidak terlalu berguna untuk jangka panjang.
Rambatino
Catatan: "cepat dan kotor" bukan "solusi yang sempurna untuk sepanjang masa." Katakan saja.
Kode Roadie
2
@ CodeRoadie Cepat dan kotor melakukan trik untuk saya, saya punya beberapa masalah tata letak dengan jawaban yang sebenarnya. Saya bisa melakukannya dengan "cara yang benar", tetapi terima kasih telah menghemat waktu!
Séraphin Hochart
@dGambit harap dicatat: "cepat dan kotor "
Kode Roadie
1
Sesuatu yang saya pelajari baru-baru ini ketika secara dinamis memuat tampilan dengan UITextViewitu dapat dipanggil dlopenuntuk mendukung input teks. Ini dapat menyebabkan kelambatan utama pada utas UI, sehingga pendekatan ini jauh lebih hebat!
yano
14

Saya ingin memiliki label yang dapat memiliki multi-baris, ukuran font minimum, dan terpusat secara horizontal dan vertikal dalam tampilan induknya. Saya menambahkan label saya ke tampilan saya secara terprogram:

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

Dan kemudian ketika saya ingin mengubah teks label saya ...

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

Semoga itu bisa membantu seseorang!

Johnus
sumber
14

FXLabel (on github) melakukan ini di luar kotak dengan mengatur label.contentModeke UIViewContentModeTop. Komponen ini tidak dibuat oleh saya, tetapi merupakan komponen yang sering saya gunakan dan memiliki banyak fitur, dan tampaknya berfungsi dengan baik.

jjxtra
sumber
11

bagi siapa pun yang membaca ini karena teks di dalam label Anda tidak terpusat secara vertikal, perlu diingat bahwa beberapa jenis font tidak dirancang sama. misalnya, jika Anda membuat label dengan ukuran zapfino 16, Anda akan melihat teksnya tidak terpusat sempurna secara vertikal.

namun, bekerja dengan helvetica akan memusatkan teks Anda secara vertikal.

Nir Pengas
sumber
Banyak font khusus tidak disejajarkan secara vertikal. UILabel atau UITextView selalu selaras tengah vertikal. Tidak perlu memikirkan perataan vertikal dalam pemrograman iOS.
Amit Singh
11

Gunakan textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        super.drawText(in: textRect)
    }
}
ma11hew28
sumber
Anda tuan adalah tuhan!
Diogo Antunes
1
Jawaban ini harus mendapatkan jauh lebih banyak suara karena sejauh ini merupakan solusi terbaik dan terbersih!
Michael Ochs
10

Subkelas UILabel dan batasi persegi panjang gambar, seperti ini:

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

    [super drawTextInRect:rect];
}

Saya mencoba solusi yang melibatkan pad baris baru dan mengalami perilaku yang salah dalam beberapa kasus. Dalam pengalaman saya, lebih mudah untuk membatasi gambar persegi seperti di atas daripada mengacaukan numberOfLines.

PS Anda dapat membayangkan dengan mudah mendukung UIViewContentMode dengan cara ini:

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

Jika Anda menggunakan pembayaran otomatis, atur konten vertikalHuggingPriority menjadi 1000, baik dalam kode atau IB. Di IB, Anda mungkin harus menghapus batasan ketinggian dengan menetapkan prioritasnya ke 1 dan kemudian menghapusnya.

Phatmann
sumber
8

Selama Anda tidak melakukan apapun tugas yang kompleks, Anda dapat menggunakan UITextViewbukan UILabels.

Nonaktifkan gulir.

Jika Anda ingin teks ditampilkan sepenuhnya hanya pengguna sizeToFitdan sizeThatFits:metode

musim panas ini
sumber
8

Dengan cepat,

let myLabel : UILabel!

Untuk membuat teks dari Label Anda agar sesuai dengan layar dan itu di atas

myLabel.sizeToFit()

Untuk membuat font label Anda agar sesuai dengan lebar layar atau ukuran lebar tertentu.

myLabel.adjustsFontSizeToFitWidth = YES

dan beberapa Penjajaran teks untuk label:

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

Dara Tith
sumber
Hanya perubahan sintaks dari sintaks lama [myLabel sizeToFit]. Terima kasih!
velkoon
7

Ini adalah solusi lama, gunakan autolayout di iOS> = 6

Solusi saya:

  1. Pisahkan garis sendiri (mengabaikan pengaturan bungkus label)
  2. Gambar garis sendiri (mengabaikan pelurusan label)

@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
Sulthan
sumber