Learn Courses My Dashboard

NBA App Stats Challenge - SVG Image Sizing

Hello hello! I am attempting my first community app challenge. So far so good. I finally figured out how to render the SVG team logos. However, I am having difficulty resizing the logos to fit the parent.

I ended up implementing SVGKit to get the image to work. Before that, I tried the UIImage with the data object but that wasn’t working, like in the City Sights App. To implement SVGKit, I created a UIViewRepresentable view that returned a UIImageView with the SVG image, and set the frame inside that as well. Didn’t work.

Here’s the code for the UIViewRepresentable view called SVGLogo…

import SwiftUI
import SVGKit

struct SVGLogo: UIViewRepresentable {

var data:Data?

func makeUIView(context: Context) -> UIImageView {
    
    let imgViewObj = UIImageView()
    let logoSVG:SVGKImage = SVGKImage(data: data!)
    
    imgViewObj.image = logoSVG.uiImage
    
    imgViewObj.contentMode = .scaleAspectFit
    
    
    // resize svg, doesn't work
    //        let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 48 * 
    1920/1080, height: 48))
    //        imgViewObj.frame.size = CGSize(width: containerView.frame.width, 
    height: 
    containerView.frame.height)
    //        imgViewObj.contentMode = .scaleAspectFit
    
    return imgViewObj
}

func updateUIView(_ uiView: UIImageView, context: Context) {
    
    // update element if needed
    
}

}

Here’s the code for the parent of the SVGLogo…
struct StandingsRowView: View {

@EnvironmentObject var model:ContentModel

@ObservedObject var team:Teams

var body: some View {
    
    ZStack {
        
        Rectangle()
            .foregroundColor(Color.white)
            .cornerRadius(10)
            .shadow(radius:10)
            

        HStack {
            
            HStack {
                Text(String(team.ConferenceRank ?? 0))
                
                SVGLogo(data: team.imageData ?? Data())
                    .frame(width: 45, height: 45)

                Text(team.Name ?? "")
            }.frame(height: 48)
            
            Spacer()
            
            HStack {
                // TODO: implement if favorite, show yellow star
                Text("\(String(team.Wins ?? 0)) - \(String(team.Losses ?? 0))")
            }
        }.padding(.horizontal)
    }.frame(height:48)
}

}

I’ve looked online and tried a bunch of different methods, but still cant figure it out. Please help! thank you in advance :+1:

I’m currently having the same issue, found any help?

Hi @givemedarock08 after a lot of web surfing, it turns out there’s no official was of resizing. After many trial and errors. I came up with a solution that works for me.

According to a comment I found on the GitHub Repo, it appears that SVGKFastImageView is a version of UIImageView which the article references.

http://cocoadocs.org/docsets/SVGKit/1.2.0/Classes/SVGKFastImageView.html

As per that article

The default if you do not set a content mode is .scaleToFill shown below left.
.scaleToFill stretches the view to fill the available space without
maintaining the aspect ratio.

So what I did was that I added a .scaleEffect modifier to my view and reduced the initial scale 4 times smaller to fit perfectly to my frame.

SVGLogo(SVGUrl: homeTeamLogoUrl)
          .scaleEffect(CGSize(width: (1.0/4), height: (1.0/4)))
           .frame(width: 50, height: 50, alignment: .center)

See the screenshot below, I hope this works for you. And if you found a more efficient solution, pls let me know :relieved:

1 Like

@President_Raindas Hey thanks for the followup! I really like the simplicity of your implementation. I ended up using your suggestion with my implementation. For my implementation, I added one line to the existing SVGLogo struct (above).

struct SVGLogo: UIViewRepresentable {

var data:Data?

func makeUIView(context: Context) -> UIImageView {
    
    let imgViewObj = UIImageView()
    
    let logoSVG:SVGKImage? = SVGKImage(data: data ?? Data())
    
    guard logoSVG != nil else {
        return imgViewObj
    }

    // I added this, resizing the svg before setting it to the UIImageView
    logoSVG!.scaleToFit(inside: CGSize(width: 50, height: 50))

    imgViewObj.contentMode = .scaleAspectFit
    
    imgViewObj.image = logoSVG!.uiImage!
    
    return imgViewObj
}

func updateUIView(_ uiView: UIImageView, context: Context) {
    
    // update element if needed
}

}

So I believe the advantage of resizing the svg before setting it to the UIImageView (or something equivalent) is it saves memory when running the app, because you have a smaller image. I read that in a stackoverflow comment and it makes sense to me, but I’m not sure if that is completely correct.

At first, I think I was using my implementation incorrectly. Initially I made the image the right size for the logos in my StandingsView, but then the logos were too small for my ScoresView. So what I think I will do is resize the image maybe 50% or so, then use the .scaleEffect() that you suggested to get the proper sizing to match what I want in the respective views.

Hope this makes sense! Thanks again!

2 Likes

@givemedarock08 glad it all worked out. :v:

Your method works better for the sake of memory. :ok_hand: