BOYYANG/1/blog/compressed/海贼王帽子简约4K壁纸 路飞草帽-6bed2ed2879f71f25c5e7c13dd9ca870

swift ui 如何自定义组件并且获取组件内部回调函数所传递出来的数据

作者: boyyang
分类: Swift
发布: 2025-07-06 06:52:11
更新: 2025-07-06 06:52:11
浏览: 3

背景描述

   最近使用swift ui开发项目的时候,遇到了一个问题。当我在封装一个自定义图片组件的时候,当组件接收到传递给图片组件的url地址的时候,我会通过通过url地址获取图片数据,同时向组件外部返回图片下载进度,以及图片是否下载成功。正常情况下可以这样做,代码如下

import SwiftUI

struct DownloadImage: View {
    @State var url: URL
    @State private var nsimage:NSImage?
    
    var onSuccess :((_ isDownload: Bool) -> Void)?
    
    func downloadImage(){
        // 成功下载图片后 伪代码
        if (onSuccess != nil){
            onSuccess!(true)
        }
    }
    var body: some View {
        VStack{
            if self.nsimage != nil {
                Image(nsImage: self.nsimage!)
            }
        }
        .onAppear{
            downloadImage()
        }
    }
}

#Preview {
    DownloadImage(url: URL(string: "https://www.test/image.png")!) { isDownload in
        print(isDownload)
    }
}

       但是如果我同时需要向这个组件传递一个View视图,那么代码将会变成以下:

import SwiftUI

struct DownloadImage<Content:View>: View {
    @State var url: URL
    @State private var nsimage:NSImage?
    
    var content: Content
    var onSuccess :((_ isDownload: Bool) -> Void)?
    
    init(url: URL, @ViewBuilder content: @escaping () -> Content, onSuccess: ((_: Bool) -> Void)? = nil) {
        self.url = url
        self.content = content()
        self.onSuccess = onSuccess
    }
    
    func downloadImage(){
        // 成功下载图片后 伪代码
        if (onSuccess != nil){
            onSuccess!(true)
        }
    }
    var body: some View {
        VStack{
            content
            if self.nsimage != nil {
                Image(nsImage: self.nsimage!)
            }
        }
        .onAppear{
            downloadImage()
        }
    }
}

#Preview {
    DownloadImage(
        url: URL(string: "https://www.test/image.png")!,
        content: {
            VStack{
                Text("xxx")
            }.frame(width: 100, height: 100)
        },
        onSuccess: { isDownload in
            print(isDownload)
        }
    )
}

       虽然也能实现同样的效果,但是我想实现类似于以下效果:通过.onDelete来接受组件传递出来的数据信息

List {
       ForEach(users, id: \.self) { user in
                    Text(user)
       }
       .onDelete(perform: delete)
}

    最终代码如下:

import SwiftUI

struct DownloadImage<Content:View>: View {
    @State var url: URL
    @State private var nsimage:NSImage?
    
    var content: Content
    var onSuccess :((_ isDownload: Bool) -> Void)?
    
    init(url: URL, @ViewBuilder content: @escaping () -> Content) {
        self.url = url
        self.content = content()
    }
    
    func downloadImage(){
        // 成功下载图片后 伪代码
        if (onSuccess != nil){
            onSuccess!(true)
        }
    }
    var body: some View {
        VStack{
            content
            if self.nsimage != nil {
                Image(nsImage: self.nsimage!)
            }
        }
        .onAppear{
            downloadImage()
        }
    }
}

extension DownloadImage {
    func onSuccess(perform action: ((_ isDownlaod: Bool) -> Void)?) -> Self{
        var this = self
        this.onSuccess = action
        return this
    }
}
    

#Preview {
    DownloadImage(
        url: URL(string: "https://www.test/image.png")!
    ){
        VStack{}.frame(width: 100, height: 100)
    }
    .onSuccess { isDownlaod in
        print(isDownlaod)
    }
}


#前端
#swift
#swift ui