iOS 7 TextKit - Как вставлять изображения в текст?

109

Я пытаюсь получить следующий эффект с помощью UITextView:

введите описание изображения здесь

В основном я хочу вставить изображение между текстом. Изображение может занимать только 1 строку, поэтому нет необходимости в переносе.

Я попытался просто добавить UIView в подпредставление:

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

Но кажется, будто он плывет по тексту и закрывает его.

Я немного прочитал о путях исключения, которые, похоже, являются одним из способов реализации этого. Однако я не хочу абсолютно позиционировать изображение - вместо этого оно должно перетекать вместе с текстом (аналогично тому, как это происходит <span>в HTML).

Энди Хин
источник
В некоторых ответах упоминается использование свойств изображения в NSTextAttachment и NSTextField, но я хочу упомянуть, что мне нужно решение, которое позволяет мне добавить UIView.
Энди Хин
5
Удивительно, что я только что смотрел Royal Rumble 2011 сегодня утром (откуда было взято ваше изображение) через сеть WWE, и вот я сегодня задаю этот вопрос.
bpapa 02
Привет, у вас есть пример рабочего кода с использованием TextAttachment?
fatuhoku

Ответы:

180

Вам нужно будет использовать строку с атрибутами и добавить изображение как экземпляр 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
Я думаю, что это пока самый близкий ответ. Можно ли использовать ту же технику с UIView вместо UIImage?
Энди Хин
4
Это не отображает изображения при использовании результирующей строки в UITextView
DeepK SOreadytohelp
6
Как изменить размер NSTextAttachment?
jsetting32
2
@bilobatum, я хочу добавить более одного изображения в textview. Так как я могу добавить?
Дикен Шах,
3
`[attributedString insertAttributedString: textAttachment atIndex: 4]` лучше, чемreplaceCharactersInRange
DawnSong
26

Код @ bilobatum преобразован в Swift для нуждающихся:

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

Вы можете попробовать использовать NSAttributedString и NSTextAttachment. Взгляните на следующую ссылку для получения дополнительных сведений о настройке NSTextAttachment для изменения размера изображения. http://ossh.com.au/design-and-technology/software-development/implementing-rich-text-with-images-on-os-x-and-ios/

В моем примере я изменяю размер изображения по ширине, в вашем случае вы можете изменить размер изображения в соответствии с высотой строки.

Дункан Гроенвальд
источник
Я думаю, что это пока самый близкий ответ. Можно ли использовать ту же технику с UIView вместо UIImage?
Энди Хин
Возможно, вам удастся серьезно поработать над своими собственными классами. NSTextAttachment имеет атрибут изображения по умолчанию, и вложение сохраняется как часть NSAttributedString. Вероятно, вы могли бы создать свои собственные подклассы и хранить все, что захотите. Я думаю, что отображение ограничено отображением изображения, поэтому не уверен, что UIView будет полезен. Насколько я помню, layoutManager ожидает изображение.
Duncan Groenewald 05
1
@AndyHin Я сам не тестировал это, но один из вариантов - отрендерить вас UIViewв a, UIImageа затем добавить его как NSTextAttachment. Чтобы отобразить представление на изображении, ознакомьтесь с этим вопросом: http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina- display? lq = 1
Майкл Гейлорд
Какие-нибудь новые разработки с этим?
fatuhoku
5

Расширяя ответ @ bilobatum и используя эту категорию из другого вопроса. Я приготовил это:

Использование:

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;

Реализация:

@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
Стиан Хойланд
источник
Изменение линии UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];к UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName] ?: [UIFont fontWithName:@"HelveticaNeue" size:12.0];должно быть лучше, потому что [attributesForRange valueForKey: NSFontAttributeName] может быть ноль , если он не был установлен в словаре
Виктор Квок
5

Решение проблемы в простом примере: введите описание изображения здесь

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
Прабхат Касера
источник