Mur*_*ood 8 svg uiimageview ios sdwebimage swift
我正在开发一个项目,我从 API 获取数据,并在该 API 中获取图像的 url。但这些图像不是PNG、JPEG或JPG格式。它们是 SVG(可缩放矢量图形)图像。据我所知,没有直接的方法、函数或者 iOS 项目框架库用于渲染SVG图像。所以我们有一堆 Pod,它们实际上用于渲染这些图像,例如(SDWebImage、SDWebImageSVGCoder、SDWebImageSVGKitPlugin、SVGKit)。我全部使用了它们,但所有这些 Pod 都没有解决我的问题。那么让我们讨论一下我现在面临的问题。
这是我的 ViewController 类代码
import SDWebImageSVGCoder
class ViewController: UIViewController {
var banks: [Bank] = [Bank(logo:"https://identity.moneyhub.co.uk/bank-icons/default",name:"Dummy"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/accord", name: "Accord Mortgages"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/ajBell", name: "AJ Bell"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/aldermore", name: "Aldermore"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/amex", name: "American Express"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/brewinDolphin", name: "Brewin Dolphin"),
Bank(logo: "https://identity.moneyhub.co.uk/bank-icons/caxton", name: "Caxton"),]
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
func setupTableView() {
self.tableView.delegate = self
self.tableView.dataSource = self
}
}
//MARK: - TABLEVIEW DELEGATE DATASOURCE
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return banks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: BankTableViewCell.identifier, for: indexPath) as! BankTableViewCell
cell.configure(self.banks[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 62
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
Run Code Online (Sandbox Code Playgroud)
我的 TableViewCell 类
class BankTableViewCell: UITableViewCell {
@IBOutlet weak var bankNameLabel: UILabel!
@IBOutlet weak var bankLogoImageView: UIImageView!
class var identifier: String {
return "BankTableViewCell"
}
func configure(_ bank: Bank) {
self.bankNameLabel.text = bank.name
guard let url = URL(string: bank.logo) else {return}
self.bankLogoImageView.sd_setImage(fromURL: url)
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我运行此代码时,仅渲染了 3 个图像,第一个图像是虚拟或默认情况,但其余三个图像未渲染。然后我尝试定位问题,然后我发现并非所有图像都是真正的 SVG 图像,实际上其中一些是光栅图像。我在这里分享两种图像类型的图像数据。
那些渲染成功的图片有这样的数据
<svg viewBox="-25 -25 200 200" xmlns="http://www.w3.org/2000/svg">
<path d="M138.299 130.707H10.644a6.386 6.386 0 00-6.384 6.391 6.384 6.384 0 006.384 6.384h127.652a6.384 6.384 0 006.384-6.384c-.002-3.532-2.86-6.391-6.381-6.391zM18.621 114.101c-3.526 0-6.384 2.859-6.384 6.388s2.858 6.391 6.384 6.391h111.697c3.526 0 6.384-2.861 6.384-6.391s-2.858-6.388-6.384-6.388h-1.593V56.625h1.593a3.19 3.19 0 000-6.38H18.621a3.19 3.19 0 000 6.38h1.597v57.472h-1.597v.004zm97.336-57.476v57.472H96.81V56.625h19.147zm-31.917 0v57.472H64.893V56.625H84.04zm-51.06 0h19.147v57.472H32.98V56.625zM10.644 44.503H138.34a6.387 6.387 0 006.402-6.388 6.392 6.392 0 00-4.312-6.044L77.094 3.558a6.4 6.4 0 00-5.237 0L8.026 32.293a6.385 6.385 0 00-3.622 7.165 6.38 6.38 0 006.24 5.045z"/>
</svg>
Run Code Online (Sandbox Code Playgroud)
但是那些未渲染但显示白色或空图像的图像具有此类数据
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="20" y="135" width="460" height="230" fill="url(#pattern0)"/>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0" transform="scale(0.005 0.01)"/>
</pattern>
<image id="image0" width="200" height="100" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACBRJREF......UwT2kAAAAASUVORK5CYII="/>
</defs>
</svg>
Run Code Online (Sandbox Code Playgroud)
所以运行项目后我的屏幕看起来像这样。
我自己找到了解决方案,只需设置条件并首先检查每个图像响应。如果图像是纯用 SVG 编写的,那么我将调用 Pod 函数,否则我将使用自己的自定义代码来提取 base64Encoded 字符串,然后渲染图像。但它造成了一些性能问题。如您所知,库也在异步调用中工作,我也使用它来图像有时加载,有时不显示正确的图像。
我的自定义代码在这里
class BankTableViewCell: UITableViewCell {
@IBOutlet weak var bankNameLabel: UILabel!
@IBOutlet weak var bankLogoImageView: SVGImageView!
class var identifier: String {
return "BankTableViewCell"
}
func configure(_ bank: Bank) {
self.bankNameLabel.text = bank.name
guard let url = URL(string: bank.logo) else {return}
self.bankLogoImageView.loadImage(fromURL: url, placeHolderImage: "")
}
}
class SVGImageView: UIImageView {
private let imageCache = NSCache<AnyObject, UIImage>()
func loadImage(fromURL imageURL: URL, placeHolderImage: String)
{
self.image = UIImage(named: placeHolderImage)
if let cachedImage = self.imageCache.object(forKey: imageURL as AnyObject)
{
debugPrint("image loaded from cache for =\(imageURL)")
self.image = cachedImage
return
}
DispatchQueue.global().async {
[weak self] in
if let imageData = try? Data(contentsOf: imageURL) {
guard let xmlStr = String(data: imageData, encoding: .utf8) else {
DispatchQueue.main.async {
self?.sd_setImage(with: URL(string: "https://identity.moneyhub.co.uk/bank-icons/default")!)
}
return
}
print(xmlStr)
if let range = xmlStr.range(of: "data:image/png;base64,") {
let base64StringWithoutfilter = xmlStr.suffix(from: range.upperBound)
let base64StringWithoutfilterRange = base64StringWithoutfilter.range(of: "/>")
let lowerRange = range.upperBound
if let upperRange = base64StringWithoutfilterRange?.upperBound {
let base64ImageString = xmlStr[lowerRange..<upperRange].dropLast(3)
if let imageData = NSData(base64Encoded: String(describing:base64ImageString)) {
if let image = UIImage(data: imageData as Data) {
DispatchQueue.main.async {
self?.image = image
return
}
}
}
}
} else {
self?.sd_setImage(with: imageURL,completed: { image, error,cache, url in
if let image = image {
DispatchQueue.main.async {
self?.image = image
return
}
}
})
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我只是想解决我的问题,将我的自定义代码放入库中,因为我不了解 Objective C 并且 SDWebImageSVGCoder pod 是用 Objective C 编写的。如果这是不可能的,请给我一个建议,或任何其他库 pod 任何东西我使用它并解决我的问题并显示我的列表,如下所示。
我会使用自定义解码器。完成后,您可以使用以下方式调用它:
self.bankLogoImageView.sd_setImage(with: url,
placeholderImage: nil,
context: [.imageCoder: CustomSVGDecoder(fallbackDecoder: SDImageSVGCoder.shared)])
Run Code Online (Sandbox Code Playgroud)
我将其命名为CustomSVGDecoder,但由于它是 PNG/JPG 解码,因此可能有一个更好的名称。我没有检查,但我猜想,您获得的自定义 SVG 使用了某些 SVG 功能,并在其中合并了非矢量图像,但您当前只使用非矢量图像。
我给了它默认 SVGDecoder 的后备解码器SDWebImageSVGDecoder,以避免检查。
class CustomSVGDecoder: NSObject, SDImageCoder {
let fallbackDecoder: SDImageCoder?
init(fallbackDecoder: SDImageCoder?) {
self.fallbackDecoder = fallbackDecoder
}
static var regex: NSRegularExpression = {
let pattern = "<image.*xlink:href=\"data:image\\/(png|jpg);base64,(.*)\"\\/>"
let regex = try! NSRegularExpression(pattern: pattern, options: [])
return regex
}()
func canDecode(from data: Data?) -> Bool {
guard let data = data, let string = String(data: data, encoding: .utf8) else { return false }
guard Self.regex.firstMatch(in: string, range: NSRange(location: 0, length: string.utf16.count)) == nil else {
print("CustomSVGDecoder: We can decode")
return true //It self should decode
}
guard let fallbackDecoder = fallbackDecoder else {
print("CustomSVGDecoder: Can't decode and there is no fallBack decoder")
return false
}
print("CustomSVGDecoder: Will rely on fallback decoder to decode")
return fallbackDecoder.canDecode(from: data)
}
func decodedImage(with data: Data?, options: [SDImageCoderOption : Any]? = nil) -> UIImage? {
guard let data = data,
let string = String(data: data, encoding: .utf8) else { return nil }
guard let match = Self.regex.firstMatch(in: string, range: NSRange(location: 0, length: string.utf16.count)) else {
print("CustomSVGDecoder: Will rely on fallback decoder to decode because of no match")
return fallbackDecoder?.decodedImage(with: data, options: options)
}
guard let rawBase64DataRange = Range(match.range(at: 2), in: string) else {
print("CustomSVGDecoder: Will rely on fallback decoder to decode because we didn't fiund the base64 part")
return fallbackDecoder?.decodedImage(with: data, options: options)
}
let rawBase64Data = String(string[rawBase64DataRange])
guard let imageData = Data(base64Encoded: Data(rawBase64Data.utf8), options: .ignoreUnknownCharacters) else {
print("CustomSVGDecoder: Will rely on fallback decoder to decode because of invalid base64")
return fallbackDecoder?.decodedImage(with: data, options: options)
}
return UIImage(data: imageData)
}
//You might need to implement these methods, I didn't check their meaning yet
func canEncode(to format: SDImageFormat) -> Bool {
print("CustomSVGDecoder: canEncode(to:)")
return true
}
func encodedData(with image: UIImage?, format: SDImageFormat, options: [SDImageCoderOption : Any]? = nil) -> Data? {
print("CustomSVGDecoder: encodedData(with:format:options:)")
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
我使用正则表达式来查找 Base64 内容,它可能需要一些修改。您可以使用您自己的版本range(of:)。
| 归档时间: |
|
| 查看次数: |
2208 次 |
| 最近记录: |