46

I want to resize an Image frame to be a square that takes the same width of the iPhone's screen and consequently the same value (screen width) for height.

The following code don't work cause it gives the image the same height of the view.

var body: some View {
        Image("someImage")
            .resizable()
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
            .clipped()
    }
Ky.
  • 28,753
  • 48
  • 180
  • 285
Rubens Neto
  • 532
  • 1
  • 4
  • 7
  • It sounds like you have a different issue, because you are working with `Image`. (And yes, there are two fairly simple ways to get the screen width, but I don't think they will solve your problem.) Have you tried adding this modifier? `.aspectRatio(contentMode: .fit)` –  Aug 30 '19 at 13:28
  • Second comment... I upvoted the answer by @DoesData because it's one to two `SwiftUI` ways of doing this (and didn't downvote the answer from @MehmetAliVataniar even though it makes some serious non-SwiftUI assumptions. The second way - found in the following question, uses subclassing `UIHostingController` and may get you *much* more things you can do: https://stackoverflow.com/questions/57441654/swiftui-repaint-view-components-on-device-rotation/57442517#comment101361813_57442517 –  Aug 30 '19 at 13:33
  • maybe this could help https://stackoverflow.com/questions/57577462/get-width-of-a-view-using-in-swiftui/57577752#57577752 – Giuseppe Sapienza Aug 30 '19 at 14:28
  • 1
    Possible duplicate of [Get width of a view using in SwiftUI](https://stackoverflow.com/questions/57577462/get-width-of-a-view-using-in-swiftui) – Giuseppe Sapienza Aug 31 '19 at 11:42

5 Answers5

69

You can create a UIScreen extension for the same. Like:

extension UIScreen{
   static let screenWidth = UIScreen.main.bounds.size.width
   static let screenHeight = UIScreen.main.bounds.size.height
   static let screenSize = UIScreen.main.bounds.size
}

Usage:

UIScreen.screenWidth
bestiosdeveloper
  • 1,837
  • 9
  • 26
  • 17
    GeometryReader is the way to go! It will update according to system event such as orientation change – Sajjon Aug 30 '19 at 14:29
  • And this would require UIKit, so no more building that SwiftUI for Mac. – Andres Canella Jun 02 '20 at 22:28
  • 1
    thanks for this. hopefully soon there will be a swiftui native code for it. but this worked for what I needed as my was already nested within another view so Geometry Reader wasn't working for me. I couldn't get global width and height. – Jayson Jul 05 '20 at 09:16
  • 2
    The `.size` isn't necessary on `UIScreen.main.bounds`, so you can use `UIScreen.main.bounds.width/height` directly, eliminimating one step and making the raw calls without the exception more viable. – Jeehut Jul 17 '20 at 07:30
  • @Jeehut: deprecated since iOS 2.0 – vikingosegundo Dec 29 '21 at 19:28
38

Try using Geometry Reader

let placeholder = UIImage(systemName: "photo")! // SF Symbols

struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            Image(uiImage: placeholder) 
            .resizable()
            .frame(width: geometry.size.width, height: geometry.size.height, alignment: .center)
            // .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
            .clipped()
        }
    }
}

enter image description here

DoesData
  • 5,786
  • 3
  • 34
  • 56
  • I tested the code but, at least in my preview, the image was still the same size of the screen instead of a square. – Rubens Neto Sep 03 '19 at 08:07
  • [@RubensNeto](https://stackoverflow.com/users/6316195/rubens-neto) - I'm not sure about a preview since I am not running OSX Catalina, but running this code on simulator / device yields the above output where the width / height are equal. I hope that helps. – DoesData Sep 03 '19 at 09:54
  • 3
    The problem with GeometryReader is that it applies only to the level you are at. If you trying to write a generic modal pop-up and want to obscure the screen below the pop-up, GeometryReader will not give you any information to do that. To do that properly requires a lot of code. – P. Ent Nov 04 '20 at 14:04
  • @P.Ent have you looked at [GeometryProxy](https://developer.apple.com/documentation/swiftui/geometryproxy)? "A proxy for access to the size and coordinate space (for anchor resolution) of the container view." – DoesData Nov 04 '20 at 20:00
  • 1
    Note that there is a typo in this answer....the height should be geometry.size.height (not width) – GarySabo Mar 28 '21 at 16:00
17

You can use UIScreen.main.bounds .width or .height

.frame(
   width:UIScreen.main.bounds.width,
   height:UIScreen.main.bounds.height
)
  • 1
    GeometryReader is the way to go! It will update according to system event such as orientation change – Sajjon Aug 30 '19 at 14:29
  • 11
    @Sajjon GeometryReader also breaks your screen and causes things to expand unnecessarily causeing more headaches. – Just a coder Dec 01 '20 at 13:46
  • 2
    This is the certain way to know the HARDWARE screen size, as specified in the question. And more importantly, if you need to get the hardware screen _height_ then GeometryReader will fail you -- it subtracts out the status bar at the top of the screen! And, thankfully, `let hardwareScreenSize = UIScreen.main.bounds.size` works just fine in SwiftUI. – ConfusionTowers Mar 18 '21 at 00:34
  • @Justacoder you can wrap GeometryReader in .background() or hide it in ZStack to avoid layout problems – Hai Feng Kao Jul 26 '21 at 14:25
6

The simplest way would be to make the image resizable and set the aspect ratio to 1.0:

var body: some View {
    Image("someImage")
       .resizable()
       .aspectRatio(1.0, contentMode: .fit)
}
Gene Z. Ragan
  • 2,411
  • 2
  • 28
  • 38
LuLuGaGa
  • 10,500
  • 5
  • 38
  • 50
0

I've come up with a solution using Environment Keys, by creating the following:

private struct MainWindowSizeKey: EnvironmentKey {
    static let defaultValue: CGSize = .zero
}

extension EnvironmentValues {
    var mainWindowSize: CGSize {
        get { self[MainWindowSizeKey.self] }
        set { self[MainWindowSizeKey.self] = newValue }
    }
}

Then by reading the size from where the window is created:

var body: some Scene {
    WindowGroup {
        GeometryReader { proxy in
            ContentView()
                .environment(\.mainWindowSize, proxy.size)
        }
    }
}

Finally I can directly get the window size in any SwiftUI view, and it changes dynamically (on device rotation or window resizing on macOS):

@Environment(\.mainWindowSize) var mainWindowSize