I wanted this ErrorView to appear centered on my view. I still find GeometryReaders pretty tricky and I can’t figure out why this ErrorView keeps sticking to the topLeading corner. I’m sure it’s something simple . . . . . help?
struct ErrorView: View {
@State var color = Color.black.opacity(0.7)
@Binding var alert : Bool
@Binding var error : String
var body: some View {
//TODO: Figure out why it's aligning to top left instead of center
GeometryReader { geo in
VStack {
HStack {
Text(self.error == "RESET" ? "Email sent!" : "Error")
.font(.title)
.fontWeight(.bold)
.foregroundColor(self.color)
Spacer()
}
.padding(.horizontal, 25)
Text(self.error == "RESET" ? "Follow the instructions in your email to reset your password." : self.error)
.foregroundColor(self.color)
.padding(.top)
.padding(.horizontal, 25)
Button {
self.alert.toggle()
} label: {
Text(self.error == "RESET" ? "Got it!" : "Cancel")
.foregroundColor(.white)
.padding(.vertical)
.frame(width: UIScreen.main.bounds.width - 120)
}
.background(Color("pink"))
.cornerRadius(10)
.padding(.top, 25)
}
.padding(.vertical, 25)
.frame(width: UIScreen.main.bounds.width - 70)
.background(Color.white)
.cornerRadius(15)
}
.background(Color.black.opacity(0.35).edgesIgnoringSafeArea(.all))
}
}
Where ErrorView is instantiated:
@State var color = Color.black.opacity(0.7)
@State var email = ""
@State var password = ""
@State var isVisible = false
@Binding var show : Bool
@State var alert = false
@State var error = ""
var body: some View {
ZStack {
ZStack(alignment: .topTrailing) { }
if self.alert {
// TODO: Is this why error aligns to top left?
ErrorView(alert: self.$alert, error: self.$error)
}
}
}
For your case use, you really don’t need to use a Geometry Reader. You can configure the message box to be in the middle using the default behaviour of a SwiftUI View.
By default anything you add to a View will be centred. That’s clear to see when you first create a new SwiftUI view where it has “Hello World!” in the middle.
Consider this version of your ErrorView
struct ErrorView: View {
@State var color = Color.black.opacity(0.7)
@Binding var alert : Bool
var error : String
var body: some View {
//TODO: Figure out why it's aligning to top left instead of center
ZStack {
Color.black.opacity(0.35)
.edgesIgnoringSafeArea(.all)
VStack(spacing: 20) {
Text(error == "RESET" ? "Email sent!" : "Error")
.font(.title)
.fontWeight(.bold)
.foregroundColor(color)
Text(error == "RESET" ? "Follow the instructions in your email to reset your password." : error)
.foregroundColor(color)
Button {
alert.toggle()
} label: {
Text(error == "RESET" ? "Got it!" : "Cancel")
.font(.system(size: 20).weight(.bold))
.foregroundColor(.white)
.padding(.vertical, 15)
}
.frame(width: 150)
.background(Color.pink)
.cornerRadius(10)
}
.padding()
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(25)
.padding(.horizontal, 30)
}
}
}
Note that there is no need to define the error String as a Binding since you are not changing it inside the ErrorView, rather all you are doing is displaying the contents so define it as a var which means that it is a required parameter when calling the ErrorView.
The VStack in which the 3 elements are placed has a spacing parameter of 20 which gives the contents of the VStack some vertical room to breathe.
The width of the background color can be extended to the edge of the screen by using .frame(maxWidth: .infinity) and then bringing it in by using additional amount of horizontal padding.