Wednesday, October 19, 2022
HomeWeb DevelopmentWorking with calendars in Swift

Working with calendars in Swift


If in case you have labored with any sort of type in a cell utility, then you know the way sophisticated it’s to deal with dates in kinds. On this article, we’ll learn to implement a calendar for dealing with and manipulating dates in a SwiftUI utility.

SwiftUI offers a DatePicker management for selecting an absolute date from customers, nonetheless, as a full-fledged calendar UI, it has some limitations. On this tutorial, we’ll additionally use a well-liked calendar library referred to as FSCalendar, a totally customizable calendar library for iOS. Our last app will appear like the pictures under:

Final Swift UI Calendar Application

Swift UI Calendar Application Final

You will discover the entire code for this tutorial on this GitHub repository. Let’s get began!

Desk of contents

We’ll cowl the next:

Create a SwiftUI undertaking

Earlier than writing any code, we’ll want a working SwiftUI utility. Let’s create it now; open Xcode, and also you’ll see a display studying Welcome to Xcode, as proven under:

Welcome Xcode Screen

Choose Create a brand new Xcode undertaking, then Xcode shall be launched with the select undertaking template popup:

Create New Xcode Project

We’ll go away the chosen choice because the default one, App, then click on Subsequent. Enter a reputation to your undertaking and click on Subsequent. Now that we’ve efficiently created a SwiftUI undertaking, let’s run it on our gadget or simulator.

To construct the app on a tool, choose it from the highest bar of Xcode, after which click on the Play button on the left to start out the construct:

Select Device Build App Play Button

If all the pieces labored appropriately, you’ll see a clean display in your gadget with a “Hey, World!” textual content within the middle.

Present a calendar view with DatePicker in SwiftUI

To create a calendar UI in our Swift utility, we’ll begin with DatePicker from SwiftUI. This construction is principally used to pick dates from a consumer interface, and it’s very simple to make use of and management.

Let’s add DatePicker into our view physique. Add the code under to the ContentView.swift file:

import SwiftUI

struct ContentView: View {
    @State var selectedDate: Date = Date()
    var physique: some View {
        // Added DatePicker with choice equal to State variable selectedDate
        DatePicker("Choose Date", choice: $selectedDate)
                  .padding(.horizontal)
    }
}
....

As you will have seen, we added DatePicker with two parameters, Choose Date and choice.

The primary String param is the title of date picker, which is proven beside the picker controls on the UI. The second param, choice, is a vital parameter that takes a Binding variable of sort Date. The Date variable modifications as the chosen date or time is modified from the DatePicker management.

To cross the Binding into the choice param, we’ve created a State variable named selectedDate of sort Date, and its preliminary worth is the present date. We additionally added somewhat horizontal padding to the part.

The UI output from the code above shall be just like the picture under:

Adding Datepicker Show Calender View UI

Now, we will open a calendar view to pick a date and time from a wheel picker, which are saved within the selectedDate variable. Now, let’s show it on the UI.

Change the code within the ContentView physique with the code under:

VStack(alignment: .middle, spacing: 0) {
    Textual content(selectedDate.formatted(date: .abbreviated, time: .normal))
        .font(.system(dimension: 28))
        .daring()
        .foregroundColor(Coloration.accentColor)
        .padding()
        .animation(.spring(), worth: selectedDate)
    Divider()
    Spacer()
    DatePicker("Choose Date", choice: $selectedDate)
        .padding(.horizontal)
}
.padding(.vertical, 200)

The code above will produce the next UI:

Open Calendar View Select Date Time Wheel Picker

We’ve applied a date picker into our utility, however we aren’t completed but. We wish to present a calendar view in our UI that can at all times be displayed. For this, we’ll use the datePickerStyle modifier of the DatePicker part. We will use this modifier to show DatePicker in any predefined kinds we would like.

We’ll use graphical type, which exhibits the DatePicker as a CalendarView that’s at all times opened. We gained’t want the time part now, so we’ll cross displayedComponents in our DatePicker initializer. We’ve additionally omitted the time half from selectedDate when displaying it on the UI.

With the modifications above, the up to date code within the physique of our ContentView will appear like the next:

