67 votes

IPhone - UILabel contenant du texte avec des polices de caractères différentes en même temps

Je cherche un moyen d'utiliser un UILabel (ou quelque chose de similaire) pour afficher quelque chose comme ceci :

Tom : Un message.

C'est comme c'est fait par exemple dans l'application Facebook pour afficher les messages "Qu'est-ce qui te passe par la tête ?". Est-ce que quelqu'un a des suggestions sur la façon d'aborder cela ?

0 votes

Pourquoi avez-vous même besoin d'un UILabel, autant que je sache vous pouvez en faire une vue et ajouter autant de UILabel que vous le souhaitez

0 votes

Vous pouvez utiliser les mêmes outils que l'application facebook utilise: three20 Joe Hewitt, le développeur derrière l'application facebook a rendu public une grande partie de son travail. Vous pouvez le trouver ainsi que de nombreuses autres fonctionnalités ici: github.com/joehewitt/three20

0 votes

Vous ne pouvez pas le faire dans un UILabel... Mais ma suggestion est qu'au lieu d'utiliser plusieurs UILabel, concentrez-vous simplement sur NSAttributedString... Trouvez des UIControllers qui dessinent NSAttribute String car UILabel, UITextView ne prend pas en charge NSAttributedString... Contrôleur pour dessiner NSAttributedString

103voto

aarn Points 485

Il existe un moyen de définir différentes polices / propriétés sur un Label en utilisant NSMutableAttributedString. Voici mon code :

 UIFont *arialFont = [UIFont fontWithName:@"arial" size:18.0];
 NSDictionary *arialDict = [NSDictionary dictionaryWithObject: arialFont forKey:NSFontAttributeName];    
 NSMutableAttributedString *aAttrString = [[NSMutableAttributedString alloc] initWithString:title attributes: arialDict];

 UIFont *VerdanaFont = [UIFont fontWithName:@"verdana" size:12.0];
 NSDictionary *verdanaDict = [NSDictionary dictionaryWithObject:VerdanaFont forKey:NSFontAttributeName];
 NSMutableAttributedString *vAttrString = [[NSMutableAttributedString alloc]initWithString: newsDate attributes:verdanaDict];    
 [vAttrString addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:(NSMakeRange(0, 15))];

 [aAttrString appendAttributedString:vAttrString];

 lblText.attributedText = aAttrString;

Notez que lblText est le UILabel, connecté en tant que propriété du fichier propriétaire. On peut continuer à ajouter autant de NSMutableAttributedString qu'on le souhaite.

Notez également que j'ai ajouté les polices verdana et arial dans mon projet et ajouté un fichier plist pour les mêmes.

10 votes

Gardez à l'esprit que attributedText de UILabel est disponible depuis iOS 6.0!

0 votes

Merci pour cette solution. Très utile.

0 votes

La combinaison de -initWithString:attributes: et -appendAttributedString: fonctionne magnifiquement et rend cela très facile! Merci beaucoup d'avoir souligné cela.

18voto

Jason Points 924

Mise à jour : Si vous êtes sous iOS 6+, utilisez UILabel.attributedText -- sinon....

J'ai créé cette sous-classe UIView de base pour prendre en charge une fonctionnalité similaire.

La liste des choses qu'elle ne prend pas en charge est plus longue que ce qu'elle fait, mais essentiellement elle vous permet de gérer une seule ligne de UILabel et de formater chaque élément comme vous le souhaitez. Cela me permet d'insérer du texte avec une couleur différente au milieu de la ligne, par exemple, et d'éviter d'utiliser le lourd UIWebView.

Je crée ces objets en plaçant un objet UIView dans mon interface (en utilisant Interface Builder) et en définissant le type de l'objet dans IB sur MultipartLabel. Ensuite, dans le code, j'appelle updateNumberOfLabels et les différents selecteurs setText selon les besoins.

//  MultipartLabel.m
//  MultiLabelLabel
//
//  Created by Jason Miller on 10/7/09.
//  Copyright 2009 Jason Miller. All rights reserved.
//

#import "MultipartLabel.h"

@interface MultipartLabel (Private)
- (void)updateLayout;
@end

@implementation MultipartLabel

@synthesize containerView;
@synthesize labels;

-(void)updateNumberOfLabels:(int)numLabels;
{
 [containerView removeFromSuperview];
 self.containerView = nil;

 self.containerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)] autorelease];
 [self addSubview:self.containerView];
 self.labels = [NSMutableArray array];

 while (numLabels-- > 0) {
  UILabel * label = [[UILabel alloc] initWithFrame:CGRectZero];
  [self.containerView addSubview:label];
  [self.labels addObject:label];
  [label release];
 }

 [self updateLayout];
}

