Liam Keeley
Liam Keeley

Reputation: 307

Strange Image Behavior In TabView: Image Fails To Scale

This is a very interesting issue. Basically, I am attempting to scale down an image; it works in a normal view, but not in the tabview, which is pretty annoying. I have tried multiple ways of scaling the image (.frame, .scaleToFit, GeometryReader etc etc), but basically the image just refuses to scale. For simplicity, I will just use .frame in the example.

TabView() {
        StatsUI()
          .tabItem {
            Text("Report")
            Image("Stats")
              .resizable()
              .frame(width : 50, height : 50)
        }

And for reference, here is the code for the image that does scale.

struct StatsUI : View {
  var body : some View {
    HStack {
      Spacer()
      Text("Stats")
      Image("Stats")
        .resizable()
        .frame(width : 50, height : 50)
      Spacer()
    }
  }
}

If it looks just about the same, that is because it is.

And here is what it looks like.

UI

The image in the tabview just will not scale. Very odd.

Thanks to anybody that has any ideas!

Upvotes: 1

Views: 648

Answers (1)

vacawama
vacawama

Reputation: 154583

A tabItem takes Text and Image, and applying modifiers doesn't seem to work, so you'll need to supply an image that is natively scaled to the right size.

I've cobbled together this SwiftUI view which will create an Image that is drawn scaled to the size you specify.

You use it like this:

ScaledImage(name: "Stats", size: CGSize(width: 24, height: 24))

struct ScaledImage: View {
    let name: String
    let size: CGSize
    
    var body: Image {
        let uiImage = resizedImage(named: self.name, for: self.size) ?? UIImage()
        
        return Image(uiImage: uiImage.withRenderingMode(.alwaysOriginal))
    }
    
    func resizedImage(named: String, for size: CGSize) -> UIImage? {
        guard let image = UIImage(named: named) else {
            return nil
        }

        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { (context) in
            image.draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

Demo

Here is a demo using the same image in both the tabView and the tabItem:

struct ContentView: View {
    
    var body: some View {
        TabView() {
            ZStack {
                Color.yellow
                Image("Stats")
                    .resizable()
                    .frame(width: 200, height: 200)
            }
            .tabItem {
                ScaledImage(name: "Stats", size: CGSize(width: 26, height: 26))
                Text("Stats")
            }
        }
    }

}

enter image description here


Note: I started with this blog entry from NSHipster.com

Upvotes: 2

Related Questions