You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:40:36