Swiftui searchable list with a datepicker?

Viewed 40

I have a List which is searchable. Is is possible to make the search with a datepicker UI?

NavigationView {
    List {
        ForEach (articles) { article in
            ArticleRow(article: article)
        }
    }
    Text("Content")
    .navigationTitle("Articles")
 
}
.searchable(text: $searchText)
2 Answers

Your code is more or less generic. So you would need to adapt this solution to fit your code. But it should give you an idea on how to do this.

//struct used for this example
struct Article: Identifiable{
    let id = UUID()
    var date: Date
}

struct TestView: View{
    //holds the unfiltered array
    let articles: [Article]
    @State private var selectedDate: Date = Date()
    //filtered array
    @State private var sorted: [Article] = []
    
    var body: some View{
        NavigationView {
            List {
                //iterate over the sorted array
                ForEach (sorted) { article in
//                    ArticleRow(article: article)
                    Text(article.date, format: .dateTime)
                }
            }
            Text("Content")
            .navigationTitle("Articles")
         
        }
        //remove the searchable modifier
//        .searchable(text: $searchText)
        // react to changes of the selected Date
        .onChange(of: selectedDate) { newValue in
            //filter the array
            // I filtered only for the day itself ignoring time
            self.sorted = articles.filter{ Calendar.current.compare($0.date, to: selectedDate, toGranularity: .day) == .orderedSame}
        }.onAppear{
            //assign the initial array
            sorted = articles
        }
        //DatePicker to select the date
        DatePicker("Select Date", selection: $selectedDate)
    }
}

Here is the code I implemented to search using the DatePicker. It uses the Calendar.current.compare function as implemented by @burnsi. I also added a reset button to reset the filter and get access to the complete list of books.

import SwiftUI

extension Date {
    
    static func from(year: Int, month: Int, day: Int) -> Date {
        let calendar = Calendar.current
        var dateComponents = DateComponents()
        dateComponents.year = year
        dateComponents.month = month
        dateComponents.day = day
        return calendar.date(from: dateComponents) ?? Date()
    }
    
}


struct Book: Identifiable {
    let id = UUID()
    let title: String
    let datePublished: Date
}

struct ContentView: View {
    
    @State private var selectedDate: Date = Date()
    @State private var reset: Bool = false
    
    @State private var books = [
        Book(title: "Introduction to JavaScript", datePublished: Date.from(year: 2022, month: 09, day: 10)),
        Book(title: "Mastering Swift", datePublished: Date.from(year: 2022, month: 09, day: 11)),
        Book(title: "Beginning SQL", datePublished: Date.from(year: 2022, month: 09, day: 12)),
        Book(title: "Professional Git", datePublished: Date.from(year: 2022, month: 09, day: 11)),
    ]
    
    @State private var filteredBooks: [Book] = []
    
    var body: some View {
        VStack(alignment: .leading) {
            
            DatePicker("Search by date", selection: $selectedDate, displayedComponents: .date)
            Button("Reset") {
                reset = true
            }
            
            Spacer()
            
            if filteredBooks.isEmpty && !reset  {
                Text("No books found.")
            } else {
                List(reset ? books: filteredBooks) { book in
                    VStack(alignment: .leading) {
                        Text(book.title)
                        Text(book.datePublished, style: .date)
                    }
                }
            }
            
            Spacer()
            
        }.onChange(of: selectedDate) { value in
            reset = false
            // filter out the books
            filteredBooks = books.filter { Calendar.current.compare($0.datePublished, to: selectedDate, toGranularity: .day) == .orderedSame }
            
        }
        .onAppear {
            filteredBooks = books
        }
        .padding()
    }
}
Related