-(void)setText:(NSString *)text forLabel:(int)labelNum;
{
 if( [self.labels count] > labelNum && labelNum >= 0 )
 {
  UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
  thisLabel.text = text;
 }

 [self updateLayout];
}

-(void)setText:(NSString *)text andFont:(UIFont*)font forLabel:(int)labelNum;
{
 if( [self.labels count] > labelNum && labelNum >= 0 )
 {
  UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
  thisLabel.text = text;
  thisLabel.font = font;
 }

 [self updateLayout];
}

-(void)setText:(NSString *)text andColor:(UIColor*)color forLabel:(int)labelNum;
{
 if( [self.labels count] > labelNum && labelNum >= 0 )
 {
  UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
  thisLabel.text = text;
  thisLabel.textColor = color;
 }

 [self updateLayout];
}

-(void)setText:(NSString *)text andFont:(UIFont*)font andColor:(UIColor*)color forLabel:(int)labelNum;
{
 if( [self.labels count] > labelNum && labelNum >= 0 )
 {
  UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
  thisLabel.text = text;
  thisLabel.font = font;
  thisLabel.textColor = color;
 }

 [self updateLayout];
}

- Réactualiser la mise en page {

 int thisX = 0;

 // TODO quand il sera temps de prendre en charge des polices de différentes tailles, il faudra ajuster chaque valeur y pour aligner les baselines

 for (UILabel * thisLabel in self.labels) {
  CGSize size = [thisLabel.text sizeWithFont:thisLabel.font
         constrainedToSize:CGSizeMake(9999, 9999)
          lineBreakMode:thisLabel.lineBreakMode];
  CGRect thisFrame = CGRectMake( thisX, 0, size.width, size.height );
  thisLabel.frame = thisFrame;

  thisX += size.width;
 }
}

- (void)dealloc {
 [labels release];
 labels = nil;

 [containerView release];
 containerView = nil;

    [super dealloc];
}

@end

0 votes

Merci @Jason, je travaille avec cette routine dans plusieurs applications et c'est génial, même sous iOS 7 ça fonctionne, j'ai simplement mis à jour sizeWithFont qui était obsolète.

18voto

mahboudz Points 23653

Utilisez deux IBOutlet UILabel, chacun avec un format différent (police/couleur/etc), comme vous le souhaitez. Déplacez le second sur le premier en fonction de la fin du texte du premier. Vous pouvez obtenir cela via sizeWithFont:forWidth:lineBreakMode:

Alternativement, vous pouvez sous-classer UILabel, et dessiner le texte vous-même dans drawRect. Si vous le faites de cette manière, ajoutez simplement une variable d'instance pour vous dire combien de la chaîne dessiner dans un format, et dessinez le reste dans un autre.

Mise à jour: Veuillez consulter la réponse de @Akshay ci-dessous. À partir d'iOS6, les UILabel peuvent contenir NSMutableAttributedString. Quand j'ai écrit ceci, cela n'était pas disponible.

1 votes

Ou, pour être plus compliqué que ce qui est probablement nécessaire, créez votre propre HTML pour représenter le message et affichez-le dans un UIWebView.

1 votes

D'accord, je pensais à une solution plus élégante. Mais apparemment, je dois le faire manuellement. Merci!

0 votes

Une alternative consisterait à utiliser des calques (en particulier CATextLayer) Consultez ce fil de discussion Texte gras et non-gras dans un seul UILabel ? stackoverflow.com/questions/3586871/…

7voto

Laurynas Points 1292

J'ai mis à jour MultipartLabel suggéré par @Jason en ajoutant la prise en charge du contentMode (alignement du texte).

MultipartLabel.h

#import 

@interface MultipartLabel : UIView {
}

@property (nonatomic,retain) UIView *containerView;
@property (nonatomic,retain) NSMutableArray *labels;
@property (nonatomic) UIViewContentMode contentMode;

- (void)updateNumberOfLabels:(int)numLabels;
- (void)setText:(NSString *)text forLabel:(int)labelNum;
- (void)setText:(NSString *)text andFont:(UIFont*)font forLabel:(int)labelNum;
- (void)setText:(NSString *)text andColor:(UIColor*)color forLabel:(int)labelNum;
- (void)setText:(NSString *)text andFont:(UIFont*)font andColor:(UIColor*)color forLabel:(int)labelNum;

@end

MultipartLabel.m

