iOS 7 TextKit - Come inserire immagini in linea con il testo?


109

Sto cercando di ottenere il seguente effetto utilizzando un UITextView:

inserisci qui la descrizione dell'immagine

Fondamentalmente voglio inserire un'immagine tra il testo. L'immagine può semplicemente occupare 1 riga di spazio, quindi non è necessario avvolgere.

Ho provato ad aggiungere semplicemente una UIView alla sottoview:

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

Ma sembra fluttuare sul testo e coprirlo.

Ho letto un po 'sui percorsi di esclusione che sembra essere un modo per implementarlo. Tuttavia, non voglio assolutamente posizionare l'immagine - invece, dovrebbe fluire con il testo (simile a come <span>si comporta in HTML).


Alcune delle risposte menzionano l'utilizzo delle proprietà dell'immagine su NSTextAttachment e NSTextField, ma voglio menzionare che ho bisogno di una soluzione che mi consenta di aggiungere una UIView.
Andy Hin

5
È incredibile che stamattina ho appena visto la Royal Rumble 2011 (da cui è stata presa la tua immagine) tramite la rete WWE ed eccomi qui a rispondere a questa domanda oggi.
bpapa

Heya, hai un esempio di codice funzionante che coinvolge TextAttachment?
fatuhoku

Risposte:


180

Dovrai utilizzare una stringa attribuita e aggiungere l'immagine come istanza di 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
Penso che questa sia la risposta più vicina finora. È possibile utilizzare la stessa tecnica con UIView invece di UIImage?
Andy Hin

4
Questa non mostra le immagini quando si utilizza la stringa risultante in UITextView
DeepK SOreadytohelp

6
Come ridimensiono NSTextAttachment?
jsetting32

2
@bilobatum, voglio aggiungere più di un'immagine in textview. Allora come posso aggiungere?
Diken Shah

3
"[stringa attribuita insertAttributedString: textAttachment atIndex: 4]" è meglio direplaceCharactersInRange
DawnSong

26

Il codice di @ bilobatum convertito in Swift per chi ha bisogno:

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)

20

Potresti provare a utilizzare NSAttributedString e NSTextAttachment. Dai un'occhiata al seguente link per maggiori dettagli sulla personalizzazione di NSTextAttachment per ridimensionare l'immagine. http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os-x-and-ios/

Nel mio esempio ridimensiono l'immagine per adattarla alla larghezza, nel tuo caso potresti voler ridimensionare l'immagine per adattarla all'altezza della linea.


Penso che questa sia la risposta più vicina finora. È possibile utilizzare la stessa tecnica con UIView invece di UIImage?
Andy Hin

Potresti essere in grado di fare alcuni lavori importanti sulle tue classi personalizzate. NSTextAttachment ha un attributo immagine predefinito e l'allegato viene archiviato come parte di NSAttributedString. Probabilmente potresti creare le tue sottoclassi e memorizzare quello che vuoi. Penso che la visualizzazione sia limitata alla visualizzazione di un'immagine, quindi non sono sicuro che una UIView sarebbe utile. Come ricordo, il layoutManager si aspetta un'immagine.
Duncan Groenewald

1
@ AnddyHin Non l'ho testato da solo, ma un'opzione è forse quella di renderizzare il tuo UIViewin a UIImagee quindi aggiungerlo come file NSTextAttachment. Per rendere la vista in un'immagine controlla questa domanda: http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina- display? lq = 1
Michael Gaylord

Qualche nuovo sviluppo con questo?
fatuhoku

5

Espandendo la risposta di @ bilobatum e utilizzando questa categoria da un'altra domanda. Ho preparato questo:

Uso:

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;

Implementazione:

@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

Modificare la riga UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];in UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName] ?: [UIFont fontWithName:@"HelveticaNeue" size:12.0];dovrebbe essere migliore, perché [attributesForRange valueForKey: NSFontAttributeName] potrebbe essere nullo se non fosse impostato nel dizionario
Victor Kwok

5

La soluzione del problema in un semplice esempio è inserisci qui la descrizione dell'immagine

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.