swiftuikingfisher

KFImage image loaded but not displayed?


I am trying to display remote images using Kingfisher SDK , the images are loaded but its not displayed

    import SwiftUI
    import Kingfisher
    
    
    struct Tab_Home: View {
        
        
        //Slider
        @State var sliderIndex:Int = 0
        //Search bar
        @State var search:String = ""
        @ObservedObject var API = REST_API()
        
        var body: some View {
            
            VStack{
                
                ZStack{
                    
                    Group{
                        Rectangle().foregroundColor(Color.white.opacity(0.1))
                                   .cornerRadius(22.5)
                        
                        HStack(spacing : 0){
                            
                            Image(systemName: "magnifyingglass")
                                .resizable()
                                .frame(width : 20 , height : 20)
                                .aspectRatio(contentMode: .fit)
                                .foregroundColor(Color.white)
                                .padding(.leading , 10)
                            
                            TextFieldPro(placeholder : Text("Search").foregroundColor(.white), text: $search)
                                     .padding(.leading , 10)
                                     .padding(.trailing , 15)
                                     .frame( height : 45)
                                     .foregroundColor(Color.white)
                        }
                      
                    }.padding(.leading , 10)
                     .padding(.trailing , 10)
                     .padding(.bottom , 5)
                     .padding(.top , 15)
                    
                }.frame(height : 65)
                 .background(Color(hex: "#CC2323"))
             
                 Spacer()
                
                ScrollView{
                    
                   TabView(selection : $sliderIndex){
                        ForEach(Env.sharedInstance.settings.sliders , id : \.self){ slider in
                           SliderBite( data: slider).frame(width :UIScreen.main.bounds.width )
                        }
                      } .tabViewStyle(PageTabViewStyle())
                    
                    
                }
                .padding(.top , 10)
                .onAppear(){
                    API.checkin()
                }
                
            }
           
        }
    }
    
    struct Tab_Home_Previews: PreviewProvider {
        static var previews: some View {
            Tab_Home()
        }
    }
    
struct SliderBite: View {
 
    let data:DTO_SLIDER
    var body: some View {
      
        Group{
            if data.full_image != nil {
                KFImage(URL(string: data.full_image!)!)
                .fade(duration: 0.25)
                .onProgress { receivedSize, totalSize in  }
                .onSuccess { _ in print("Image loaded") }
                .onFailure { error in print("Load image error : \(error)") }
                .frame(width :UIScreen.main.bounds.width , height : 200)
                .aspectRatio(contentMode: .fill)
                .background(Color.black)
            }
        }.clipped()
    }
}

//Decoded from rest API

    struct DTO_SLIDER:Decodable,Hashable{
        var full_image:String?
    }

what did i miss there ?


Solution

  • The problem is not with KFImage, which is loading as expected, but with the fact that TabView is somehow unaware that the image has been loaded and that it needs to re-render it, but it can be solved easily:

    Store your urls to display in an array and then use ForEach inside the TabView - this is enough to make the images appear once they are loaded:

    struct TabHome: View {
        
        @State var search: String = ""
        let urls = [
            "https://www.broadway.org.uk/sites/default/files/styles/banner_crop/public/2019-10/star-wars-the-rise-of-skywalker-banner-min.jpg?h=639d4ef1&itok=z4KZ-3Tt",
            "https://www.broadway.org.uk/sites/default/files/styles/banner_crop/public/2019-11/star-wars-quiz-banner-min.jpg?h=f75da074&itok=bFe6rBe_"]
        
        var body: some View {
            VStack(spacing : 15) {
                HStack(spacing : 10) {
                    Image(systemName: "magnifyingglass")
                        .resizable()
                        .frame(width: 20, height: 20)
                    TextField("Search", text: $search)
                        .frame(height: 45)
                }
                .padding(.horizontal)
                .background(
                    RoundedRectangle(cornerRadius: 22.5)
                        .foregroundColor(Color.gray.opacity(0.1))
                    )
                .padding()
                
                ScrollView{
                    TabView {
                        ForEach(urls, id: \.self) { url in
                            SliderBite(url: url)
                        }
                    }   .tabViewStyle(PageTabViewStyle())
                    
                }
            }
        }
    }
    

    You might also want to make your KFImage resizable:

    struct SliderBite: View {
        
        let url: String
        
        var body: some View {
            KFImage(URL(string: url)!)
                .resizable()
                .fade(duration: 0.25)
                .aspectRatio(contentMode: .fill)
                .frame(height : 200)
                .background(Color.black)
        }
        
    }
    

    Loaded KFImage inside TabView

    To address showing of images from identical url

    If you declare DTO_SLIDER like this:

    struct DTO_SLIDER: Decodable, Identifiable {
        
        let full_image: String?
        let id = UUID()
    }
    

    it will ensure each one is unique even if it has identical full_image. It also means you can use it like that:

    ForEach(Env.sharedInstance.settings.sliders) { slider in
        //...
    }