Подтвердить что ты не робот

Условное обозначение заголовка заголовка UIButton с усечением хвоста

Мне нужно включить перенос слов и усечение хвоста, в то же время, на UIButton titleLabel. Установка numberOfLines на что-то большее, чем 0, не работает, текст остается в одной строке.

Я уже обыскал и не нашел решения. Любая идея?

4b9b3361

Ответ 1

Я решил это в тот же день, когда я разместил этот вопрос, поставив UIButton поверх UILabel с numberOfLines, установленным в 3. Я оставил это недопустимым, чтобы увидеть, есть ли у кого-то лучшая идея, но, по-видимому, нет другого решения.

Ответ 2

Это не правильно:

lblTemp.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail
lblTemp.numberOfLines = 0;

NSLineBreakMode определяется в NSParagraphStyle.h как:

typedef NS_ENUM(NSInteger, NSLineBreakMode) {       /* What to do with long lines */
    NSLineBreakByWordWrapping = 0,      /* Wrap at word boundaries, default */
    NSLineBreakByCharWrapping,      /* Wrap at character boundaries */
    NSLineBreakByClipping,      /* Simply clip */
    NSLineBreakByTruncatingHead,    /* Truncate at head of line: "...wxyz" */
    NSLineBreakByTruncatingTail,    /* Truncate at tail of line: "abcd..." */
    NSLineBreakByTruncatingMiddle   /* Truncate middle of line:  "ab...yz" */
} NS_ENUM_AVAILABLE_IOS(6_0);

Обратите внимание, что это NS_ENUM, а не NS_OPTION, поэтому он не предназначен для использования в качестве маски. Для получения дополнительной информации см. this.

В действительности использование оператора | по этим константам приводит к маскировке, соответствующей NSLineBreakByTruncatingTail:

(NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail) == 4
NSLineBreakByTruncatingTail == 4

Насколько я знаю, обрезание последней строки в основном тексте, а также выполнение переносимости слов не могут быть выполнены с помощью простых API CTFramesetterCreateWithAttributedString и CTFrameDraw, но это может быть сделано с построением строки за строкой, который должен выполнять UILabel.

iOS 6 упрощает это, открывая новые API-интерфейсы рисования в NSStringDrawing.h:

typedef NS_ENUM(NSInteger, NSStringDrawingOptions) {
    NSStringDrawingTruncatesLastVisibleLine = 1 << 5, // Truncates and adds the ellipsis character to the last visible line if the text doesn't fit into the bounds specified. Ignored if NSStringDrawingUsesLineFragmentOrigin is not also set.
    NSStringDrawingUsesLineFragmentOrigin = 1 << 0, // The specified origin is the line fragment origin, not the base line origin
    NSStringDrawingUsesFontLeading = 1 << 1, // Uses the font leading for calculating line heights
    NSStringDrawingUsesDeviceMetrics = 1 << 3, // Uses image glyph bounds instead of typographic bounds
} NS_ENUM_AVAILABLE_IOS(6_0);

@interface NSAttributedString (NSExtendedStringDrawing)
- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);
@end

Итак, если вы используете UILabel, вы хотите, чтобы ваш NSAttributedString NSParagraphStyle или lineBreakMode на самой этикетке устанавливали:

NSLineBreakByTruncatingTail

И свойство numberOfLines на ярлыке должно установить на 0.

Из заголовков UILabel на numberOfLines:

// if the height of the text reaches the # of lines or the height of the view is less than the # of lines allowed, the text will be
// truncated using the line break mode.

Из документации UILabel:

This property controls the maximum number of lines to use in order to fit the label’s text into its bounding rectangle. The default value for this property is 1. To remove any maximum limit, and use as many lines as needed, set the value of this property to 0.
If you constrain your text using this property, any text that does not fit within the maximum number of lines and inside the bounding rectangle of the label is truncated using the appropriate line break mode.

Единственная проблема, которая возникает с этой несколько неясной особенностью UILabel, заключается в том, что вы не можете получить размер перед рисованием (что необходимо для некоторых динамических макетов UITableView + UITableViewCell), не прибегая к модификации NSAttributedString NSParagraphStyle на лету.

Как и в iOS 6.1.4, вызов -boundingRectWithSize: options: context с NSAttributedString, который имеет режим прерывания строки NSLineBreakByTruncatingTail (для UILabel), возвращает неверную высоту одной строки, даже если следующие параметры передаются в:

(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine)

(Обратите внимание, что NSStringDrawingUsesLineFragmentOrigin является необходимостью для многострочных строк.)

