SwiftUI Week Calendar View. #4: WeekView


Greetings, traveler!

We continue our series about SwiftUI Week Calendar View. This is the fourth part, where we will create the WeekView.

If you just want to check out the complete source code, here it is.

Let’s start with the WeekView. This view will represent seven weekdays. According to our concept, we will generate three tabs with a Week representation. This approach will allow us to create an infinite Week Calendar.

Properties

First, let’s create a WeekView. It will have a property to hold a Week model instance. Another property will represent a selected date value. We must mark this property as Binding to provide data outside and receive it from there.

public struct WeekView: View {
    
    var week: Week
    @Binding var selectedDay: Date
        
    public var body: some View {
       
    }
    
}

Date management

We will use the ForEach View to loop all the Week model’s dates and create a view for them. But before we do this, let’s add some extensions to the Date. You can put them to the same extension we created before or make another one. We should do this to mark weekdays with a specific style.

First, we need to create a function that returns a Bool value to determine whether the chosen date is the same day as our binding selectedDay property.

extension Date {
    
    func isSameDay(with date: Date) -> Bool {
        Calendar.current.compare(self, to: date, toGranularity: .day) == .orderedSame
    }

}

Now, we can create a computed property that will help us determine whether the chosen date is today.

extension Date {
    
    var isToday: Bool {
        isSameDay(with: .now)
    }
    
    func isSameDay(with date: Date) -> Bool {
        Calendar.current.compare(self, to: date, toGranularity: .day) == .orderedSame
    }
    
}

Weekdays

We can create a VStack with the day of the month and a weekday name to display weekdays. We can also use our Date extensions to handle accent color. Then, we can wrap it inside the ForEach View, and we are good to go.

public struct WeekView: View {
    
    var week: Week
    @Binding var selectedDay: Date
        
    public var body: some View {
        HStack {
            ForEach(week.dates, id: \.self) { date in                 
                VStack {
                    Text(date.formatted(.dateTime.weekday()).capitalized)
                        .foregroundColor(.primary)
                        .frame(maxWidth: .infinity)
                        .font(font)
                        .fontWeight(.semibold)
                   
                    Circle()
                        .foregroundColor(date.isSameDay(with: selectedDay) && !date.isToday ? .blue.opacity(0.5) : .clear)
                        .frame(height: circleHeight)
                        .overlay {
                            ZStack {
                                if date.isToday {
                                    Circle()
                                        .foregroundColor(.blue)
                                        .frame(height: 32)
                                }
                                
                                Text(date.formatted(.dateTime.day(.twoDigits)))
                                    .frame(maxWidth: .infinity)
                                    .font(font)
                                    .foregroundColor(date.isToday || date.isSameDay(with: selectedDay) ? .blue : .primary)
                            }
                        }
                }.onTapGesture {
                    selectedDay = date
                }
                .frame(maxWidth: .infinity)
            }
        }
        .padding()
    }
    
}

Conclusion

We are done with the WeekView and ready to create our WeekCalendarView.