Я пытаюсь заменить изображение в NSAttributedString
его уменьшенной копией (чтобы соответствовать ширине UITextView
), однако во многих (не во всех) случаях замененное изображение представляет собой маску оригинал. Я предполагаю, что есть что-то в других атрибутах строки, которые делают это, так как и извлечение изображения, и создание новой атрибутной строки из изображения работают отлично.
Примечание: ответы, подобные этому как изменить размер изображения или сделать как NSAttributedString NSTextAttachment (или установить его начальный размер) показать, как создать строку с изображениями (что я могу сделать) или как изменить размер текстового вложения (опять же, я могу сделать это) до создания строки, но не как изменить вместо .
Обновление Благодаря предложениям комментатора @Larme я теперь решил свою первоначальную проблему изменения размера изображения на месте путем изменения исходного NSTextAttachment.bounds
- обратите внимание, не заменяя его, изменив его in situ . Я не собираюсь публиковать это как ответ на свой вопрос, так как он не отвечает на более широкий вопрос о замене изображения.
Любые советы о том, как действовать с благодарностью, приняты.
Вот основа:
extension NSAttributedString {
func resizeAttachments(maxWidth: CGFloat) -> NSAttributedString {
var replacement = NSMutableAttributedString(attributedString: self)
func replace(_ image: UIImage, in range: NSRange, dict: [NSAttributedString.Key : Any]) {
// ... see below for variants of this
}
self.enumerateAttributes(in: NSMakeRange(0, self.length),
options: [],
using: {dict, range, stop in
for (key, value) in dict {
if key == .attachment, let attachment = value as? NSTextAttachment {
if
let fw = attachment.fileWrapper, fw.isRegularFile,
let d = fw.regularFileContents,
let image = UIImage(data: d)?.resized(toWidth: maxWidth) {
// removing the resize above makes no difference to the issue
// i.e. replacing the image with itself still causes the same problem
replace(image, in: range, dict: dict)
return // Exit the block. Can't have 2 .attachments.
}
}
}
})
return replacement
}
}
Пока что прямое перечисление self
изменяет изменяемый скопировать строку replacement
при обнаружении изображения. Вот что я получаю:

Из этого немасштабированного оригинала:

Итак, что я попробовал в функции замены?
func replace(_ image: UIImage, in range: NSRange, dict: [NSAttributedString.Key : Any]) {
let newAttachment = NSTextAttachment(image: image)
let newCharacter = NSMutableAttributedString(attachment: newAttachment)
// NB if I replace the entire string with `newCharacter` the image is perfect (but obviously the rest of the string has gone)
// Option 1
replacement.replaceCharacters(in: range, with: newCharacter)
// Option 2
var newDict: [NSAttributedString.Key : Any] = dict
newDict[.attachment] = newAttachment
replacement.addAttributes(newDict, range: range)
// Option 3
replacement.removeAttribute(.attachment, range: range)
replacement.addAttribute(.attachment, value: newAttachment, range: range)
}
Я ничего не могу найти о фактической замене изображений. Как я уже сказал, извлечение изображения работает нормально - если я просто верну новую атрибутивную строку только с извлеченным изображением, то это идеально. Если я добавлю изображение до конца, это работает. Это модифицирует это в месте, которое, кажется, проблема. Кто-нибудь когда-нибудь делал это успешно?