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.75k stars 224 forks source link

Any plans to support this library on SwiftUI? #38

Open sethi-ishmeet opened 3 years ago

bryankeller commented 3 years ago

Hi @sethi-ishmeet - this is something that's definitely on our radar. My understanding is that support could be added by wrapping it with UIViewRepresentable. I'll be exploring this in the coming weeks!

aakrem commented 3 years ago

Hi @bryankeller I've tried wrapping it into a UIViewRepresentable without any success.. Any updates on how we can make this library working with swiftui ?

PwBwolf commented 3 years ago

This worked for me

import SwiftUI
import HorizonCalendar

struct HorrizonView: UIViewRepresentable {

func makeUIView(context: Context) -> CalendarView {
    let calendarView = CalendarView(initialContent: makeContent())
    return calendarView
}

func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<HorrizonView>) {}

private func makeContent() -> CalendarViewContent {
    let calendar = Calendar(identifier: .gregorian)
    let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
    let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!
    return CalendarViewContent(
      calendar: calendar,
      visibleDateRange: startDate...endDate,
      monthsLayout: .vertical(options: VerticalMonthsLayoutOptions()))
}

}

Make sure you call struct in the swiftUI view you wish to display it.

 struct DatePickerView: View {
@State private var beginingDate = Date()
@State private var endDate = Date()
var body: some View {
    VStack {
        HStack {
            Text(beginingDate, style: .date)
            Image("arrpwshape.zigzag.right.fill")
            Text(endDate, style: .date)
        }
        HorrizonView()

        Button("Save", action: {
            print("Saving dates")
            print($beginingDate)
        })
    }
}
Screen Shot 2020-10-27 at 8 59 20 PM

}

bryankeller commented 3 years ago

@sethi-ishmeet @PwBwolf if you're still actively using this, a pull request to add this SwiftUI support is welcome since it sounds like you've figured out how to do it 🙂 !

fluffy919 commented 3 years ago

Hi, I have an issue with final class DayRangeIndicatorView: UIView { .. init(indicatorColor: UIColor) { self.indicatorColor = indicatorColor supre.init(frame: frame) // 'self' used in property access 'frame' before 'super.init' call backgroundColor = .clear } }

I write the error message as a comment. Why is this happening?[

Screen Shot 2021-06-08 at 9 53 08 PM (1)

](url)

viktoriakryvosheevaa commented 2 years ago

Hi, I have an issue with final class DayRangeIndicatorView: UIView { .. init(indicatorColor: UIColor) { self.indicatorColor = indicatorColor supre.init(frame: frame) // 'self' used in property access 'frame' before 'super.init' call backgroundColor = .clear } }

I write the error message as a comment. Why is this happening? Screen Shot 2021-06-08 at 9 53 08 PM (1)

use super.init(frame: .zero)

vipinsaini0 commented 2 years ago

@sethi-ishmeet @PwBwolf if you're still actively using this, a pull request to add this SwiftUI support is welcome since it sounds like you've figured out how to do it 🙂 !

Please add SwiftUI support in it.

YaseenMallick25 commented 2 years ago

This worked for me

import SwiftUI
import HorizonCalendar

struct HorrizonView: UIViewRepresentable {

func makeUIView(context: Context) -> CalendarView {
    let calendarView = CalendarView(initialContent: makeContent())
    return calendarView
}

func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<HorrizonView>) {}

private func makeContent() -> CalendarViewContent {
    let calendar = Calendar(identifier: .gregorian)
    let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
    let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!
    return CalendarViewContent(
      calendar: calendar,
      visibleDateRange: startDate...endDate,
      monthsLayout: .vertical(options: VerticalMonthsLayoutOptions()))
}

}

Make sure you call struct in the swiftUI view you wish to display it.

 struct DatePickerView: View {
@State private var beginingDate = Date()
@State private var endDate = Date()
var body: some View {
    VStack {
        HStack {
            Text(beginingDate, style: .date)
            Image("arrpwshape.zigzag.right.fill")
            Text(endDate, style: .date)
        }
        HorrizonView()

        Button("Save", action: {
            print("Saving dates")
            print($beginingDate)
        })
    }
}
Screen Shot 2020-10-27 at 8 59 20 PM

}

How can I make the month like January,2020 instead of 2020 M01 Screen Shot 2021-09-14 at 2 40 41 AM

bryankeller commented 2 years ago

@YaseenMallick25 your calendar instance doesn't have a locale set. Try using Calendar.current, or add a locale to let calendar = Calendar(identifier: .gregorian).

YaseenMallick25 commented 2 years ago

@PwBwolf I used this but still not working . import SwiftUI import HorizonCalendar

struct CalendarViewController: UIViewRepresentable {

func makeUIView(context: Context) -> CalendarView { let calendarView = CalendarView(initialContent: makeContent()) return calendarView }

func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext) {}

private func makeContent() -> CalendarViewContent { let calendar = Calendar(identifier: .gregorian) let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))! let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))! return CalendarViewContent( calendar: calendar, visibleDateRange: startDate...endDate, monthsLayout: .vertical(options: VerticalMonthsLayoutOptions())) }

}

