Swiftui: Prevent Image() from Expanding View Rect Outside of Screen Bounds

SwiftUI: Prevent Image() from expanding view rect outside of screen bounds

You have to limit the frame size of the out-of-bounds Image before it is being picked up by the ZStack to avoid the ZStack to grow and so the Overlay to go out of position.

edit: aheze shows with his answer a way around using GeometryReader by putting the Image into the background of Overlay() with .background(Image()..). This avoids the usage of ZStack and GeometryReader completely and is possibly a cleaner solution.

Based on parent view size

struct IgnoringEdgeInsetsView2: View {
var body: some View {
ZStack {
GeometryReader { geometry in
Image("smile")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: geometry.size.width,
maxHeight: geometry.size.height)
}
Overlay()
}
}
}

Based on screen size

struct IgnoringEdgeInsetsView: View {
var body: some View {
ZStack {
Image("smile-photo")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: UIScreen.main.bounds.width,
maxHeight: UIScreen.main.bounds.height)
Overlay()
}
}
}

Example

prevent views from expanding out of screen width

The problem is your Dentist-line is too long and your code handles it the wrong way.

Do it like this:

                    Text("Dentist | General Dentistry | General Dentistry Dentistry")
.fixedSize(horizontal: false, vertical: true) // <--- like this
.lineLimit(2)
.foregroundColor(Color.gray)
.font(.system(size: 13, weight: .regular))
// .fixedSize(horizontal: true, vertical: false)
.multilineTextAlignment(.leading)

Trying to format an image in the top right corner – SwiftUI

Edit: Because your image is in a ZStack, it will expand and overflow the screen. You should use the background modifier instead.

struct ContentView: View {
var body: some View {
VStack{
HStack {
Spacer()

Button(action: {}, label: {
Image(systemName: "gear").resizable().aspectRatio(contentMode: .fit)
.frame(width: 50, height: 50) })
}
.padding()

Spacer()

HStack {
Button(action: {}, label: {
Image(systemName: "plus")
.resizable().aspectRatio(contentMode: .fit).frame(width: 150, height: 150, alignment: .center).padding().border(Color.white, width: 8).cornerRadius(10.0).foregroundColor(.white)
})
}
Spacer()
}

/// here!
.background(
Image("Background")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
)
}
}

Result:

Image of gradient in background, plus icon centered, settings icon at top-right

If you're using a ZStack to layer the background, a view inside there might be expanding beyond the edges. I've tried to reproduce what you want below, but it would be helpful if you posted some more code.

struct ContentView: View {
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [.blue, .green]), startPoint: .top, endPoint: .bottom)
.ignoresSafeArea()

Image(systemName: "plus")
.resizable()
.foregroundColor(.white)
.frame(width: 200, height: 200)

VStack{
HStack {
Spacer()

Button(action: { }) {
Image(systemName: "gear")
.resizable()
.foregroundColor(.white)
.frame(width: 50, height: 50)

}
}

Spacer()
}
}
}
}

Result:

gradient background, plus icon centered, settings icon at top-right

SwiftUI layout grows outside the bounds of the device when using .edgesIgnoringSafeArea()

After reading the updated question I have made some changes and tried to make a small demo. In this, I am using the same approach as before, put NavigationView in your main tab view and with this you don't have to hide and show every time you come or leave your main tab view.

import SwiftUI

struct ContentView: View {
var body: some View {
MainTabView()
}
}

struct MainTabView : View {

enum Item : CaseIterable {
case home
case resources
case profile
}

@State private var selected : Item = .home

var body: some View {
NavigationView {
VStack(spacing: 0.0) {
ZStack {
Group {
HomeView()
.zIndex(selected == .home ? 1 : 0)

ResourcesView()
.zIndex(selected == .resources ? 1 : 0)

ProfileView()
.zIndex(selected == .profile ? 1 : 0)

}
.frame(minWidth: .zero, maxWidth: .infinity, minHeight: .zero, maxHeight: .infinity)
.background(Color.white)

}

HStack {
Group {
Image(systemName: "house.fill")
.onTapGesture {
self.selected = .home
}

Spacer()

Image(systemName: "plus.app.fill")
.onTapGesture {
self.selected = .resources
}

Spacer()

Image(systemName: "questionmark.square.fill")
.onTapGesture {
self.selected = .profile
}
}
.padding(.horizontal, 30)
}
.frame(height: 40)
.foregroundColor(Color.white)
.background(Color.gray)


// Code here for building and showing/hiding a Toolbar
// Basically just a HStack with a few buttons in it
}
.edgesIgnoringSafeArea(.bottom)
} // <- This causes the screen to jump to 846
}
}

struct ProfileView : View {
@State private var showQuestionnaireView = false

var body: some View {
// NavigationView {
ZStack {

NavigationLink(destination: QuestionnaireView( showQuestionnaireView:$showQuestionnaireView),
isActive: $showQuestionnaireView) {
Text("Show Questionnaire View")
}
.navigationBarTitle("")
.navigationBarHidden(true)

}

// }
}
}

struct QuestionnaireView : View {
@Binding var showQuestionnaireView : Bool

var body: some View {
GeometryReader { screenGeometry in
ZStack {
Color.orange
VStack {
Text("Top")
Spacer()
Text("Bottom")
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
}

struct HomeView: View {
var body: some View {
NavigationLink(destination: SecondView()) {
Text("Home View")
}
}
}

struct ResourcesView: View {
var body: some View {
NavigationLink(destination: SecondView()) {
Text("Resources View")
}
}
}

struct SecondView: View {
var body: some View {
Text("Second view in navigation")
.background(Color.black)
.foregroundColor(.white)
}
}


struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice(PreviewDevice(rawValue: "iPhone 11"))
}
}

Why do the views extend wider than the screen?

This is happening because of the layout of PaddedImageView View, you can actually remove the Spacer since it is not needed there.

So change

struct PaddedImageView: View {
let color: Color = .red

var body: some View {
ZStack {
color
Image(systemName: "edit")
.resizable()
.padding()
}
Spacer()
}
}

to

struct PaddedImageView: View {
let color: Color = .red

var body: some View {
ZStack {
color
Image(systemName: "edit")
.resizable()
.padding()
}
}
}

Note:
SwiftUI Engine infers the layout of your view from the implementation of the body property. It's recommended to have one Parent View inside the body property.



Related Topics



Leave a reply



Submit