ios - محاذاة النص رأسيا إلى الأعلى داخل إايلابيل


لدي UILabel مع مساحة UILabel من النص. في بعض الأحيان، عندما يكون النص قصيرا جدا، يتم عرض هذا النص في المركز الرأسي للتسمية.

كيف يمكن محاذاة النص عموديا ليكون دائما في الجزء العلوي من UILabel ؟




Answers


لا توجد طريقة لتعيين المحاذاة الرأسية على UILabel ، ولكن يمكنك الحصول على نفس التأثير عن طريق تغيير إطار الملصق. لقد جعلت تسميات أورانج حتى تتمكن من رؤية بوضوح ما يحدث.

إليك طريقة سريعة وسهلة للقيام بذلك:

    [myLabel sizeToFit];

إذا كان لديك تسمية ذات نص أطول من شأنها أن تجعل أكثر من سطر واحد، numberOfLines بتعيين numberOfLines إلى 0 (صفر يعني هنا عددا غير محدود من الخطوط).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

إصدار أطول

سأجعل التسمية في التعليمات البرمجية بحيث يمكنك أن ترى ما يجري. يمكنك إعداد معظم هذا في واجهة منشئ جدا. بلدي الإعداد هو التطبيق القائم على عرض مع صورة الخلفية التي أدليت بها في فوتوشوب لإظهار هوامش (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 يعمل كالمعتاد. لا يزال عرض الإطار ضيقا ليتناسب مع الرسالة في أقصى اليمين.

أعطى مارك أميري إصلاحا للالمنشورات القومية والقصص المصورة باستخدام تخطيط السيارات في التعليقات:

إذا تم تضمين التسمية في القالب أو القصة المصورة كعرض فرعي view فيوكونترولر يستخدم أوتولايوت، ثم وضع استدعاء sizeToFit الخاص بك في viewDidLoad لن تعمل، لأن أحجام أوتولايوت والمواقف العامة بعد دعا viewDidLoad وسوف تتراجع على الفور آثار دعوة sizeToFit الخاص بك. ومع ذلك، sizeToFit استدعاء sizeToFit من داخل viewDidLayoutSubviews العمل.

جوابي الأصلي (للأجيال القادمة / مرجع):

يستخدم هذا الأسلوب 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;



  1. تعيين النص الجديد:

    myLabel.text = @"Some Text"
  2. تعيين maximum number الأسطر إلى 0 (تلقائي):

    myLabel.numberOfLines = 0
  3. تعيين إطار التسمية إلى الحد الأقصى للحجم:

    myLabel.frame = CGRectMake(20,20,200,800)
  4. استدعاء sizeToFit لتقليل حجم الإطار حتى محتويات تناسب فقط:

    [myLabel sizeToFit]

إطار التسميات الآن مرتفع وعريض بما فيه الكفاية لتناسب النص الخاص بك. يجب أن يكون أعلى اليسار دون تغيير. لقد اختبرت هذا فقط مع أعلى اليسار النص الانحياز. بالنسبة إلى التنسيقات الأخرى، قد تضطر إلى تعديل الإطار بعد ذلك.

أيضا، بلدي التسمية لديه كلمة التفاف تمكين.




الرجوع إلى حل التمديد:

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

هناك حاجة إلى مساحة إضافية في كل خط جديد مضاف، لأنه UILabels فون UILabels 'زائدة عوائد النقل ليتم تجاهلها :(

وبالمثل، يجب تحديث لينبوتوم أيضا مع @" \n@%" بدلا من "\n@%" (لتهيئة دورة يجب أن يتم استبدال "ل (إنت 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]; بعد كل تعيين نص يورابيل.




فقط في حالة انها من أي مساعدة لأحد، كان لي نفس المشكلة ولكن كان قادرا على حل المشكلة ببساطة عن طريق التحول من استخدام UILabel لاستخدام UITextView . وأنا أقدر هذا ليس للجميع لأن وظيفة مختلفة قليلا.

إذا قمت بالتبديل إلى استخدام UITextView ، يمكنك إيقاف تشغيل كافة خصائص العرض التمرير وكذلك التفاعل المستخدم تمكين ... وهذا UITextView على التصرف أكثر مثل التسمية.




مثل الجواب أعلاه، لكنه لم يكن صحيحا تماما، أو من السهل أن صفعة في التعليمات البرمجية لذلك أنا تنظيفه قليلا. أضف هذه الإضافة إما لملف .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];



لا موس، لا ضجة

@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

لا موس، لا الهدف- ج، لا ضجة ولكن سويفت 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)
    }

}



طريقة أسرع (وأكثر رطبة) لتحقيق ذلك هي عن طريق تعيين وضع كسر خط ييلابيل إلى "كليب" وإضافة مبلغ ثابت من الخطوط الجديدة.

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

