iOS 7 TextKit - Làm thế nào để chèn hình ảnh nội dòng với văn bản?


109

Tôi đang cố gắng đạt được hiệu ứng sau bằng cách sử dụng UITextView:

nhập mô tả hình ảnh ở đây

Về cơ bản tôi muốn chèn một hình ảnh giữa văn bản. Hình ảnh có thể đơn giản chỉ chiếm 1 hàng không gian nên không cần bao bọc.

Tôi đã thử chỉ thêm một UIView vào chế độ xem phụ:

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

Nhưng nó dường như nổi trên văn bản và che mất nó.

Tôi đã đọc một chút về các đường dẫn loại trừ dường như là một cách để thực hiện điều này. Tuy nhiên, tôi không muốn định vị hình ảnh một cách tuyệt đối - thay vào đó, nó phải chảy cùng với văn bản (tương tự như cách <span>hoạt động trong HTML).


Một số câu trả lời đề cập đến việc sử dụng các thuộc tính hình ảnh trên NSTextAttachment và NSTextField nhưng tôi muốn đề cập rằng tôi cần một giải pháp cho phép tôi thêm một UIView.
Andy Hin

5
Thật ngạc nhiên là tôi vừa xem Royal Rumble 2011 vào sáng nay (nơi hình ảnh của bạn được lấy từ) qua mạng WWE và ở đây tôi đang giải đáp câu hỏi này hôm nay.
bpapa

Heya, bạn có ví dụ về một số mã làm việc liên quan đến TextAttachment không?
fatuhoku

Câu trả lời:


180

Bạn sẽ cần sử dụng một chuỗi được phân bổ và thêm hình ảnh vào ví dụ của 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
Tôi nghĩ đây là câu trả lời gần nhất cho đến nay. Có thể sử dụng cùng một kỹ thuật này với UIView thay vì UIImage không?
Andy Hin

4
Đây không phải là hiển thị hình ảnh khi sử dụng chuỗi kết quả là UITextView
DeepK SOreadytohelp

6
Làm cách nào để thay đổi kích thước NSTextAttachment?
jsetting32

2
@bilobatum, tôi muốn thêm nhiều hình ảnh vào textview. Vì vậy, làm thế nào tôi có thể thêm?
Diken Shah

3
`[AttributedString insertAttributedString: textAttachment atIndex: 4]` là tốt hơn so vớireplaceCharactersInRange
DawnSong

26

Mã của @ bilobatum được chuyển đổi sang Swift cho những ai có nhu cầu:

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

Bạn có thể thử sử dụng NSAttributedString và NSTextAttachment. Hãy xem liên kết sau để biết thêm chi tiết về việc tùy chỉnh NSTextAttachment để thay đổi kích thước hình ảnh. http://ossh.com.au/design-and-technology/software-development/implecting-rich-text-with-images-on-os-x-and-ios/

Trong ví dụ của tôi, tôi thay đổi kích thước hình ảnh để phù hợp với chiều rộng, trong trường hợp của bạn, bạn có thể muốn thay đổi kích thước hình ảnh để phù hợp với chiều cao của dòng.


Tôi nghĩ đây là câu trả lời gần nhất cho đến nay. Có thể sử dụng cùng một kỹ thuật này với UIView thay vì UIImage không?
Andy Hin

Bạn có thể thực hiện một số công việc chính trên các lớp tùy chỉnh của riêng bạn. NSTextAttachment có thuộc tính hình ảnh mặc định và tệp đính kèm được lưu trữ như một phần của NSAttributedString. Bạn có thể tạo các lớp con của riêng mình và lưu trữ bất cứ thứ gì bạn muốn. Tôi nghĩ rằng hiển thị bị giới hạn trong việc hiển thị hình ảnh nên không chắc UIView sẽ hữu ích. Khi tôi nhớ lại layoutManager mong đợi một hình ảnh.
Duncan Groenewald

1
@AndyHin Tôi chưa tự mình kiểm tra điều này nhưng một tùy chọn có thể là hiển thị của bạn UIViewthành a UIImagevà sau đó thêm nó dưới dạng một NSTextAttachment. Để hiển thị chế độ xem thành một hình ảnh, hãy xem câu hỏi này: http://stackoverflow.com/questions/4334233/how-to-capture-uiview-to-uiimage-without-loss-of-quality-on-retina- display? lq = 1
Michael Gaylord

Bất kỳ phát triển mới với điều này?
fatuhoku

5

Mở rộng câu trả lời của @ bilobatum và sử dụng danh mục này từ câu hỏi khác. Tôi đã nấu ra điều này:

Sử dụng:

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;

Thực hiện:

@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

Thay đổi dòng UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName];để UIFont *fontForRange = [attributesForRange valueForKey:NSFontAttributeName] ?: [UIFont fontWithName:@"HelveticaNeue" size:12.0];nên tốt hơn, vì [attributesForRange valueForKey: NSFontAttributeName] có thể con số không nếu nó không được đặt trong từ điển
Victor Kwok

5

Giải pháp vấn đề trong ví dụ đơn giản là nhập mô tả hình ảnh ở đây

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.