111 votes

iOS 7 TextKit - Comment insérer des images en ligne avec du texte ?

J'essaie d'obtenir l'effet suivant en utilisant une UITextView :

enter image description here

En gros, je veux insérer une image entre deux textes. L'image peut simplement occuper une ligne d'espace, sans qu'il soit nécessaire de l'envelopper.

J'ai essayé d'ajouter simplement une UIView à la sous-vue :

UIView *pictureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[pictureView setBackgroundColor:[UIColor redColor]];
[self.textView addSubview:pictureView];

Mais il semble flotter au-dessus du texte et le recouvrir.

J'ai fait un peu de lecture sur voies d'exclusion qui semble être une façon de mettre cela en œuvre. Cependant, je ne veux pas positionner l'image de manière absolue, mais plutôt la faire couler avec le texte (de manière similaire à la manière dont les <span> se comporte en HTML).

0 votes

Quelques réponses mentionnent l'utilisation des propriétés d'image sur NSTextAttachment et NSTextField mais je tiens à préciser que j'ai besoin d'une solution qui me permette d'ajouter un UIView.

7 votes

Il est étonnant que j'aie regardé le Royal Rumble 2011 ce matin (d'où votre image a été prise) via le réseau WWE et que je tombe sur cette question aujourd'hui.

0 votes

Hé, avez-vous un exemple de code fonctionnel impliquant TextAttachment ?

183voto

bilobatum Points 3961

Vous devrez utiliser une chaîne attribuée et ajouter l'image comme instance de NSTextAttachment :

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"like after"];

NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:@"whatever.png"];

NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];

[attributedString replaceCharactersInRange:NSMakeRange(4, 1) withAttributedString:attrStringWithImage];

4 votes

Je pense que c'est la réponse la plus proche jusqu'à présent. Est-il possible d'utiliser cette même technique avec UIView au lieu de UIImage ?

4 votes

Les images ne s'affichent pas lorsque l'on utilise la chaîne résultante dans UITextView.

0 votes

Il devrait le faire si vous définissez le texte attribué sur l'UITextView.

30voto

Justin Vallely Points 2374

Le code de @bilobatum converti en Swift pour ceux qui en ont besoin :

let attributedString = NSMutableAttributedString(string: "like after")

let textAttachment = NSTextAttachment()

textAttachment.image = UIImage(named: "whatever.png")

let attrStringWithImage = NSAttributedString(attachment: textAttachment)

attributedString.replaceCharacters(in: NSMakeRange(4, 1), with: attrStringWithImage)

21voto

Duncan Groenewald Points 2802

Vous pouvez essayer d'utiliser NSAttributedString et NSTextAttachment. Consultez le lien suivant pour plus de détails sur la personnalisation de la NSTextAttachment afin de redimensionner l'image. http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os-x-and-ios/

Dans mon exemple, je redimensionne l'image pour l'adapter à la largeur. Dans votre cas, vous voudrez peut-être redimensionner l'image pour l'adapter à la hauteur de la ligne.

0 votes

Je pense que c'est la réponse la plus proche jusqu'à présent. Est-il possible d'utiliser cette même technique avec UIView au lieu de UIImage ?

0 votes

Vous pourriez être en mesure de faire un travail important sur vos propres classes personnalisées. NSTextAttachment possède un attribut image par défaut et la pièce jointe est stockée comme une partie de NSAttributedString. Vous pourriez probablement créer vos propres sous-classes et stocker ce que vous voulez. Je pense que l'affichage est limité à l'affichage d'une image, donc pas sûr qu'un UIView soit utile. Si je me souviens bien, le layoutManager attend une image.

1 votes

@AndyHin Je ne l'ai pas testé moi-même mais une option est peut-être de rendre votre UIView à un UIImage et l'ajouter ensuite comme un NSTextAttachment . Afin de rendre la vue en image, consultez cette question : http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina-display?lq=1

6voto

balla Points 427

