2

I'm new to SwiftUI, so I'm following a tutorial to get familiar with it. However, my app's content is getting cut off on smaller screens (both vertically and horizontally). How can I prevent this from happening?

Here's my code:

EDIT: I have added borders around my images and resized the images as suggested in your comments and answers, but as you can see, the images don't appear to be taking up any more space than they're supposed to.

struct ContentView: View {
  var body: some View {
    ZStack {
      Image("background").ignoresSafeArea(.all)
      VStack {
        Spacer()
        Image("logo")
          .resizable()
          .aspectRatio(contentMode: .fit)
          .frame(width: 100)
          .border(Color.black)
        Spacer()
        HStack {
          Spacer()
          Image("card3").border(Color.black, width: 3)
          Spacer()
          Image("card4").border(Color.black, width: 3)
          Spacer()
        }
        Spacer()
        Image("dealbutton")
          .resizable()
          .aspectRatio(contentMode: .fit)
          .frame(width: 100)
          .border(Color.black)
        Spacer()
        HStack {
          Spacer()
          VStack {
            Text("Player").padding(.bottom, 10)
            Text("0").font(.largeTitle)
          }
          Spacer()
          VStack {
            Text("CPU").padding(.bottom, 10)
            Text("0").font(.largeTitle)
          }
          Spacer()
        }
        .foregroundColor(.white)
        Spacer()
      }
    }
  }
}

And here's what the preview looks like on an iPod touch: iPod Touch Preview

wristbands
  • 1,021
  • 11
  • 22
  • Try doing `Image("dealbutton").resizable()` – aheze Apr 19 '21 at 18:56
  • Ok just tried that, but it just made the dealbutton take up practically the entire screen... I think the problem has more to do with the frame of the ZStack not being confined to the bounds of the screen. But I'm not sure how to fix that. – wristbands Apr 19 '21 at 19:02
  • Are your "war" and "deal" images cropped to the size of the text we see, or is there empty transparent space around them? In other words, if you use `.border` to add a border around them, will it show that they're right up against the cards and buttons? – jnpdx Apr 19 '21 at 19:04
  • @jnpdx I tried adding a border around the images like you suggested, and it shows the border right up against the cards and buttons. – wristbands Apr 19 '21 at 19:33

2 Answers2

3

Try making Image("background") resizable or set it as the .background(:) of your ZStack. Currently the background image isn’t resizable and is larger than the screen, so it shows at its native size and stretches its parent ZStack beyond the bounds of the screen. Since your content is in that same ZStack, it also extends beyond the bounds of the screen

Adam
  • 4,405
  • 16
  • 23
1

Your issue is related to your images that you have present on the view structure itself. Images are rendered at 100% their size, irrespective of their constraints. This will cause other views to be pushed away. The solution for that is to set a set size on the view itself that matches within the confines of your available space. Also you're resizing your ZStack which also resizes the content inside of the ZStack. For example.

Image("logo")
    .resizeable()
    .aspectRatio(contentMode: .fit)
    .frame(width: 100)

Handling your image like this will ensure that it is set to the appropriate size when it is rendered. Then you can have the remaining views fall into place in a way that's expected. If you need it scaled on a % for the screen size you can use a GeometryReader to scale the view for different screen sizes.

GeometryReader { reader in 
    Image("logo")
        .resizeable()
        .aspectRatio(contentMode: .fit)
        .frame(width: reader.size.width * 0.2)
}

Finally, remove your ZStack and set it up like this.

VStack {
    //Your Content
}.background(
      //Make sure to set the edgesIgnoring.. on this NOT the VStack
      Image("background").edgesIgnoringSafeArea(.all)
  )

Tip When Working with Stacks

Stacks, wether VStack, HStack, or ZStack's all ALWAYS have their frame set to the content that is held inside of them. If you had an object with a width of 100 and a height of 10,000 then the Stack would also have those dimensions, unless otherwise specified with a Modifier such as .frame(width...) or even, in your case, an Image that is resized.

Suppose your same stack then has a width: 10, height: 10 view added to it, it would still retain the same size as the largest content held within. This is of course handled differently with HStack and VStacks as they actually stack things in a 2D plane, whereas the ZStack works on the 3D plane.

xTwisteDx
  • 2,152
  • 1
  • 9
  • 25
  • I tried applying what you suggested in the first code snippet to both of my images (logo and dealbutton), but it didn't seem to work. The screen layout looks almost exactly identical, except I could make the images slightly bigger or smaller. – wristbands Apr 19 '21 at 19:28
  • Also add it to your Cards. Finally, remove the ZStack and set a `.background(Image("background"))` modifier to the `VStack` – xTwisteDx Apr 19 '21 at 20:12
  • Thanks so much for that in-depth explanation on how stacks get their size and how to make sure images stay within bounds. I think you're right that it makes the most sense to just use the `Image("background")` as the background image of the VStack, rather than putting the image inside a ZStack. The main reason I didn't accept your answer is because there was no need to make any other images resizable; all I had to do was fix the background image, which is exactly what the other answer suggested. But your response was still very explanatory and helpful, which is why I gave it an upvote :) – wristbands Apr 19 '21 at 20:42
  • <3 my hero. @wristbands – xTwisteDx Apr 19 '21 at 20:44