web-dev-qa-db-fra.com

UIButton Title Wrap Word Wrap avec troncature de la queue

Je dois activer le wrapping Word et la troncature de la queue, en même temps, sur une UIButton's s titleLabel. Définir numberOfLines sur quelque chose de plus que 0 ne fonctionne pas, le texte reste sur une ligne.

J'ai déjà cherché et n'ai pas trouvé de solution. Une idée?

18
pt2ph8

Je l'ai résolue le jour même où j'ai posté cette question en plaçant un UIButton sur un UILabel avec numberOfLines égal à 3. J'avais laissé cela inacceptable pour voir si quelqu'un avait une meilleure idée, mais apparemment, il n'y a pas d'autre solution.

4
pt2ph8

C'est pas correct:

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

NSLineBreakMode est défini dans NSParagraphStyle.h comme suit:

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);

Notez que c'est un NS_ENUM, pas un NS_OPTION, il n'est donc pas destiné à être utilisé comme masque. Pour plus d'informations, voir this .

En réalité, en utilisant le | opérateur sur ces constantes conduit à un masque correspondant à NSLineBreakByTruncatingTail:

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

Autant que je sache, tronquer la dernière ligne de Core Text et effectuer un wrapping de Word ne peut pas être effectué avec la simple CTFramesetterCreateWithAttributedString & CTFrameDraw API , mais peut être fait avec une présentation ligne par ligne, UILabel doit être Faire.

iOS 6 simplifie cela en exposant de nouvelles API de dessin dans 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

Donc, si vous utilisez UILabel, vous voulez que le NSParagraphStyle de votre NSAttributedString ou le lineBreakMode sur le label lui-même soit défini sur:

NSLineBreakByTruncatingTail

Et la propriété numberOfLines sur l'étiquette must doit être définie sur 0.

A partir des en-têtes UILabel sur 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.

Dans la documentation 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.

Le seul problème qui se pose avec cette fonctionnalité un peu obscure d'UILabel est que vous ne pouvez pas obtenir la taille avant de dessiner (ce qui est une nécessité pour certaines dispositions dynamiques UITableView + UITableViewCell) sans avoir à modifier à la volée le NSParagraphStyle de NSAttributedString.

Depuis iOS 6.1.4, appelez -boundingRectWithSize: options: contexte avec une chaîne NSAttributedString possédant un mode de saut de ligne NSLineBreakByTruncatingTail (pour UILabel), renvoie une hauteur de ligne unique incorrecte même si les options suivantes sont passées:

(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine)

(Veuillez noter que NSStringDrawingUsesLineFragmentOrigin est une nécessité pour les chaînes multilignes.)

Ce qui est pire, c’est que lineBreakMode d’UILabel modifie not le style de paragraphe NSAttributedStrings. Vous devez donc modifier le style de paragraphe de votre chaîne attribuée pour votre calcul de dimensionnement, puis pour le transmettre à UILabel afin qu’il puisse le dessiner.

C'est-à-dire, NSLineBreakByWordWrapping pour -boundingRectWithSize: options: context et NSLineBreakByTruncatingTail pour UILabel (utilisez l'option NSStringDrawingTruncatesLastVisibleLine en interne, ou quoi que ce soit pour couper la dernière ligne).

La seule alternative pour ne pas trop modifier le style de paragraphe de votre chaîne consiste à créer une simple sous-classe UIView qui remplace -drawRect: (avec le contentMode approprié défini pour être redessiné également) et à utiliser la nouvelle API de dessin iOS 6. :

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

N'oubliez pas d'utiliser NSLineBreakByWordWrapping et passing (NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine) comme options.

Enfin, avant iOS 6, si vous souhaitiez effectuer le wrapping Word + la troncature de la queue pour une chaîne attribuée, vous devez effectuer vous-même la mise en page ligne par ligne avec Core Text.

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

Assurez-vous de définir Alignment en premier Ps: cela ne fonctionne que lorsque la version du système est supérieure à 5.0.

4
akin
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's 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];
}
0
dengApro

Essayez de définir numberOfLines plus que 2 et réglez la hauteur également en conséquence.

    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];
0
Meet