airbnb / HorizonCalendar

A declarative, performant, iOS calendar UI component that supports use cases ranging from simple date pickers all the way up to fully-featured calendar apps.
Apache License 2.0
2.77k stars 232 forks source link

tooltips and avoid to select a some dates #227

Open alexisgarciaa opened 1 year ago

alexisgarciaa commented 1 year ago

Hi @bryankeller i am working o a fitness app and , i really love how easy has been to implement the calendar, how ever i am getting some issues now trying to make that some day be unavailable as airbnb app and also make that those day wont select the dates , and also i was able to implement the tooltip option however i would love to implement as airbnb app that show it once is press the date by the way i am using swiftui

command-tab commented 1 year ago

My experience with making days unavailable has required two steps:

  1. Make the day actually un-selectable by returning from the calendarView.daySelectionHandler in makeUIView when an unavailable day has been tapped:

    func makeUIView(context _: Context) -> CalendarView {
        let calendarView = CalendarView(initialContent: makeContent())
        calendarView.daySelectionHandler = { day in
            // Do nothing if the user attempts to select a day before today
            if dayIsBeforeToday(day: day) {
                return
            }
    
            // Also return here if your day is unavailable for some other reason
    
            // Otherwise, add code here to update the selection like usual
        }
        return calendarView
    }
    
    func dayIsBeforeToday(day: Day) -> Bool {
        if let selectedDate = calendar.date(from: day.components) {
            let startOfToday = calendar.startOfDay(for: Date())
            if selectedDate < startOfToday {
                return true
            }
        }
        return false
    }
  2. Make the day appear un-selectable in makeContent by passing a boolean to the SwiftUI day View:

    private func makeContent() -> CalendarViewContent {
        // ...
    
        return CalendarViewContent(
            calendar: calendar,
            visibleDateRange: visibleDateRange,
            monthsLayout: .vertical(options: VerticalMonthsLayoutOptions())
        )
        .dayItemProvider { day in
            var isSelected = false
            // Do a conditional check here that toggles isSelected if your `day` should appear selected
    
            var isEnabled = true
            // Do a conditional check here that toggles isEnabled if your `day` should appear disabled
    
            return YourCustomSwiftUIDayView(
                dayNumber: day.day,
                isSelected: isSelected,
                isEnabled: isEnabled
            ).calendarItemModel
    }
    struct YourCustomSwiftUIDayView: View {
        let dayNumber: Int
        let isSelected: Bool
        let isEnabled: Bool
    
        var body: some View {
            ZStack(alignment: .center) {
                Text("\(dayNumber)")
                    .foregroundColor(isEnabled ? Color(UIColor.label) : .gray)
                if isSelected {
                    Circle()
                        .strokeBorder(Color.accentColor, lineWidth: 1)
                        .background {
                            Circle()
                                .foregroundColor(Color(UIColor(Color.accentColor).withAlphaComponent(0.15)))
                        }
                        .aspectRatio(1, contentMode: .fill)
                }
            }
        }
    }

I'm still fairly new to Swift and SwiftUI, so take this with a grain of salt :)

jonathanhyperion commented 1 year ago

Thank you so much that help me a lot by the way have you ever tried to make a quick selection with a button a show a range of date selected?