如何从HTML字符串在UITextView中渲染带认证内联图片并按比例缩放?
从HTML字符串在UITextView中渲染带认证的等比例缩放内联图片
核心需求拆解
要实现目标需解决三个关键点:
- 带身份认证的图片网络请求
- 下载后图片的等比例缩放适配
- 异步下载完成后更新UITextView的内联内容布局
修正后的代码实现
1. 带认证的图片下载工具类
确保图片请求携带认证信息(以Bearer Token为例),完善NetworkHandler的下载逻辑:
class NetworkHandler { static let sharedInstance = NetworkHandler() func downloadFile(urlPathString: String, completion: @escaping (UIImage) -> Void, failure: @escaping (String) -> Void) { guard let url = URL(string: urlPathString) else { failure("无效图片链接") return } var request = URLRequest(url: url) // 添加认证头,根据实际认证方式调整 if let authToken = UserDefaults.standard.string(forKey: "user_auth_token") { request.setValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization") } let task = URLSession.shared.dataTask(with: request) { data, response, error in DispatchQueue.main.async { if let error = error { failure(error.localizedDescription) return } guard let data = data, let image = UIImage(data: data) else { failure("图片解析失败") return } completion(image) } } task.resume() } }
2. NSTextAttachment扩展:等比例缩放+异步更新
修改扩展方法,添加基于UITextView宽度的等比例缩放逻辑,并在下载完成后触发布局更新:
extension NSTextAttachment { func downloadAndScaleImage(urlPathString: String, placeholderImage: UIImage?, textViewWidth: CGFloat) { self.image = placeholderImage NetworkHandler.sharedInstance.downloadFile(urlPathString: urlPathString) { [weak self] downloadedImage in guard let self = self else { return } // 计算等比例缩放尺寸,预留左右边距 let maxDisplayWidth = textViewWidth - 16 let scaleRatio = maxDisplayWidth / downloadedImage.size.width let scaledHeight = downloadedImage.size.height * scaleRatio // 更新附件图片与布局边界(y偏移优化垂直对齐) self.image = downloadedImage self.bounds = CGRect(x: 0, y: -4, width: maxDisplayWidth, height: scaledHeight) // 通知UITextView重新渲染 NotificationCenter.default.post(name: NSNotification.Name("TextViewImageUpdate"), object: nil) } failure: { errorMsg in ShowUserMessageUtil.showUserMessageOnRootViewController(text: errorMsg) self.image = placeholderImage } } }
3. HTML图片替换与布局更新监听
在解析HTML并替换图片的逻辑中,传入文本视图宽度,并监听布局更新通知:
// 假设已完成HTML解析,得到图片位置(nsRange)和图片URL(previewItems[index].urlString) func replaceHTMLImages(in textView: UITextView) { let textViewWidth = textView.bounds.width _attributedString.beginEditing() let attachment = NSTextAttachment() attachment.downloadAndScaleImage(urlPathString: previewItems[index].urlString, placeholderImage: defaultImage, textViewWidth: textViewWidth) let inlineAttrString = NSAttributedString(attachment: attachment) _attributedString.replaceCharacters(in: nsRange, with: inlineAttrString) _attributedString.endEditing() textView.attributedText = _attributedString // 监听图片下载完成后的布局更新 NotificationCenter.default.addObserver(self, selector: #selector(refreshTextViewLayout), name: NSNotification.Name("TextViewImageUpdate"), object: nil) } @objc func refreshTextViewLayout() { yourTextView.layoutIfNeeded() } // 视图销毁时移除监听 deinit { NotificationCenter.default.removeObserver(self) }
关键说明
- 认证适配:通过给请求添加Authorization头,适配需要身份验证的图片资源,可根据实际认证机制调整头字段内容。
- 比例缩放:基于UITextView实际宽度计算缩放比例,保证图片不会超出文本容器,同时保留原比例避免拉伸变形。
- 异步更新:图片下载为异步操作,通过通知触发文本视图重新布局,解决异步加载后图片不显示或布局错乱的问题。
内容的提问来源于stack exchange,提问作者Divagar.G
相关产品推荐
相关产品推荐