VStack() {
    Textual content(selectedDate.formatted(date: .abbreviated, time: .omitted))
        .font(.system(dimension: 28))
        .daring()
        .foregroundColor(Coloration.accentColor)
        .padding()
        .animation(.spring(), worth: selectedDate)
        .body(width: 500)
    Divider().body(peak: 1)
    DatePicker("Choose Date", choice: $selectedDate, displayedComponents: [.date])
        .padding(.horizontal)
        .datePickerStyle(.graphical)
    Divider()
}
.padding(.vertical, 100)

The code above will consequence within the UI under:

Datepickerstyle Modifier Datepicker Component

Including TabView into utility

To date, we’ve built-in a calendar-like view utilizing DatePicker. However we will enhance on this through the use of a well-liked iOS library referred to as FSCalendar.

However first, we have to separate these two screens in our app UI. For this, we’ll use TabView, which can create two tabs in our app, one for CalendarView with DatePicker, and one other for FSCalendar.

Let’s begin by shifting the UI that we created within the part above into one other SwiftUI file. Create a brand new SwiftUI file in Xcode and name it DatePickerCalendar. Paste the code from the physique of ContentView into the physique of DatePickerCalendar:

import SwiftUI

struct DatePickerCalendar: View {
    @State var selectedDate = Date()
    var physique: some View {
        VStack {
            FormattedDate(selectedDate: selectedDate, omitTime: true)
            Divider().body(peak: 1)
            DatePicker("Choose Date", choice: $selectedDate,
                       in: ...Date(), displayedComponents: .date)
                .datePickerStyle(.graphical)
            Divider()
        }
    }
}

struct DatePickerCalendar_Previews: PreviewProvider {
    static var previews: some View {
        DatePickerCalendar()
    }
}

Within the code above, you’ll discover that we’ve applied two modifications. For one, we’ve added the in parameter within the DatePicker initializer, which permits the consumer to select dates in a given vary. On this case, I’ve supplied all dates from the earlier to the present date.

FormattedDate is a helper view that I created to make the code look clear. It’s principally the identical Textual content part that we used beforehand to show selectedDate on the UI with some type modifiers.

To create the FormattedDate view, create a brand new SwiftUI file, identify it FormattedDate, and add the next code inside it:

import SwiftUI

struct FormattedDate: View {
    var selectedDate: Date
    var omitTime: Bool = false
    var physique: some View {
        Textual content(selectedDate.formatted(date: .abbreviated, time: 
              omitTime ? .omitted : .normal))
            .font(.system(dimension: 28))
            .daring()
            .foregroundColor(Coloration.accentColor)
            .padding()
            .animation(.spring(), worth: selectedDate)
            .body(width: 500)
    }
}

struct FormattedDate_Previews: PreviewProvider {
    static var previews: some View {
        FormattedDate(selectedDate: Date())
    }
}

We additionally have to create a brand new file for our calendar view that can implement the FSCalendar library. Create a brand new SwiftUI file named CalendarView and add the next code inside physique:

Textual content("That is Calendar View")

Now, let’s add the TabView in our ContentView file:

TabView {
    DatePickerCalendar()
      .tabItem {
        Label("DatePicker Calendar", systemImage: "calendar.badge.plus")
            .padding()
      }
    CalendarView()
      .tabItem {
        Label("Fullscreen Calendar", systemImage: "calendar")
            .padding()
      }
}
.onAppear {
    let look = UITabBarAppearance()
    look.backgroundColor = UIColor(Coloration.purple.opacity(0.2))
    look.shadowColor = UIColor(.purple)
    look.backgroundEffect = UIBlurEffect(type: .extraLight)
    UITabBar.look().standardAppearance = look
    UITabBar.look().scrollEdgeAppearance = look
}

Within the code above, we now have added two views in our TabView. First is the DatePickerCalendar, which we created earlier, and the second is the empty CalendarView. Every view has a tabItem modifier that defines what to show contained in the tab bar. We’ve additionally added an onAppear occasion methodology on TabView to alter the looks of TabView.

Now, we’ll have the UI under:

Add Views Tab View

Putting in FSCalendar into our undertaking

Now, let’s set up the FSCalendar library. So as to add a brand new library, in Xcode, go to File Add Packages, as seen within the picture under:

Install FS Calender Add Package

Click on on the Add (+) button, then click on on Add swift package deal assortment:

Xcode Add Package File UI

Add Swift Package Collection

Then, paste the next hyperlink into the enter and proceed:

https://github.com/WenchaoD/FSCalendar

That is the repository URL of the package deal we’ll use:

Repository Github URL Fscalendar

That’s it! You’ve now added FSCalendar into you undertaking. If all the pieces went proper, you’ll now see FSCalendar in Package deal Dependencies on the left aspect of Xcode in undertaking navigator menu:

Added Fscalendar Xcode

Combine UIKit view from FSCalendar with UIViewRepresentable

Now, we’ve put in FSCalendar, however we can’t straight make the most of the library as it’s because it doesn’t help SwiftUI out of the field. Subsequently, we’ll have to make the most of the UIKit view offered by this library.

For this, we’ll use UIViewRepresentable as a wrapper across the UIKit view to show it in our SwiftUI view hierarchy. For extra details about this, you can even seek advice from the official documentation.

First, we’ll create a view in the identical file, which returns UIViewRepresentable. Then, we’ll implement some methodology inside it, which can create a UIView and can permit us to speak with it:

import UIKit
import FSCalendar
....

struct CalendarView: View {
    var physique: some View {
      CalendarViewRepresentable(selectedDate: $selectedDate)
    }
}

struct CalendarViewRepresentable: UIViewRepresentable {
    typealias UIViewType = FSCalendar

    func makeUIView(context: Context) -> FSCalendar {
      return FSCalendar()
    }

    func updateUIView(_ uiView: FSCalendar, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, 
          FSCalendarDelegate, FSCalendarDataSource {
            var mother or father: CalendarViewRepresentable

            init(_ mother or father: CalendarViewRepresentable) {
                self.mother or father = mother or father
            }
    }
}

Within the code above, we’ve applied three strategies and one class:

  • makeUIView: Creates the UIView that shall be rendered on the UI. For now, we straight return an occasion of FSCalendar, which we’ll change as we transfer ahead to present us extra management over the calendar
  • updateUIView: Used to replace state of the view. We gained’t want this for this tutorial.
  • makeCoordinator: Used to create a customized occasion that we will use to speak between SwiftUI and UIKit views
  • Coordinator: The customized occasion that’s returned from makeCoordinator

Utilizing the code above, we now have an FSCalendar view in our utility, which can appear like the picture under by default:

Add Fscalendar View Swift Application

Displaying a calendar view with FSCalendar

We’ve efficiently rendered a calendar view in our app UI. Now, let’s set the date worth chosen by the consumer on the calendar. To take action, we’ll create a calendar variable inside our CalendarViewRepresentable and customise it because the consumer performs interactions on the UI:

struct CalendarView: View {
  // Added a @State var to trace the chosen date by consumer
  @State var selectedDate: Date = Date()

  var physique: some View {
        VStack {
            // Displaying the chosen date
            FormattedDate(selectedDate: selectedDate, omitTime: true)
            // Passing the selectedDate as Binding
            CalendarViewRepresentable(selectedDate: $selectedDate)
        }
  }
}

struct CalendarViewRepresentable: UIViewRepresentable {
  ...
  // Making a object of FSCalendar to trace throughout the view
  fileprivate var calendar = FSCalendar()

  // Getting selectedDate as a Binding in order that we will replace it as 
  // consumer modifications their choice 
  @Binding var selectedDate: Date

  func makeUIView(context: Context) -> FSCalendar {
          // Setting delegate and dateSource of calendar to the
          // values we get from Coordinator
          calendar.delegate = context.coordinator
          calendar.dataSource = context.coordinator
          // returning the intialized calendar
          return calendar
  }

  ....


    class Coordinator: NSObject, 
                        FSCalendarDelegate, FSCalendarDataSource {
        ....
        // Implementing the didSelect methodology of FSCalendar
        // that is fired with the brand new date when consumer selects a brand new date
        // within the Calendar UI, we're setting our selectedDate Binding
        // var to this new date when that is triggered
        func calendar(_ calendar: FSCalendar, 
                        didSelect date: Date,
                        at monthPosition: FSCalendarMonthPosition) {
            mother or father.selectedDate = date
        }
    }

  ....
}

Now, our calendar UI will appear like the picture under:

Displaying Calender View Fs Calendar

Customizing the calendar UI

Now that we’ve applied a working calendar in our SwiftUI utility, let’s customise the calendar. FSCalendar comes with loads of customizability options. You’ll be able to have a full have a look at them on the GitHub repo.

After including some customized options and kinds to our calendar, the ultimate code in our CalendarView file shall be as follows:

import SwiftUI
import UIKit
import FSCalendar

struct CalendarView: View {

