SwiftUI content is not displayed on top of the screen - swift

I have a NavigationView and then a VStack. The issue is that everything inside VStack is being displayed in the middle of the screen and not on top. Why is that?
var body: some View {
VStack {
VStack(alignment: .leading) {
if (request?.receiverID ?? "") == userDataViewModel.userID {
Text("\(sendertFirstName) wants to ship your package").font(.title)
} else {
Text("You want to ship \(recieverFirstName)'s package").font(.title)
}
HStack{
Image(systemName: "clock.fill").font(.subheadline)
Text("\(createdAt, formatter: DateService().shortTime)").font(.subheadline).foregroundColor(.secondary)
}
HStack {
VStack(alignment: .leading) {
HStack {
Image(systemName: "person.fill").font(.subheadline)
Text(sendertFirstName).font(.subheadline).foregroundColor(.secondary)
}
}
Spacer()
VStack(alignment: .leading) {
HStack {
Image(systemName: "star.fill")
Text(rating).font(.subheadline).foregroundColor(.secondary)
}
}
}
}
VStack(alignment: .center) {
HStack {
Button("Accept") {
//print(self.request.createdAt)
//FirestoreService().respondToRequest(request: self.request.documentReference, status: "accepted")
}
.padding()
Button("Decline") {
//FirestoreService().respondToRequest(request: self.request.documentReference, status: "declined")
}
.foregroundColor(.red)
.padding()
}
}
ScrollView {
ForEach(messages) { (message: Message) in
if message.senderId == self.userDataViewModel.userID {
HStack {
Spacer()
Text(message.text).font(.subheadline).padding(7.5).background(self.blue).cornerRadius(30).foregroundColor(.white)
}.padding(.bottom, 2)
} else {
HStack {
Text(message.text).font(.subheadline).padding(7.5).background(self.gray).cornerRadius(30).foregroundColor(.white)
Spacer()
}.padding(.bottom, 2)
}
}
}
HStack {
TextField("Message", text: $inputMessage).padding(5).background(self.gray).cornerRadius(30).foregroundColor(.white)
Button(action: {
let msg: [String: Any] = [
"text": self.inputMessage,
"createdAt": Timestamp(),
"senderId": self.userDataViewModel.userID
]
self.reference.updateData([
"messages": FieldValue.arrayUnion([msg])
])
self.messages.append(Message(dictionary: msg))
self.inputMessage = ""
}) {
Image(systemName: "arrow.up.circle.fill").foregroundColor(self.blue).font(.title)
}
}
Spacer()
}
.padding()
.border(Color.red)
}
I want the content to start on top not on the middle. What am I doing wrong here?

You don't need the NavigationView - the way you have everything set up now you are wrapping the VStack in a NavigationView twice and the massive white space is the second empty navigation bar.
By default most Views take only the amount of space they need and they are placed in the center of their parent view. So if you want your content to be placed at the top, you need to add Spacer() as the last element in your VStack:
var body: some View {
VStack {
/* ... */
Spacer()
}
}
Spacer is one of the rare Views that takes all space offered to it by the parent view and will push all of your content upwards.

Maybe you can try this way:
NavigationView {
VStack {
...
}.frame(maxHeight:.infinity, alignment: .top)
.padding()
.border(Color.red).navigationBarTitle("", displayMode: .inline)
}

Add a .navigationBarHidden(true) to your VStack

Related

Complex view using HStack, LazyHStack or Grid?

So I have the following code:
struct MapPinSheetMoreInfoView: View {
let item: Place
var body: some View {
HStack(alignment: .top, spacing: 3) {
VStack(alignment: .leading) {
Text("Location")
.font(.caption.weight(.semibold))
.lineLimit(1)
if item.address != "" {
Text(item.address)
.font(.footnote)
.foregroundColor(.secondary)
Text(item.city + ", " + item.state)
.font(.footnote)
.foregroundColor(.secondary)
} else {
Text("N/A")
}
}
Divider()
VStack(alignment: .leading) {
HStack {
VStack {
Text("Weather")
.font(.caption.weight(.semibold))
.lineLimit(1)
HStack(alignment: .firstTextBaseline, spacing: 3) {
Image(systemName: "waveform")
.imageScale(.small)
.foregroundColor(.secondary)
Text("79%")
.font(.caption.weight(.regular))
.foregroundColor(.secondary)
}
}
Divider()
HStack {
Text("Hello, World!")
}
}
Divider()
HStack {
HStack {
Text("Hello, World!")
}
Divider()
HStack {
Text("Hello, World!")
}
}
}
}
}
}
Which produces this weird, out of place view:
As you can see, it all out of place - What type of grid system can I utilize to keep the exact percentage of views on a complex view like this? I want something like this:
What grid system let's me keep percentages and always have the VStack/HStack be that large?

How to make a List background black in SwiftUI?