struct CalendarView_Previews: PreviewProvider { static var previews: some View { CalendarViewController() .preferredColorScheme(.dark) } }

YaseenMallick25 commented 2 years ago

calendar.locale = Locale(identifier: "en_us") or calendar.locale = Locale.current adding this fixes the problem.

davidfitz314 commented 2 years ago

Just wanted to let anyone know who is looking, inorder to use closures like the daySelectionHandler you need to pass the closure into the UIRepresentable and set it up in the makeUIView() function afterwords dont forget to update your calendar in the updateUIView() function

var selectedDay: Day?
    var onSelect: (Day?) -> Void
    func makeUIView(context: Context) -> CalendarView {
        let calendarView = CalendarView(initialContent: self.makeContent())
        calendarView.daySelectionHandler = onSelect
        return calendarView
    }

    func updateUIView(_ uiView: CalendarView, context: UIViewRepresentableContext<CalendarDisplayView>) {
        uiView.setContent(self.makeContent())
    }

    private func makeContent() -> CalendarViewContent {
        let calendar = Calendar.current
        let selectedDay = self.selectedDay
        var dateComponent = DateComponents()

        dateComponent.year = 1
        let futureDate = Calendar.current.date(byAdding: dateComponent, to: self.startDate)!
        return CalendarViewContent(
            calendar: calendar,
            visibleDateRange: self.startDate...futureDate,
            monthsLayout: .horizontal(options: HorizontalMonthsLayoutOptions()))
            .withDayItemModelProvider { day in
                var invariantViewProperties = DayLabel.InvariantViewProperties(
                    font: UIFont.systemFont(ofSize: 18),
                    textColor: .darkGray,
                    backgroundColor: .clear)

                if day == selectedDay {
                    invariantViewProperties.textColor = .white
                    invariantViewProperties.backgroundColor = .blue
                    print("selected")
                }

                return CalendarItemModel<DayLabel>(
                    invariantViewProperties: invariantViewProperties,
                    viewModel: .init(day: day))
            }
    }
AntonVoropaiev commented 1 year ago

What is a DayLable here? with InvariantViewProperties?

davidfitz314 commented 1 year ago

What is a DayLable here? with InvariantViewProperties?

DayLable and InvariantViewProperties are the UI of the calendar library for each day of said calendar. InvariantViewProperties allow you to set textColor, backgroundColor and other properties. In my project I used it to modify selected days from their default coloring to an orange color, and for how to decide the selected days I have a date range picker that the client uses and then the calendar reflects it using the new colors.

AntonVoropaiev commented 1 year ago

What is a DayLable here? with InvariantViewProperties?

DayLable and InvariantViewProperties are the UI of the calendar library for each day of said calendar. InvariantViewProperties allow you to set textColor, backgroundColor and other properties. In my project I used it to modify selected days from their default coloring to an orange color, and for how to decide the selected days I have a date range picker that the client uses and then the calendar reflects it using the new colors.

Thanks! If I got you right i can specify DayLabel by myself for a particular day? and it is not a Horizon Calendar library type.

davidfitz314 commented 1 year ago

What is a DayLable here? with InvariantViewProperties?

DayLable and InvariantViewProperties are the UI of the calendar library for each day of said calendar. InvariantViewProperties allow you to set textColor, backgroundColor and other properties. In my project I used it to modify selected days from their default coloring to an orange color, and for how to decide the selected days I have a date range picker that the client uses and then the calendar reflects it using the new colors.

Thanks! If I got you right i can specify DayLabel by myself for a particular day? and it is not a Horizon Calendar library type.

Ah sorry about the misunderstanding, it is a Horizon Calender Type not a built in native library calendar type.

AntonVoropaiev commented 1 year ago

Thank you so much!

davidfitz314 commented 1 year ago

Thank you so much!

No problem, After instantiating the Horizon Calendar, I believe if your using XCode you should be able to cmd click on the Horizon Calendar Day Label or Invariant View Properties to see more of the declared params. Sometimes that's an easier method then looking through the doc online.