Weird gap in LazyVGrid

45 Views Asked by At

I'm not very experienced with LazyVGrid. What is this weird gap between the 1:45 and 2:00 buttons, and how can I get rid of it?

import PlaygroundSupport
import SwiftUI

struct ContentView: View {
  
  let dates: [Date] = (0...34).compactMap { interval -> Date? in
    var components = Calendar.current.dateComponents([.day, .month, .year], from: Date())
    components.hour = 7
    components.minute = 30
    
    guard var date = Calendar.current.date(from: components) else { return nil }
    
    date.addTimeInterval(Double(900 * interval))
    
    if Calendar.current.component(.hour, from: date) == 12 {
      date.addTimeInterval(3600)
    }
    
    return date
  }
  
  func text(for date: Date) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "h:mm a"
    return formatter.string(from: date)
  }
  
  var body: some View {
    LazyVGrid(columns: Array(repeating: GridItem.init(.flexible(), spacing: nil, alignment: nil), count: 3)) {
      ForEach(dates, id: \.self) { date in
        Button {
          
        } label: {
          Capsule()
            .overlay {
              Text(text(for: date))
                .foregroundStyle(.white)
            }
            .foregroundColor(.blue)
            .frame(height: 44)
        }
      }
    }.padding()
  }
}

PlaygroundPage.current.setLiveView(ContentView().frame(width: 400, height: 800).padding())

enter image description here

2

There are 2 best solutions below

0
HangarRash On BEST ANSWER

The problem is that your logic for skipping the 12 o'clock hour time slots is resulting in 4 duplicate dates. You need a collection with only unique values.

In the dates property initializer, replace the line:

date.addTimeInterval(3600)

with:

return nil

This will eliminate the 4 12 o'clock time slots and avoid any duplicate dates which in turn removes the gap in the grid.

2
workingdog support Ukraine On

The reason you have these gaps is because you have multiple dates the same. The ForEach loop requires unique items for it to work.

One way to avoid this is to create a unique object for each date, such as shown in the example code:

// --- here
struct DateItem: Identifiable {
    let id = UUID()
    var date: Date
}

struct ContentView: View {
    
    // --- here
    let dates: [DateItem] = (0...34).compactMap { interval -> DateItem? in
        var components = Calendar.current.dateComponents([.day, .month, .year], from: Date())
        components.hour = 7
        components.minute = 30
        
        guard var date = Calendar.current.date(from: components) else { return nil }
        
        date.addTimeInterval(Double(900 * interval))
        
        if Calendar.current.component(.hour, from: date) == 12 {
            date.addTimeInterval(3600)
        }
        
        return DateItem(date: date) // <--- here
    }
    
    func text(for date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "h:mm a"
        return formatter.string(from: date)
    }
    
    var body: some View {
        LazyVGrid(columns: Array(repeating: GridItem.init(.flexible(), spacing: nil, alignment: nil), count: 3)) {
            ForEach(dates) { date in  // <--- here
                Button {
                    // ...
                } label: {
                    Capsule()
                        .overlay {
                            Text(text(for: date.date))  // <--- here
                                .foregroundStyle(.white)
                        }
                        .foregroundColor(.blue)
                        .frame(height: 44)
                }
            }
        }.padding()
    }
}