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

SwiftUI中List内Button的HStack加载网络图片显示黑色问题

解决SwiftUI中List按钮内网络图片不显示的问题

嘿,我来帮你搞定这个网络图片无法渲染的问题!你的代码里核心问题在于同步加载网络图片的方式,这在SwiftUI的渲染流程里会出问题,咱们一步步来解决:

问题根源

你当前的artwork()函数是在主队列(UI线程)里用Data(contentsOf:)同步请求网络图片,这会导致两个关键问题:

  • 同步网络请求会阻塞UI线程,让界面卡顿甚至无响应
  • SwiftUI的View是值类型,每次视图刷新都会重新调用artwork(),反复发起无效请求,而且图片加载完成后无法正确触发视图更新

而系统图片和本地资源不需要网络请求,所以能正常显示。

解决方案1:使用SwiftUI官方的AsyncImage(iOS 15+)

这是最简单的方案,苹果在iOS15之后提供了AsyncImage组件,专门用来异步加载网络图片,自动处理加载、失败、占位状态:

替换你原来的artwork()函数,直接在View里使用AsyncImage:

import SwiftUI

struct ContentView: View {
    let artworkURL = URL(string: "https://via.placeholder.com/150")!
    
    var body: some View {
        List {
            Button(action: {
                // 你的按钮点击逻辑
                print("按钮被点击啦")
            }) {
                HStack {
                    AsyncImage(url: artworkURL) { phase in
                        switch phase {
                        case .empty:
                            // 加载中的占位视图
                            Image(systemName: "book")
                                .frame(width: 50, height: 50)
                        case .success(let image):
                            // 加载成功的图片
                            image
                                .resizable()
                                .scaledToFit()
                                .frame(width: 50, height: 50)
                        case .failure:
                            // 加载失败的占位视图
                            Image(systemName: "exclamationmark.triangle")
                                .frame(width: 50, height: 50)
                        @unknown default:
                            Image(systemName: "book")
                                .frame(width: 50, height: 50)
                        }
                    }
                    // 其他信息
                    Text("按钮标题")
                }
            }
        }
    }
}

解决方案2:兼容iOS 15以下版本

如果需要支持更低版本的iOS,咱们可以用ObservableObject来异步加载图片,手动管理加载状态:

  1. 创建图片加载器类:
import SwiftUI
import Combine

class ImageLoader: ObservableObject {
    @Published var image: UIImage?
    private var cancellable: AnyCancellable?
    
    deinit {
        cancellable?.cancel()
    }
    
    func load(url: URL) {
        cancellable = URLSession.shared.dataTaskPublisher(for: url)
            .map { UIImage(data: $0.data) }
            .replaceError(with: UIImage(systemName: "book"))
            .receive(on: DispatchQueue.main)
            .assign(to: \.image, on: self)
    }
}
  1. 在ContentView里使用这个加载器:
struct ContentView: View {
    let artworkURL = URL(string: "https://via.placeholder.com/150")!
    @StateObject private var imageLoader = ImageLoader()
    
    var body: some View {
        List {
            Button(action: {
                // 你的按钮点击逻辑
                print("按钮被点击啦")
            }) {
                HStack {
                    if let image = imageLoader.image {
                        Image(uiImage: image)
                            .resizable()
                            .scaledToFit()
                            .frame(width: 50, height: 50)
                    } else {
                        Image(systemName: "book")
                            .frame(width: 50, height: 50)
                    }
                    // 其他信息
                    Text("按钮标题")
                }
                .onAppear {
                    imageLoader.load(url: artworkURL)
                }
            }
        }
    }
}

这两种方案都能解决你遇到的网络图片不显示问题,而且不会阻塞UI,还能正确处理加载状态~

内容的提问来源于stack exchange,提问作者user208685

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:23:21