La solution du problème dans un exemple simple est enter image description here

let attachment = NSTextAttachment()
attachment.image = UIImage(named: "qrcode")

let iconString = NSAttributedString(attachment: attachment)
let firstString = NSMutableAttributedString(string: "scan the ")
let secondString = NSAttributedString(string: "QR code received on your phone.")

firstString.append(iconString)
firstString.append(secondString)

self.textLabel.attributedText = firstString

5voto

Stian Høiland Points 1699

Développant les propos de @bilobatum réponse et en utilisant cette catégorie d'une autre question. J'ai préparé ça :

Utilisation :

UILabel *labelWithImage = [UILabel new];
labelWithImage.text = @"Tap [new-button] to make a new thing!";
NSAttributedString *stringWithImage = [labelWithImage.attributedText attributedStringByReplacingOccurancesOfString:@"[new-button]" withImage:[UIImage imageNamed:@"MyNewThingButtonImage"] scale:0];
labelWithImage.attributedText = stringWithImage;

Mise en œuvre :

@interface NSMutableAttributedString (InlineImage)

- (void)replaceCharactersInRange:(NSRange)range withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale;

@end

@interface NSAttributedString (InlineImages)

- (NSAttributedString *)attributedStringByReplacingOccurancesOfString:(NSString *)string withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale;

@end

.

@implementation NSMutableAttributedString (InlineImages)

- (void)replaceCharactersInRange:(NSRange)range withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale {

    if (floorf(inlineImageScale) == 0)
        inlineImageScale = 1.0f;

    // Create resized, tinted image matching font size and (text) color
    UIImage *imageMatchingFont = [inlineImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    {
        // Font size
        NSDictionary *attributesForRange = [self attributesAtIndex:range.location effectiveRange:nil];
        UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];
        CGSize imageSizeMatchingFontSize = CGSizeMake(inlineImage.size.width * (fontForRange.capHeight / inlineImage.size.height), fontForRange.capHeight);

        // Some scaling for prettiness
        CGFloat defaultScale = 1.4f;
        imageSizeMatchingFontSize = CGSizeMake(imageSizeMatchingFontSize.width * defaultScale,     imageSizeMatchingFontSize.height * defaultScale);
        imageSizeMatchingFontSize = CGSizeMake(imageSizeMatchingFontSize.width * inlineImageScale, imageSizeMatchingFontSize.height * inlineImageScale);
        imageSizeMatchingFontSize = CGSizeMake(ceilf(imageSizeMatchingFontSize.width), ceilf(imageSizeMatchingFontSize.height));

        // Text color
        UIColor *textColorForRange = [attributesForRange valueForKey:NSForegroundColorAttributeName];

        // Make the matching image
        UIGraphicsBeginImageContextWithOptions(imageSizeMatchingFontSize, NO, 0.0f);
        [textColorForRange set];
        [inlineImage drawInRect:CGRectMake(0 , 0, imageSizeMatchingFontSize.width, imageSizeMatchingFontSize.height)];
        imageMatchingFont = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

    // Text attachment with image
    NSTextAttachment *textAttachment = [NSTextAttachment new];
    textAttachment.image = imageMatchingFont;
    NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:textAttachment];

    [self replaceCharactersInRange:range withAttributedString:imageString];
}

@end

@implementation NSAttributedString (InlineImages)

- (NSAttributedString *)attributedStringByReplacingOccurancesOfString:(NSString *)string withInlineImage:(UIImage *)inlineImage scale:(CGFloat)inlineImageScale {

    NSMutableAttributedString *attributedStringWithImages = [self mutableCopy];

    [attributedStringWithImages.string enumerateOccurancesOfString:string usingBlock:^(NSRange substringRange, BOOL *stop) {
        [attributedStringWithImages replaceCharactersInRange:substringRange withInlineImage:inlineImage scale:inlineImageScale];

    }];

    return [attributedStringWithImages copy];
}

@end

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