How can I make an Image with half of screen height in SwiftUI?
Asked Answered
A

3

6

I would like to centre an image on the screen but make its height half of the screen height? How is this possible?

Almedaalmeeta answered 28/11, 2020 at 21:41 Comment(0)
E
5

You can use a GeometryReader in SwiftUI to get details of a view's container geometry; Note that this approach is different to using the screen size, but this is a more flexible as you can use it inside other views.

struct RatioImage: View {
    let image: Image
    let heightRatio:CGFloat = 0.5
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                Spacer()
                image.resizable().aspectRatio(contentMode: .fit)
                .frame(width: geo.size.width, height: geo.size.height*heightRatio, 
                       alignment: .center)
                Spacer()
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        HalfHeight {
            RatioImage(image: Image(systemName:"photo.fill"))
        }
    }
}

By using SwiftUI's ViewBuilder capability you can create a generic container that can resize arbitrary content:

struct RatioContainer<Content: View>: View {
    let heightRatio:CGFloat
    let content: Content

    init(heightRatio:CGFloat = 0.5,@ViewBuilder content: () -> Content) {
            self.heightRatio = heightRatio
            self.content = content()
    }

    var body: some View {
        GeometryReader { geo in
            VStack {
                Spacer()
            content.frame(width: geo.size.width, height: geo.size.height*heightRatio, alignment: .center)
                Spacer()
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        RatioContainer {
            VStack {
                Image(systemName: "photo").resizable().aspectRatio(contentMode: .fit)
                Text("Some caption text").font(.caption)
            }
        }
    }
}

You can even nest instances of the container, which won't work correctly if you use UIScreen dimensions:

struct ContentView: View {
    var body: some View {
        VStack {
            RatioContainer {
                VStack {
                    Image(systemName: "photo").resizable().aspectRatio(contentMode: .fit)
                    Text("Some caption text").font(.caption)
                    RatioContainer(heightRatio:0.3) {
                        VStack {
                            Image(systemName: "photo.fill").resizable().aspectRatio(contentMode: .fit)
                            Text("Some other caption text").font(.caption)
                        }
                    }
                    
                }
            }
            
        }
    }
}
Endolymph answered 29/11, 2020 at 10:58 Comment(0)
S
6

Like this, if you have a question about code ask plz, I think it is easy to understand.

import SwiftUI

struct ContentView: View {
    var body: some View {

        Image(systemName: "person")
            .resizable()
            .frame(width: UIScreen.main.bounds.height/2, height: UIScreen.main.bounds.height/2)
            .aspectRatio(contentMode: .fit)
    }
}

updated: for supporting orientation change:

import SwiftUI

struct ContentView: View {

@State var sizeOfImage: CGFloat = UIScreen.main.bounds.height/2

var body: some View {

    Image(systemName: "person")
        .resizable()
        .frame(width: sizeOfImage, height: sizeOfImage)
        .aspectRatio(contentMode: .fit)
        .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
            sizeOfImage = UIScreen.main.bounds.height/2  }



    }
}
Sheerness answered 28/11, 2020 at 21:49 Comment(6)
Is this cross platform or only works for iOS?Almedaalmeeta
It works for sure in every iPhone, iPad, iPod but for macOS it must do some works same for watchOSSheerness
This code works, but you will need to use a GeometryReader instead if you want the image to resize when the phone rotates portrait to landscape.Exacerbate
@nicksarno: the question was clearly about Image Size not orientation how ever i provided an update for that as well without using GeometryReader!Sheerness
@Omid: Well if they used your original code and the phone rotated, your image size would be wrong. Just trying to help!Exacerbate
@nicksarno: no problem, thanks for help! good jobSheerness
E
5

You can use a GeometryReader in SwiftUI to get details of a view's container geometry; Note that this approach is different to using the screen size, but this is a more flexible as you can use it inside other views.

struct RatioImage: View {
    let image: Image
    let heightRatio:CGFloat = 0.5
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                Spacer()
                image.resizable().aspectRatio(contentMode: .fit)
                .frame(width: geo.size.width, height: geo.size.height*heightRatio, 
                       alignment: .center)
                Spacer()
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        HalfHeight {
            RatioImage(image: Image(systemName:"photo.fill"))
        }
    }
}

By using SwiftUI's ViewBuilder capability you can create a generic container that can resize arbitrary content:

struct RatioContainer<Content: View>: View {
    let heightRatio:CGFloat
    let content: Content

    init(heightRatio:CGFloat = 0.5,@ViewBuilder content: () -> Content) {
            self.heightRatio = heightRatio
            self.content = content()
    }

    var body: some View {
        GeometryReader { geo in
            VStack {
                Spacer()
            content.frame(width: geo.size.width, height: geo.size.height*heightRatio, alignment: .center)
                Spacer()
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        RatioContainer {
            VStack {
                Image(systemName: "photo").resizable().aspectRatio(contentMode: .fit)
                Text("Some caption text").font(.caption)
            }
        }
    }
}

You can even nest instances of the container, which won't work correctly if you use UIScreen dimensions:

struct ContentView: View {
    var body: some View {
        VStack {
            RatioContainer {
                VStack {
                    Image(systemName: "photo").resizable().aspectRatio(contentMode: .fit)
                    Text("Some caption text").font(.caption)
                    RatioContainer(heightRatio:0.3) {
                        VStack {
                            Image(systemName: "photo.fill").resizable().aspectRatio(contentMode: .fit)
                            Text("Some other caption text").font(.caption)
                        }
                    }
                    
                }
            }
            
        }
    }
}
Endolymph answered 29/11, 2020 at 10:58 Comment(0)
Y
0

I had to call aspectRatio before .frame() so the image doesn't stretch

Image(imageName)
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/2)
Yawl answered 9/11 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.