Home > Software engineering >  How to change an image to a structure? SwiftUI
How to change an image to a structure? SwiftUI

Time:10-29

Now, when the application is opened, the image from the link is displayed, but if the user does not have the Internet, then the image from the files of my application is displayed

how instead of my image - name: "noconnection", show my structure: Indicator() if the user has no internet connection.

my code:

struct RemoteImage: View {

    private enum LoadState {
        case loading, success, failure
    }

    private class Loader: ObservableObject {
            var data = Data()
            var state = LoadState.loading

            init(url: String) {
                guard let parsedURL = URL(string: url) else {
                    fatalError("Invalid URL: \(url)")
                }

                URLSession.shared.dataTask(with: parsedURL) { data, response, error in
                    if let data = data, data.count > 0 {
                        self.data = data
                        self.state = .success
                    } else {
                        self.state = .failure
                    }

                    DispatchQueue.main.async {
                                        self.objectWillChange.send()
                                    }
                                }.resume()
                            }
                        }

    @StateObject private var loader: Loader
     var loading: Image
     var failure: Image

     var body: some View {
         selectImage()
             .resizable()
     }

    init(url: String, loading: Image = Image("loadingimage"), failure: Image = Image("noconnection")) {
         _loader = StateObject(wrappedValue: Loader(url: url))
         self.loading = loading
         self.failure = failure
     }

     private func selectImage() -> Image {
         switch loader.state {
         case .loading:
             return loading
         case .failure:
             return failure
         default:
             if let image = UIImage(data: loader.data) {
                return Image(uiImage: image).resizable()
             } else {
                 return failure
             }
         }
     }
 }

my structure - Indicator() - code

struct Indicator : UIViewRepresentable {
    func makeUIView(context: Context) -> UIActivityIndicatorView {
        let indicator = UIActivityIndicatorView()
        indicator.startAnimating()
        indicator.style = .large
        indicator.color = .systemTeal
        
        return indicator
    }
    
    func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
        //
    }
}

This structure - Indicator() - should be shown instead of an image "noconnection"

image

I will be grateful for any help

CodePudding user response:

You could change your failure type to accept an Indicator. Then, change your selectImage to a @ViewBuilder that returns some View:


struct RemoteImage: View {
    
    private enum LoadState {
        case loading, success, failure
    }
    
    private class Loader: ObservableObject {
        var data = Data()
        var state = LoadState.loading
        
        init(url: String) {
            guard let parsedURL = URL(string: url) else {
                fatalError("Invalid URL: \(url)")
            }
            
            URLSession.shared.dataTask(with: parsedURL) { data, response, error in
                if let data = data, data.count > 0 {
                    self.data = data
                    self.state = .success
                } else {
                    self.state = .failure
                }
                
                DispatchQueue.main.async {
                    self.objectWillChange.send()
                }
            }.resume()
        }
    }
    
    @StateObject private var loader: Loader
    var loading: Image
    var failure: Indicator
    
    var body: some View {
        selectImage()
    }
    
    init(url: String, loading: Image = Image("loadingimage").resizable(), failure: Indicator = Indicator()) {
        _loader = StateObject(wrappedValue: Loader(url: url))
        self.loading = loading
        self.failure = failure
    }
    
    @ViewBuilder private func selectImage() -> some View {
        switch loader.state {
        case .loading:
            loading
        case .failure:
            failure
        default:
            if let image = UIImage(data: loader.data) {
                Image(uiImage: image).resizable()
            } else {
                failure
            }
        }
    }
}

In this case, you might want to get rid of the default argument and just set var failure = Indicator() instead of using the initializer

  • Related