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 ?
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)
}
}
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
//...
}