//  MultipartLabel.m
//  MultipartLabel
//
//  Créé par Jason Miller le 10/7/09.
//  Mis à jour par Laurynas Butkus, 2011
//  Droits d'auteur 2009 Jason Miller. Tous les droits sont réservés.
//

#import "MultipartLabel.h"

@interface MultipartLabel (Privé)
- (void)updateLayout;
@end

@implementation MultipartLabel

@synthesize containerView;
@synthesize labels;
@synthesize contentMode;

-(void)updateNumberOfLabels:(int)numLabels
{
    [containerView removeFromSuperview];
    self.containerView = nil;

    self.containerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)] autorelease];
    [self addSubview:self.containerView];
    self.labels = [NSMutableArray array];

    while (numLabels-- > 0) {
        UILabel * label = [[UILabel alloc] initWithFrame:CGRectZero];
        label.backgroundColor = self.backgroundColor;
        [self.containerView addSubview:label];
        [self.labels addObject:label];
        [label release];
    }

    [self updateLayout];
}

-(void)setText:(NSString *)text forLabel:(int)labelNum
{
    if( [self.labels count] > labelNum && labelNum >= 0 )
    {
        UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
        thisLabel.text = text;
    }

    [self updateLayout];
}

-(void)setText:(NSString *)text andFont:(UIFont*)font forLabel:(int)labelNum
{
    if( [self.labels count] > labelNum && labelNum >= 0 )
    {
        UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
        thisLabel.text = text;
        thisLabel.font = font;
    }

    [self updateLayout];
}

-(void)setText:(NSString *)text andColor:(UIColor*)color forLabel:(int)labelNum
{
    if( [self.labels count] > labelNum && labelNum >= 0 )
    {
        UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
        thisLabel.text = text;
        thisLabel.textColor = color;
    }

    [self updateLayout];
}

- (void)setText:(NSString *)text andFont:(UIFont*)font andColor:(UIColor*)color forLabel:(int)labelNum
{
    if( [self.labels count] > labelNum && labelNum >= 0 )
    {
        UILabel * thisLabel = [self.labels objectAtIndex:labelNum];
        thisLabel.text = text;
        thisLabel.font = font;
        thisLabel.textColor = color;
    }

    [self updateLayout];
}

- (void)updateLayout {

    int thisX;
    int thisY;
    int totalWidth = 0;
    int offsetX = 0;

    int sizes[[self.labels count]][2];
    int i = 0;

    for (UILabel * thisLabel in self.labels) {
        CGSize size = [thisLabel.text sizeWithFont:thisLabel.font constrainedToSize:CGSizeMake(9999, 9999) 
                                     lineBreakMode:thisLabel.lineBreakMode];

        sizes[i][0] = size.width;
        sizes[i][1] = size.height;
        totalWidth+= size.width;

        i++;
    }

    i = 0;

    for (UILabel * thisLabel in self.labels) {
        // X
        switch (self.contentMode) {
            case UIViewContentModeRight:
            case UIViewContentModeBottomRight:
            case UIViewContentModeTopRight:
                thisX = self.frame.size.width - totalWidth + offsetX;
                break;

            case UIViewContentModeCenter:
                thisX = (self.frame.size.width - totalWidth) / 2 + offsetX;
                break;

            default:
                thisX = offsetX;
                break;
        }

        // Y
        switch (self.contentMode) {
            case UIViewContentModeBottom:
            case UIViewContentModeBottomLeft:
            case UIViewContentModeBottomRight:
                thisY = self.frame.size.height - sizes[i][1];
                break;

            case UIViewContentModeCenter:
                thisY = (self.frame.size.height - sizes[i][1]) / 2;
                break;

            default:
                thisY = 0;
                break;
        }

        thisLabel.frame = CGRectMake( thisX, thisY, sizes[i][0], sizes[i][1] );

        offsetX += sizes[i][0];

        i++;
    }
}

- (void)dealloc {
    [labels release];
    labels = nil;

    [containerView release];
    containerView = nil;

    [super dealloc];
}

@end

1voto

George Petrov Points 151

Utilisez l'API CoreText, ce sera beaucoup plus rapide.

Voici quelques exemples

Essentiellement, les choses que vous devrez faire sont : 1: Créer une sous-classe UIView 2: Dans la méthode drawRect:, ajoutez la logique de dessin du texte.

La logique de dessin du texte : - Vous devrez connaître la plage du "name" donc si Tom: Some message. est votre chaîne de caractères, vous devrez appliquer une police différente pour la plage (0, 3).

Vous pouvez tout personnaliser avec CoreText :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X