iOS 7 TextKit - Wie füge ich Bilder in Text ein?


109

Ich versuche, mit UITextView den folgenden Effekt zu erzielen:

Geben Sie hier die Bildbeschreibung ein

Grundsätzlich möchte ich ein Bild zwischen Text einfügen. Das Bild kann einfach nur 1 Zeile Platz einnehmen, sodass keine Umhüllung erforderlich ist.

Ich habe versucht, der Unteransicht nur eine UIView hinzuzufügen:

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

Aber es scheint über den Text zu schweben und ihn abzudecken.

Ich habe ein wenig über Ausschlusspfade gelesen , was eine Möglichkeit zu sein scheint, dies zu implementieren. Ich möchte das Bild jedoch nicht unbedingt positionieren, sondern es sollte mit dem Text fließen (ähnlich wie <span>in HTML).


In einigen Antworten wird die Verwendung der Bildeigenschaften in NSTextAttachment und NSTextField erwähnt. Ich möchte jedoch erwähnen, dass ich eine Lösung benötige, mit der ich eine UIView anhängen kann.
Andy Hin

5
Erstaunlich, dass ich heute Morgen den Royal Rumble 2011 (von dem Ihr Bild aufgenommen wurde) über das WWE-Netzwerk gesehen habe und hier bin ich heute bei dieser Frage.
Papa

Heya, haben Sie ein Beispiel für einen Arbeitscode mit TextAttachment?
Fatuhoku

Antworten:


180

Sie müssen eine zugewiesene Zeichenfolge verwenden und das Bild als Instanz hinzufügen von 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
Ich denke, dies ist die bisher naheliegendste Antwort. Ist es möglich, dieselbe Technik mit UIView anstelle von UIImage zu verwenden?
Andy Hin

4
Dies zeigt die Bilder nicht an, wenn die resultierende Zeichenfolge in UITextView
DeepK SOreadytohelp

6
Wie ändere ich die Größe des NSTextAttachments?
jsetting32

2
@bilobatum, ich möchte mehr als ein Bild in die Textansicht einfügen. Wie kann ich hinzufügen?
Diken Shah

3
`[zugeschriebenString insertAttributedString: textAttachment atIndex: 4]` ist besser alsreplaceCharactersInRange
DawnSong

26

Der Code von @ bilobatum wurde für Bedürftige in Swift konvertiert:

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

Sie können versuchen, NSAttributedString und NSTextAttachment zu verwenden. Weitere Informationen zum Anpassen des NSTextAttachment, um die Größe des Bildes zu ändern, finden Sie unter folgendem Link. http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os-x-and-ios/

In meinem Beispiel passe ich die Größe des Bilds an die Breite an. In Ihrem Fall möchten Sie möglicherweise die Größe des Bildes an die Linienhöhe anpassen.


Ich denke, dies ist die bisher naheliegendste Antwort. Ist es möglich, dieselbe Technik mit UIView anstelle von UIImage zu verwenden?
Andy Hin

Möglicherweise können Sie einige wichtige Arbeiten an Ihren eigenen benutzerdefinierten Klassen ausführen. NSTextAttachment verfügt über ein Standardbildattribut und der Anhang wird als Teil des NSAttributedString gespeichert. Sie könnten wahrscheinlich Ihre eigenen Unterklassen erstellen und speichern, was Sie wollen. Ich denke, die Anzeige beschränkt sich auf die Anzeige eines Bildes, daher bin ich mir nicht sicher, ob eine UIView nützlich wäre. Soweit ich mich erinnere, erwartet der layoutManager ein Bild.
Duncan Groenewald

1
@AndyHin Ich habe dies nicht selbst getestet, aber eine Möglichkeit besteht möglicherweise darin, Ihr UIViewzu einem zu rendern UIImageund es dann als hinzuzufügen NSTextAttachment. Um die Ansicht zu einem Bild zu rendern, überprüfen Sie diese Frage: http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina- Anzeige? lq = 1
Michael Gaylord

Irgendwelche neuen Entwicklungen damit?
Fatuhoku

5

Erweitern Sie die Antwort von @ bilobatum und verwenden Sie diese Kategorie aus einer anderen Frage. Ich habe mir das ausgedacht:

Verwendung:

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;

Implementierung:

@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

Das Ändern der Zeile UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];in UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName] ?: [UIFont fontWithName:@"HelveticaNeue" size:12.0];sollte besser sein, da [attributeForRange valueForKey: NSFontAttributeName] möglicherweise null ist, wenn es nicht im Wörterbuch festgelegt wurde
Victor Kwok

5

Problemlösung im einfachen Beispiel ist Geben Sie hier die Bildbeschreibung ein

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.