لن يعمل هذا الحل للجميع - على وجه الخصوص، إذا كنت لا تزال تريد إظهار "..." في نهاية السلسلة إذا تجاوز عدد الأسطر التي تظهرها، فستحتاج إلى استخدام أحد البتات أطول من التعليمات البرمجية - ولكن بالنسبة لكثير من الحالات هذا سوف تحصل على ما تحتاجه.




بدلا من UILabel يمكنك استخدام UITextField الذي لديه خيار المحاذاة العمودية:

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



لقد صارعت مع هذا واحد لفترة طويلة وأردت أن حصة حل بلدي.

هذا وسوف تعطيك UILabel شأنها أن UILabel النص وصولا الى 0.5 المقاييس ومركز رأسيا النص. تتوفر هذه الخيارات أيضا في القصة المصورة / يب.

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



إنشاء فئة جديدة

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



في واجهة منشئ

  • تعيين UILabel لحجم أكبر نص ممكن
  • تعيين Lines إلى '0' في سمات المفتش

في التعليمات البرمجية

  • تعيين نص التسمية
  • استدعاء sizeToFit على التسمية

مقتطف الشفرة:

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



إنشاء فئة فرعية من إيليابيل. يعمل كالسحر:

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

كما نوقش هنا .




كتبت وظيفة استخدام لتحقيق هذا الغرض. يمكنك إلقاء نظرة:

// adjust the height of a multi-line label to make it align vertical with top
+ (void) alignLabelWithTop:(UILabel *)label {
  CGSize maxSize = CGSizeMake(label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // get actual height
  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.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




أخذت بعض الوقت لقراءة التعليمات البرمجية، وكذلك التعليمات البرمجية في الصفحة المقدمة، ووجدت أنها جميعا في محاولة لتعديل حجم الإطار من التسمية، بحيث لا تظهر المحاذاة العمودية مركز الافتراضي.

ومع ذلك، في بعض الحالات نحن لا نريد تسمية لاحتلال كل تلك المساحات، حتى لو كان التسمية لديها الكثير من النص (على سبيل المثال صفوف متعددة مع ارتفاع متساو).

هنا، استخدمت طريقة بديلة لحلها، ببساطة عن طريق لوحة جديدة إلى نهاية التسمية (الثابتة والمتنقلة علما بأنني ورثت فعلا 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 "];
}



ل أوي التكيف (iOS8 أو بعد)، محاذاة العمودية من إيليابيل هو أن يتم تعيين من ستوريبوارد عن طريق تغيير خصائص noOfLines = 0` و

القيود

  1. ضبط ييلابيل ليفارجين، ريتمارجين وأعلى الهامش القيود.

  2. تغيير Content Compression Resistance Priority For Vertical لرأسي = 1000` بحيث عمودي> أفقي.

تعديل:

noOfLines=0

والقيود التالية كافية لتحقيق النتائج المرجوة.




أخذت الاقتراحات هنا وخلق وجهة نظر التي يمكن التفاف على إيليابيل وسوف حجمه وتعيين عدد من خطوط بحيث يتم محاذاة أعلى. ببساطة إيليابيل باعتبارها سوبفيو:

@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



يمكنك استخدام تاتتوستيدلابيل ، وهو يدعم المحاذاة العمودية.

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

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



لقد وجدت الإجابات على هذا السؤال هي الآن قليلا من التاريخ، لذلك إضافة هذا لمحبي تخطيط السيارات هناك.

تخطيط السيارات يجعل هذه المسألة تافهة جدا. على افتراض أننا نقوم بإضافة التسمية إلى UIView *view ، 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 ) وسيتم وضع التسمية من الحافة إلى الحافة أفقيا، أعلى view .




أردت أن يكون لها تسمية التي كانت قادرة على أن يكون خطوط متعددة، والحد الأدنى لحجم الخط، وتركز على حد سواء أفقيا وعموديا في وجهة نظر الأم. لقد أضفت التسمية برمجيا إلى وجهة نظري:

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

نأمل أن يساعد شخص ما!




فكسلابيل (على جيثب) يفعل ذلك من خارج منطقة الجزاء عن طريق وضع label.contentMode إلى label.contentMode . هذا المكون لم يتم من قبل لي، وإنما هو عنصر يمكنني استخدامها في كثير من الأحيان ولها طن من الميزات، ويبدو أن تعمل بشكل جيد.




لقد استخدمت الكثير من الأساليب المذكورة أعلاه، وأريد فقط إضافة نهج سريع وقذر استخدمته:

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

تأكد من أن عدد الخطوط الجديدة في السلسلة سيسبب أي نص لملء المساحة العمودية المتاحة، وتعيين إايلابيل لاقتطاع أي نص متدفق.

لأنه في بعض الأحيان جيدة بما فيه الكفاية جيدة بما فيه الكفاية .




لأي شخص يقرأ هذا لأن النص داخل التسمية الخاصة بك لا تركز عموديا، نضع في اعتبارنا أن بعض أنواع الخط ليست مصممة على قدم المساواة. على سبيل المثال، إذا قمت بإنشاء تسمية مع حجم زابفينو 16، سترى النص لا تتمركز بشكل عمودي تماما.

ومع ذلك، فإن العمل مع هلفيتيكا مركز عموديا النص الخاص بك.




الفئة الفرعية ييلابيل وتقييد مستطيل الرسم، مثل هذا:

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

    [super drawTextInRect:rect];
}

