UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Weird gap between Stack and List

Forums > SwiftUI

Good day everyone, I worked on my app today and wondered where this little gap comes from... The ZStack (top) and List (bottom) are marked with a red border, so you can see the gap clearly, where the 2 lines of red should meet, but they don't

https://imgur.com/a/x5msmWr

Code:

import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) var managedObjContext
    @FetchRequest(sortDescriptors: [SortDescriptor(\.date, order: .reverse)]) var money: FetchedResults<Money>

    @State private var showingAddView = false
    @State private var amount = Double()

    var body: some View {
        NavigationView {
            VStack(alignment: .center) {
                ZStack {
                RoundedRectangle(cornerRadius: 25)
                    .padding()
                    .foregroundColor(.white)
                    .background(.ultraThinMaterial)
                    .frame(width: .infinity, height: 250)
                    VStack {
                        Text("Verfügbar")
                            .foregroundColor(.black)
                            .bold()
                            .font(.title)
                        Text("\(totalMoneyToday(), specifier: "%.2f")€")
                            .foregroundColor(.blue)
                            .bold()
                            .font(.title)
                        HStack {
                            Spacer()
                            Label("", systemImage: "arrow.up.circle")
                                .foregroundColor(.green)
                            Text("\(amount, specifier: "%.2f")€")
                            Spacer()
                            Label("", systemImage: "arrow.down.circle")
                                .foregroundColor(.red)
                            Text("\(amount, specifier: "%.2f")€")
                            Spacer()
                        }
                        .padding()
                    }
                }
                .border(Color.red, width: 1)
                List {
                    ForEach(money) { money in
                        NavigationLink(destination: EditMoneyView(money: money)) {
                            HStack {
                                VStack(alignment: .leading, spacing: 6) {
                                    Text(money.name!)
                                        .bold()

                                    Text("\(money.amount, specifier: "%.2f")") + Text("€")
                                }
                                Spacer()
                                Text("\(money.date!, style: .date)")
                                    .foregroundColor(.gray)
                                    .italic()
                            }
                        }
                    }
                    .onDelete(perform: deleteMoney)
                }
                .border(Color.red, width: 1)
                .listStyle(.plain)
            }
            .navigationBarTitle("Financist", displayMode: .inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        showingAddView.toggle()
                    } label: {
                        Label("Hinzufügen", systemImage: "plus.circle")
                    }
                }
            }
            .sheet(isPresented: $showingAddView) {
                AddMoneyView()
            }
        }
    }
    private func deleteMoney(offsets: IndexSet) {
        withAnimation {
            offsets.map { money[$0] }.forEach(managedObjContext.delete)

            DataController().save(context: managedObjContext)
        }
    }

    private func totalMoneyToday() -> Double {
        var moneyToday: Double = 0
        for item in money {
            if Calendar.current.isDateInToday(item.date!) {
                moneyToday += item.amount
            }
        }
        return moneyToday
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Thank you very much!

1      

Marci has a stacking problem and seeks clarification:

The ZStack (top) and List (bottom) are marked with a red border,
so you can see the gap clearly, clearly see the gap.

It's not a bug! It's a feature!

See -> Apple Explains VStack Spacing

Your ZStack and your List of expense items are embedded inside a VStack. Unless you specify a spacing, the VStack will choose a default distance for its subviews.

To fix, you'll probably want something like this code. As we might say in the Tube, Mind the Gap!

import SwiftUI
// Focus on the problem.
// Remove CoreData, expenses, navigation links, etc from your code to focus
// on the VStack gap issue.
struct VStackGapView: View {
    @State private var nilSpacing = true // use nil or 0.0
    var vstackSpacing: CGFloat? { nilSpacing ? nil : 0.0 } // Pick one or the other
    var body: some View {
        NavigationView {
            // from developer documentation:
            // VStack spacing is the distance between adjacent subviews,
            // or nil if you want the stack to choose a default distance for each pair of subviews.
            VStack(alignment: .center, spacing: vstackSpacing) {
                // 1. Visual Element #1: Toggle =====================
                Toggle("VStack spacing: \(nilSpacing ? "nil" : "0.0")", isOn: $nilSpacing)
                    .padding([.leading, .top, .trailing])
                    .border(Color.black, width: 3.0)
                // 2. Visual Element #2: Rectangle and Text ============
                ZStack {
                    Rectangle()
                        .foregroundColor(.indigo.opacity(0.6))
                        .frame(height: 100)
                    Text("Mind the Gap!").font(.largeTitle)
                }
                // 3. Visual Element #3: List of Text views =========
                List { ForEach((42...49), id: \.self) {  Text("Line \($0)") } }
                    .border(Color.black, width: 3.0) // Hint: make this wider and black for clarity
            }
            .navigationTitle("VStack Spacing")
        }
    }
}

struct VStackGap_Previews: PreviewProvider { static var previews: some View { VStackGapView() } }

2      

You didn't ask, but here are my thoughts on ContentView.

ContentView


In decades of coding courses and C+ Programming for Dummies type books, function names were often given the generic name Foo or perhaps Bar. These were nonsense names to help the reader focus on syntax, or on a technique, and not necessarily what the function was designed to do.

When you create a new SwiftUI view, XCode gives the view a nonsense name: ContentView! Why not BoxView? or FooView? Ugh.

@twoStraws and most all other SwiftUI content providers in YouTube land will express the need for descriptive variable names. They'll note how important it is to use camelCase, or to capitalize the names of Structs and Classes. Indeed, when creating other views in a project, they're very careful to give the new views a meaningful name!

Yet, they'll often leave the first view named ContentView.

Here's my personal feedback. As soon as you create a new SwiftUI View, change the name from ContentView to something meaningful in your application.

For example, in your application, the main focus of your application may be the BalanceView or pick a more appropriate name. I picked VStackGapView because that was the focus of your problem.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.