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



15 Answers

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

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

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

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

    [myLabel sizeToFit]

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

أيضًا ، تم تمكين التفاف الكلمة الخاصة بي.

ios cocoa-touch uikit uilabel text-alignment

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

كيف أقوم بمحاذاة النص رأسياً ليكون دائماً في قمة UILabel ؟




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

إذا قمت بالتبديل إلى استخدام UITextView ، يمكنك إيقاف تشغيل كافة خصائص Scroll View بالإضافة إلى تمكين تفاعل المستخدم ... 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];



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

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



خلق فئة جديدة

LabelTopAlign

ملف

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

م ملف

#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. يعمل كالسحر:

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

كما ناقشنا here .




حل Storyboard: أبسط وأسهل طريقة هي تضمين Label في StackView وتعيين Axis StackView إلى Horizontal ، Alignment Top في Attribute Inspector من Storyboard.




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

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

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



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

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

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



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

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

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




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

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

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

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




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

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

    [super drawTextInRect:rect];
}

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

ملاحظة: يمكنك تخيل دعم 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];
}



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

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

إذا كنت ترغب في النص ليتم عرضها المستخدم عادل تماما 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];
}



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

استخدام drawRect هو الثمن بعض الشيء في رأيي. الطريقة الصحيحة للحصول على UILabel لمحاذاة رأسيا هو عدم استخدام UILabel. استخدم UITextView (متعدد المسارات UITextField) ولاحظ خاصية المحتوى مثل:

- (UITextView*)textView{
     if(!_textView){
        UIEdgeInsets insets = UIEdgeInsetsMake(0, 50, 0, 5);
        CGRect frame = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
        _textView = [[UITextView alloc]initWithFrame:UIEdgeInsetsInsetRect(frame, insets)];
        _textView.delegate = self;
        _textView.scrollEnabled = YES;
        _textView.bounces = YES;
        _textView.backgroundColor = [UIColor whiteColor];
        [_textView setUserInteractionEnabled:NO];
        [_textView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
    }
    return _textView;
}

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:    (NSDictionary *)change context:(void *)context {
UITextView *tv = object;

CGFloat height = [tv bounds].size.height;
CGFloat contentheight;

#ifdef __IPHONE_7_0
    contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
#else
    contentheight = [tv contentSize].height;
#endif

    switch(self.verticalAlignment) {
        case VerticalAlignmentBottom:{
            CGFloat topCorrect = ([tv bounds].size.height - contentheight);
            topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
        break;
        case VerticalAlignmentMiddle:{
            CGFloat topCorrect = (height - contentheight * [tv zoomScale])/2.0;
            topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
            break;
        case VerticalAlignmentTop:{
            tv.contentOffset = (CGPoint){.x = 0, .y = 0 };
        }
            break;
        default:
            break;
    }
}

بشكل أساسي ما يحدث هنا هو أننا نعين الصف الدراسي الذي نعيش فيه كمراقب ، وننظر إلى خاصية contentSize مع خيار NSKeyValueObservingOptionNew حتى يتم الاتصال في كل مرة يتغير فيها المحتوى ، -(void)observeValueForKeyPath:ofObject:change:context:وبعد ذلك يمكنك حساب حجم الإزاحة لمحاذاة النص بشكل مناسب .

لا أستطيع أخذ الفضل في ذلك ، جاءت الفكرة الأصلية من here . لكن ، هذا الحل لا يعمل على iOS7. بعد التصيد حول SO لبضع ساعات ، وجدت هذا: iOS 7 المحاذاة العمودية الإصلاح . الخط الرئيسي هناكcontentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height; .لسبب ما في iOS 7 ، لا يعمل الحصول على ارتفاع حجم المحتوى ولكن يعمل على إصلاحه. لم يعمل أي من الحلين بمفرده ولكن بعد إجراء بعض التعديلات ، تمكنت من تجميع الحل السابق.




Related