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()
}
}
}
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:
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:
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
Swift 4 Decode Simple Root Level JSON Value
Swiftui List Empty State View/Modifier
Can't Hook Up an Outlet Collection in Xcode 6 Using Storyboard
Constant Speed Orbit Around Point with Sknode
Swift, Auto Resize Custom Table View Cells
Why Should Not Directly Extend Uiview or Uiviewcontroller
Swift - Avaudioplayer, Sound Doesn't Play Correctly
Arkit - Viewport Size VS Real Screen Resolution
Swift Error Handling for Methods That Do Not Throw
Mutable Binding in Swiftui Live Preview
Error: Use of Unresolved Identifier 'Process'
Binding an Element of an Array of an Observableobject:'Subscript(_:)' Is Deprecated
Is There an Alternative to Initialize() in MACos Now That Swift Has Deprecated It
Swift/Uiview/Drawrect - How to Get Drawrect to Update When Required
Swift: How to Call Cckeyderivationpbkdf from Swift