    @State var selectedDate: Date = Date()

    var physique: some View {
              CalendarViewRepresentable(selectedDate: $selectedDate)
                .padding(.backside)
                .padding(EdgeInsets(prime: 40,
                          main: 0, backside: 0, trailing: 0))
                .background{
                    AsyncImage(url: URL(
                                string: "https://photographs.pexels.com/pictures/1939485/pexels-photo-1939485.jpeg")){ img in
                        img.resizable(resizingMode: .stretch)
                            .blur(radius: 4, opaque: true)
                    } placeholder: {
                        LinearGradient(colours: [.red.opacity(0.4),
                                      .green.opacity(0.4)],
                                      startPoint: .prime,
                                      endPoint: .backside)
                    }
                }
                .ignoresSafeArea(.all, edges: .prime)
    }
}

struct CalendarViewRepresentable: UIViewRepresentable {
    typealias UIViewType = FSCalendar

    fileprivate var calendar = FSCalendar()
    @Binding var selectedDate: Date

    func makeUIView(context: Context) -> FSCalendar {
        calendar.delegate = context.coordinator
        calendar.dataSource = context.coordinator

        // Added the under code to alter calendar look
        calendar.look.todayColor = UIColor(displayP3Red: 0,
                                                  inexperienced: 0,
                                                  blue: 0, alpha: 0)
        calendar.look.titleTodayColor = .black
        calendar.look.selectionColor = .orange
        calendar.look.eventDefaultColor = .purple
        calendar.look.titleTodayColor = .blue
        calendar.look.titleFont = .boldSystemFont(ofSize: 24)
        calendar.look.titleWeekendColor = .systemOrange
        calendar.look.headerMinimumDissolvedAlpha = 0.12
        calendar.look.headerTitleFont = .systemFont(
                                                ofSize: 30, 
                                                weight: .black)
        calendar.look.headerTitleColor = .darkGray
        calendar.look.headerDateFormat = "MMMM"
        calendar.scrollDirection = .vertical
        calendar.scope = .month
        calendar.clipsToBounds = false

        return calendar
    }

    func updateUIView(_ uiView: FSCalendar, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, 
          FSCalendarDelegate, FSCalendarDataSource {
        var mother or father: CalendarViewRepresentable

        init(_ mother or father: CalendarViewRepresentable) {
            self.mother or father = mother or father
        }

        func calendar(_ calendar: FSCalendar, 
                      didSelect date: Date,
                      at monthPosition: FSCalendarMonthPosition) {
            mother or father.selectedDate = date
        }

        func calendar(_ calendar: FSCalendar, 
                  imageFor date: Date) -> UIImage? {
            if isWeekend(date: date) {
                return UIImage(systemName: "sparkles")
            }
            return nil
        }

        func calendar(_ calendar: FSCalendar, 
                      numberOfEventsFor date: Date) -> Int {
            let eventDates = [Date(), Date(),
                                Date.now.addingTimeInterval(400000),
                                Date.now.addingTimeInterval(100000),
                                Date.now.addingTimeInterval(-600000),
                                Date.now.addingTimeInterval(-1000000)]
            var eventCount = 0
            eventDates.forEach { eventDate in
                if eventDate.formatted(date: .full, 
                              time: .omitted) == date.formatted(
                                date: .full, time: .omitted){
                    eventCount += 1;
                }
            }
            return eventCount
        }

        func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
            if isWeekend(date: date) {
                return false
            }
            return true
        }

        func maximumDate(for calendar: FSCalendar) -> Date {
            Date.now.addingTimeInterval(86400 * 30)
        }

        func minimumDate(for calendar: FSCalendar) -> Date {
            Date.now.addingTimeInterval(-86400 * 30)
        }
    }
}

func isWeekend(date: Date) -> Bool {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "EEEE"
    let day: String = dateFormatter.string(from: date)
    if day == "Saturday" || day == "Sunday" {
        return true
    }
    return false
}

The code above will give us an output just like the picture under:

Final Calender View Code Custom Features Styles

Conclusion

On this tutorial, we discovered create a CalendarView UI utilizing the DatePicker management. We additionally discovered implement a calendar library to attain our finish UI consequence by incorporating a UIViewRepresentable to render a UIKit view inside a SwiftUI utility.

Thanks for studying!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments