Заменить изображение NSTextattachement на NSMutableattributedString
Я создаю UITextView с текстом и изображениями (Подкласс NSTextstorage для отображения моего контента)
У меня есть текстовое содержание с URL-адресами изображений. Поэтому моя проблема в том, что мне нужно скачать все изображения, если они не кэшированы.
Поэтому я хочу сначала вставить изображение-заполнитель, загрузить изображение, а затем заменить изображение-заполнитель на загруженное.
Вот как я делаю свои вещи.
Во-первых, я форматирую свой текст с URL-адресом изображений, заменяя все URL-адреса этим тегом:
[IMG]url[/IMG]
Затем я использую регулярное выражение, чтобы получить все эти теги.
Я проверяю, есть ли кэшированное изображение или нет. Если нет, я извлекаю все URL, загружаю их и кеширую.
Я создал класс NSObject ImageCachingManager и объявил метод делегата, вызываемый при загрузке изображения:
@protocol ImageCachingManagerDelegate <NSObject>
- (void)managerDidCacheImage:(UIImage *)image forUrl:(NSString *)url;
@end
Таким образом, я решил использовать URL-адрес изображения, полученного методом делегата, для поиска соответствующего URL-адреса в моем атрибуте NSTextstorage attributeString и заменить текущее изображение NSTextattachement загруженным.
Но я не знаю, как это сделать...
Спасибо за помощь!
1 ответ
Сейчас я работаю над чем-то очень похожим на это и думаю, что это может помочь. Код очень альфа, но, надеюсь, он поможет вам перейти к следующему шагу - я сделаю шаг вперед:
Общий цикл1. Найдите теги изображений в полнотекстовом фрагменте, используя Reg Ex или XPath - лично я считаю Hppl более мощным, но если ваш контент хорошо структурирован и надежен, регулярное выражение, вероятно, подойдет.
https://github.com/topfunky/hpple
Уменьшите пространство этого соответствия до 1 символа и сохраните этот диапазон - textAttachment занимает только 1 символ пространства в текстовом представлении, поэтому лучше уменьшить его до 1, в противном случае, когда вы заменяете первое совпадение символов в диапазоне на первое текстовое присоединение маркер следующего диапазона устареет, что приведет к проблемам. В зависимости от того, сколько обработки вам нужно сделать, чтобы ввести этот текст во время инициализации, это важный шаг, мне приходится много обрабатывать текст, и диапазоны меняются во время этого анализа, поэтому я создал массив специальных символов, которые я знаю никогда не будет находиться во входах и помещать эти одиночные символы в зарезервированное пространство, в то же время я сохраняю этот специальный символ и источник изображения в массиве очень простого подкласса NSObject, в котором хранится SpecialChar, ImgSrc plus имеет пространство для NSRange, но я в основном нахожу специальный символ позже в процессе, потому что он был перемещен с этой точки, а затем установил nsrange в самом конце обработки - это может быть не нужно в вашем случае, но принцип заключается в так же; Вам нужен пользовательский объект с NsRange (который станет текстовым вложением) и imgSource.
Переберите этот массив, чтобы добавить заполнитель imageAttachments к вашей атрибутивной строке. Вы можете сделать это, добавив прозрачное изображение или загрузочное изображение. Вы также можете проверить свой кеш на наличие существующих изображений в этот момент и пропустить заполнитель, если он существует в кеше.
Используя ваш делегат, когда изображение успешно загружено, вам нужно заменить текущее вложение на новое. Заменив заполнитель в диапазоне, который вы уже сохранили в своем объекте. Создайте заполнитель attributeString с помощью NSTextAttachment, а затем замените этот диапазон, как показано ниже.
Пример кода:
Шаги 1 и 2:
specialCharsArray = [[NSArray alloc]initWithObjects:@"Û", @"±", @"¥", @"å", @"æ", @"Æ", @"Ç", @"Ø", @"õ", nil];
// используя Hppl
NSString *allImagesXpathQueryString = @"//img/@src";
NSArray *imageArray = [bodyTextParser searchWithXPathQuery:allImagesXpathQueryString];
//
imageRanges = [[NSMutableArray alloc] init];
if([imageArray count]){
for (TFHppleElement *element in imageArray) {
int i = 0;
NSString *imgSource = [[[element children] objectAtIndex:0] content];
NSString *replacementString = [specialCharsArray objectAtIndex:i];
UIImage *srcUIImage = [UIImage imageNamed:imgSource];
[srcUIImage setAccessibilityIdentifier:imgSource]; //only needed if you need to reference the image filename later as it's lost in a UIImage if stored directly
// imagePlacement - это подкласс NSObject для хранения диапазона, замены и изображения, как указано выше
imagePlacement *foundImage = [[imagePlacement alloc]init] ;
[foundImage initWithSrc:srcUIImage replacement:replacementString];
[imageRanges addObject:foundImage];
i++;
}
Шаг 3:
-(void)insertImages{
if ([imageRanges count]) {
[self setScrollEnabled:NO]; //seems buggy with scrolling on
int i = 0; //used to track the array placement for tag
for(imagePlacement *myImagePlacement in imageRanges){
// creates a text attachment with an image
NSMutableAttributedString *placeholderAttString = [[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText];
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
//scales image down to ration of width of view - you probably don't need this
CGSize scaleToView = imagePlacement.imgSrc.size;
scaleToView.width = self.frame.size.width;
scaleToView.height = (self.frame.size.width/imagePlacement.imgSrc.size.width)*imagePlacement.imgSrc.size.height;
attachment.image = [self imageWithColor:[UIColor clearColor] andSize:scaleToView];
NSMutableAttributedString *imageAttrString = [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];
[self setAttributedText:placeholderAttString];
i++;
}
}
[self setScrollEnabled:YES];
}
- (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize) size {
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}