Что еще хуже, так это то, что UILabel lineBreakMode делает не переопределять стиль абзаца NSAttributedStrings, поэтому вам нужно изменить стиль атрибута строки атрибута для расчета размера, а затем передать его в UILabel, чтобы он может нарисовать его.

То есть NSLineBreakByWordWrapping для -boundingRectWithSize: options: context и NSLineBreakByTruncatingTail для UILabel (чтобы он мог, использовать NSStringDrawingTruncatesLastVisibleLine внутри или что бы он ни делал, чтобы обрезать последнюю строку)

Единственная альтернатива, если вы не хотите изменять стиль абзаца строк более чем один раз, - это сделать простой подкласс UIView, который переопределяет -drawRect: (с соответствующим набором contentMode, который также будет перерисовываться), и использует iOS 6 новый API для рисования:

- (void)drawWithRect:(CGRect)rect options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context NS_AVAILABLE_IOS(6_0);

Вспомним использование NSLineBreakByWordWrapping и передачу (NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine) в качестве параметров.

Наконец, перед iOS 6, если вы хотите сделать перенос слов + укорочение хвоста для атрибутной строки, вам придется выполнять линейную компоновку самостоятельно с помощью Core Text.

Ответ 3

[self.costomButton.titleLabel setTextAlignment:UITextAlignmentLeft];
[self.costomButton.titleLabel setNumberOfLines:3];

Убедитесь, что вы должны сначала установить Alignment ps: это работает только тогда, когда версия системы больше 5.0

Ответ 4

Попробуйте установить numberOfLines более 2 и соответственно установите высоту.

    m_button = [UIButton buttonWithType:UIButtonTypeCustom];
[m_button setFrame:CGRectMake(isLandscape?20:10, 40, isLandscape?300:250, 40)];
m_button.titleLabel.font  = [UIFont fontWithName:@"HelveticaNeue" size:17];
[m_btnDiscoverPoint setTitle:@"Title" forState:UIControlStateNormal];
CGRect buttonFrame = [m_button frame];

if ([m_button.titleLabel.text length]>0) {
    CGSize suggestedSize = [m_button.titleLabel.text sizeWithFont:[UIFont fontWithName:@"HelveticaNeue" size:17] constrainedToSize:CGSizeMake(FLT_MAX,m_button.frame.size.height) lineBreakMode:UILineBreakModeWordWrap];

    if (suggestedSize.width >= self.view.frame.size.width) {
        suggestedSize.width = self.view.frame.size.width-10;
        suggestedSize.height=suggestedSize.height+20;
        m_button.titleLabel.numberOfLines=2;
    }
    else{
        m_button.titleLabel.numberOfLines=1;
    }

    buttonFrame.size.width = suggestedSize.width;

    [m_button setFrame:buttonFrame];
}
[m_button setBackgroundColor:[UIColor clearColor]];
[m_button addTarget:self action:@selector(btnClickAction) forControlEvents:UIControlEventTouchUpInside];

Ответ 5

button.titleLabel.numberOfLines = 2;
button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
UIFont * theFont = [UIFont systemFontOfSize: 14]; // you set
CGSize textSize = [titleStr sizeWithAttributes:@{NSFontAttributeName: theFont}];
CGFloat theWidth = kScreenWidth-otherWidthYouSet;// I thought the button frame is content driving ,and is limited 
CGFloat ratio = theWidth*heightYouSet/((textSize.width+4)*(textSize.height+6));// 4 , 6 , is made by experience . I think the textSize is taken one line text default by the system 
NSUInteger validNum = ratio * titleStr.length;

if(ratio<1){
    [button setTitle: [[titleStr substringToIndex: validNum] stringByAppendingString: @"..."] state: yourState];

}
else{
    [button setTitle: titleStr state: yourState];
}

Ответ 6

Вы можете указать несколько меток lineBreakMode на ярлыке, используя побитовый оператор OR.

Например, следующий код обернет текст метки и добавит эллипсис в конец текста, когда он будет расширен за пределы высоты рамки метки.

lblTemp.lineBreakMode = UILineBreakModeWordWrap | UILineBreakModeTailTruncation;
lblTemp.numberOfLines = 0;

UPDATE: это неверно. Кажется, он работает, потому что UILineBreakModeWordWrap равно 0 в перечислении. См. Комментарии ниже.

Ответ 7

Все свойства пользовательского интерфейса устарели в iOS. Используйте аббревиатуры NS вместо пользовательского интерфейса. Как здесь показано здесь - NSLineBreakByTruncatingMiddle