What I did to make the entire screen black is to use this construction in my view:
ZStack {
Color.black.ignoresSafeArea() }
And for the List modifiers I used the following two:
.listRowBackground(Color.black)
.listStyle(.plain)
This works great.
But then I want to add a view on top of my List (like a header) and some white space appears around it ? Where does that come from ? And how can I change it to black ?
Here is my complete code:
struct WorkoutView: View {
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
List {
TempView()
ForEach(1..<30) { index in
VStack(alignment: .leading, spacing: 4) {
Text("one line")
.foregroundColor(.white)
.font(.title)
.fontWeight(.bold)
}
.padding(.vertical)
}
.listRowBackground(Color.black)
}
.listStyle(.plain)
}
}
}
struct TempView: View {
var body: some View {
ZStack(alignment: .leading) {
Color.black.ignoresSafeArea()
Text("Hello World")
.foregroundColor(.red)
.font(.largeTitle)
.bold()
}
}
}
Just do the same thing you did for the ForEach: add a .listBackground() modifier. Like this:
TempView()
.listRowBackground(Color.black)

Why is my SwiftUI VStack not aligning properly?

I'm trying to make my VStack padding consistent regardless of the content, and it doesn't seem to be working in certain instances (as if the Scrollview aligned with the center instead).
Ideally, I would like the padding to be consistent regardless of the content on the screen.
Such as this (when padding isn't consistent):
Here is the code used:
var body: some View {
VStack {
HStack{
Button(action: {}) {
Image(systemName: "arrow.backward")
}
Spacer(minLength: 0)
Button(action: {}) {
Image(systemName: "bookmark")
}
}
.padding(.vertical, 10)
ScrollView {
VStack{
HStack{
VStack (alignment: .leading, spacing: 5) {
Text("Today's Poem, \(currentDate)")
if let poem = fetch.poems.first {
Text("\(poem.title)")
Text("BY "+poem.author.uppercased())
VStack (alignment: .leading) {
ForEach(poem.lines, id: \.self) {
Text($0)
.multilineTextAlignment(.leading)
}
}
} else {
Spacer()
}
}
}
}
}
Button("Get Next Poem") { fetch.getPoem() }
}
.background(Color.white.ignoresSafeArea())
.padding(.horizontal)
}
}
Any ideas? Thanks in advance.
Change the innermost
VStack {
to
VStack(alignment: .leading) {

How to center align a Section item in a Form

I am trying to center align an array of views inside a section, however all I get is leading alignment. I tried using VStack instead of HStack, and using .frame(width: ..., alignment: .center) but these don't work for me. If I substitute the ScrollView with a Text then that works. I'm using Xcode 12.3 and iOS 14.3.
struct TestSectionAlign : View {
var body : some View {
Form {
Section(header: Text("background color")) {
viewForBackgroundColor
}
}
}
var viewForBackgroundColor : some View {
HStack {
Spacer()
ScrollView.init(.horizontal, showsIndicators: false) {
HStack {
Spacer()
ForEach(0..<15) { i in
Button(action: {
// do something
}) {
Image(systemName: "circle.fill").foregroundColor(Color.init(white: Double(i)/16.0))
}
.buttonStyle(PlainButtonStyle())
}
Spacer()
}
}
Spacer()
}
}
}
Here is a solution using GeometryReader, then setting manually width of the HStack and aligning it center
struct ContentView : View {
var body : some View {
Form {
Section(header: Text("background color")) {
viewForBackgroundColor
}
}
}
var viewForBackgroundColor : some View {
GeometryReader { geometry in
HStack(alignment: .center) {
ScrollView.init(.horizontal, showsIndicators: false) {
HStack(alignment: .center) {
ForEach(0..<15) { i in
Button(action: {
// do something
}) {
Image(systemName: "circle.fill").foregroundColor(Color.init(white: Double(i)/16.0))
}
.buttonStyle(PlainButtonStyle())
}
}.frame(width: geometry.size.width, height: geometry.size.height, alignment: .center) //<< here now center
}
}.border(Color.red)
}
}
}

SwiftUI - custom TabBar height based on device

I am trying to set up the height of my custom TabBar based on Device, my code:
struct MyTabBar: View {
#Binding var index: Int
var body: some View {
HStack {
Button(action: {
self.index = 0
}) {
Image(ImageText.iconHome.image)
}
Spacer(minLength: 0)
Button(action: {
self.index = 1
}) {
Image(ImageText.iconBell.image)
}
Spacer(minLength: 0)
Button(action: {
self.index = 2
}) {
Image(ImageText.iconAdd.image)
}
Spacer(minLength: 0)
Button(action: {
self.index = 3
}) {
Image(ImageText.iconSearch.image).foregroundColor(Color.red)
}
Spacer(minLength: 0)
Button(action: {
self.index = 4
}) {
Image(ImageText.iconHamburger.image)
}
}.padding(.horizontal, 26).frame(height: 56)
}
}
If the devices have notch, how can I set my custom TabBar to have higher height? Does SwiftUI have something that can be useful here?
You can use the GeometryReader element to access the safe area insets, and add it as a padding using .safeAreaInsets.bottom (note that the Xcode autocompletion is almost never working on GeometryProxy properties):
var body: some View {
GeometryReader { proxy in
VStack {
// Content goes here
Spacer()
// Custom tab bar
HStack {
Spacer()
Button(action: {}) {
Image(systemName: "house.fill")
.padding()
}
Spacer()
Button(action: {}) {
Image(systemName: "house.fill")
.padding()
}
Spacer()
Button(action: {}) {
Image(systemName: "house.fill")
.padding()
}
Spacer()
Button(action: {}) {
Image(systemName: "house.fill")
.padding()
}
Spacer()
}
.padding(.bottom, proxy.safeAreaInsets.bottom)
.background(Color.red)
}
}.edgesIgnoringSafeArea(.bottom)
}