swiftswiftuiswiftui-list

How to dynamic generate a view when a list item got clicked


I have a list to represent a list of dates

enter image description here

It displays like in the upper side of screenshot

I'm wondering how can I click the another date in the list and generate a dynamic view based on new date

my current code to generate all dates

func generateDateListView() -> some View{
        return ScrollView(.horizontal, showsIndicators: false){
            HStack(spacing: 6){
                ForEach(1...7, id:\.self){ index in
                    if index == 2{
                        singlePickedDate(isSelected: true)
                    }
                    else{
                        singlePickedDate(isSelected: false)
                    }
                }
            }
        }
    }
    

I tried to do that with NavigationLink but it's not something I wanted, I dont want to route it to another new page. Instead, I want to stay in same page, but changed the new clicked date with clicked view(the white circle thingy) and generate the new content.

I think I may know how to generate the new content, but I just not sure how to select an item in the list


Solution

  • import SwiftUI
    
    struct CalendarView: View {
        // Get current date information
        let calendar = Calendar.current
        let currentDate = Date()
    
        // Define date formatter to display month
        let dateFormatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "MMMM" // Display full month name
            return formatter
        }()
    
        // Calculate current week days
        var currentWeek: [Date] {
            let startOfWeek = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: currentDate))!
            return (0..<7).compactMap { calendar.date(byAdding: .day, value: $0, to: startOfWeek) }
        }
    
        var body: some View {
            VStack {
                // Display the current month name
                HStack {
                    Text(dateFormatter.string(from: currentDate))
                        .font(.title)
                        .bold()
                    Spacer()
    
                    // Calendar icon (you can use SF Symbols here)
                    Image(systemName: "calendar")
                        .font(.title)
                }
                .padding()
                .background(Color.yellow)
    
                // Display the days of the week
                HStack(spacing: 10) {
                    ForEach(currentWeek, id: \.self) { date in
                        DayView(date: date, isToday: calendar.isDate(date, inSameDayAs: currentDate))
                            .frame(maxWidth: .infinity) // Ensure each day takes equal space
                    }
                }
                .padding()
                .background(Color.yellow)
            }
        }
    }
    
    // View for each day
    struct DayView: View {
        let date: Date
        let isToday: Bool
        let calendar = Calendar.current
    
        // Date formatter to extract the day name and number
        let dayFormatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "E" // Day of the week as abbreviation
            return formatter
        }()
    
        let numberFormatter: DateFormatter = {
            let formatter = DateFormatter()
            formatter.dateFormat = "d" // Day number
            return formatter
        }()
    
        var body: some View {
            VStack(spacing: 4) {
                // Day of the week (e.g., Mon)
                Text(dayFormatter.string(from: date))
                    .bold()
                    .foregroundColor(.black)
                    .lineLimit(1) // Ensure day name stays in one line
                    .minimumScaleFactor(0.5) // Allow text to scale if needed to fit
    
                // Day number (e.g., 1)
                Text(numberFormatter.string(from: date))
                    .bold()
                    .foregroundColor(.black)
                    .padding(.top, 10)
    
                // Current day has a white circle around it
                if isToday {
                    Circle()
                        .fill(Color.white)
                        .frame(width: 35, height: 35)
                        .overlay(
                            Text(numberFormatter.string(from: date))
                                .bold()
                                .foregroundColor(.black)
                        )
                        .padding(.top, -30)
                }
            }
            .padding(7)
            .background(isToday ? Color.black.opacity(0.3) : Color.clear) // Highlight current day with opaque background
            .cornerRadius(100)
        }
    }
    
    struct ContentView: View {
        var body: some View {
            CalendarView()
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            Group {
                ContentView()
                    .previewDevice("iPhone 14")
                ContentView()
                    .previewDevice("iPhone SE (3rd generation)")
                    .previewInterfaceOrientation(.landscapeLeft)
            }
        }
    }