حاولت الحل التي تنطوي على حشو الخط الجديد وركض إلى سلوك غير صحيح في بعض الحالات. في تجربتي، فإنه من الأسهل لتقييد الرسم المستقيم كما هو موضح أعلاه من الفوضى مع numberOfLines .

بس يمكنك أن تتخيل بسهولة دعم إيفيوكونتينتمود بهذه الطريقة:

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



إذا كنت تستخدم أوتولايوت، تعيين المحتوى الرأسيأصعب الأولوية إلى 1000، إما في التعليمات البرمجية أو يب. في يب قد تضطر بعد ذلك لإزالة قيود الارتفاع عن طريق تعيين الأولوية إلى 1 ثم حذفه.




طالما أنك لا تفعل أي مهمة معقدة، يمكنك استخدام UITextView بدلا من UILabels .

تعطيل التمرير.

إذا كنت ترغب في أن يتم عرض النص تماما sizeToFit المستخدم فقط sizeToFit sizeThatFits: أساليب




إذا كان إنشاء طريقة العرض المخصصة الخاصة بك خيارا، يمكنك فعل شيء من هذا القبيل:

- (void)drawRect:(CGRect)rect
{
    CGRect bounds = self.bounds;
    [self.textColor set];
    [self.text drawInRect:bounds
                 withFont:self.font
            lineBreakMode:UILineBreakModeTailTruncation
                alignment:self.textAlignment];
}



هذا هو الحل القديم، استخدام أوتولايوت على دائرة الرقابة الداخلية> = 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



I riffed من اقتراح dalewking وأضاف UIEdgeInset للسماح للهامش قابل للتعديل. عمل جميل حولها.

- (id)init
{
    if (self = [super init]) {
        contentEdgeInsets = UIEdgeInsetsZero;
    }

    return self;
}

- (void)layoutSubviews
{
    CGRect localBounds = self.bounds;
    localBounds = CGRectMake(MAX(0, localBounds.origin.x + contentEdgeInsets.left), 
                             MAX(0, localBounds.origin.y + contentEdgeInsets.top), 
                             MIN(localBounds.size.width, localBounds.size.width - (contentEdgeInsets.left + contentEdgeInsets.right)), 
                             MIN(localBounds.size.height, localBounds.size.height - (contentEdgeInsets.top + contentEdgeInsets.bottom)));

    for (UIView *subview in self.subviews) {
        if ([subview isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel*)subview;
            CGSize lineSize = [label.text sizeWithFont:label.font];
            CGSize sizeForText = [label.text sizeWithFont:label.font constrainedToSize:localBounds.size lineBreakMode:label.lineBreakMode];

            NSInteger numberOfLines = ceilf(sizeForText.height/lineSize.height);

            label.numberOfLines = numberOfLines;
            label.frame = CGRectMake(MAX(0, contentEdgeInsets.left), MAX(0, contentEdgeInsets.top), localBounds.size.width, MIN(localBounds.size.height, lineSize.height * numberOfLines)); 
        }
    }
}



كنت أعمل على تلك المشكلة بالذات كذلك، حتى لقد اتخذت الأفكار التي DS و نيفان كينغ وأساسا منها مجتمعة إلى فئة فرعية التي تطبق خاصية المحاذاة العمودية، والذي يسمح لك أيضا لتغيير محاذاة أكثر من مرة واحدة فقط. انها تقترض من UIControlContentVerticalAlignmentنوع وتدعم أيضا UIControlContentVerticalAlignmentFill.

من ما رأيت، numberOfLinesيبدو أن لا طائل منه عندما يتعلق الأمر المحاذاة العمودية، لذلك في هذا فرعية يتم تعيينها دائما إلى 0 عند تطبيق المحاذاة العمودية. أيضا، لا يزال لديك لوضع lineBreakModeنفسك في حال كنت ترغب في تسمية نص متعدد الخطوط.

هناك هو: QALabel على جيثب




في UILabel محاذاة النص عموديا غير ممكن. ولكن، يمكنك تغيير حيوي ارتفاع التسمية باستخدام sizeWithFont:طريقة NSString، ومجرد مجموعة في x و y كما تريد.

يمكنك استخدام UITextField. وهو يدعم peoperty contentVerticalAlignment كما هو فئة فرعية من UIControl. لديك لتعيين بها userInteractionEnabledإلى NO لمنع المستخدم من كتابة النص على ذلك.