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.