Home > Software engineering >  How to create a timeline like the iOS calendar app?
How to create a timeline like the iOS calendar app?

Time:09-12

I am fairly new in Swift(UI) and I am just trying to fiddle around and create myself a timeline like in the Calendar iOS app with the hours on the left and a divider per hour plus a red line where the current time is at.

Like this

I've seem to accomplish the first (hour and divider), but I am stuck on drawing the current time and position it correctly based on time and spacing.

Like this

Is anyone able to help me or guide me to the right direction? Thank you in advance!

My current code:

struct ContentView: View {
    let dateFormatter = DateFormatter()
    
    init(){
        dateFormatter.dateFormat = "HH:mm"
    }
    
    var sortedTimeFrom: [Date] = {
        let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())!
        var sortedTime: [Date] = []
        var calender = Calendar(identifier: .iso8601)
        calender.locale = Locale(identifier: "en_US_POSIX")
        let currentHour = calender.component(.hour, from: today)
        
        (0...(24)).forEach {
            guard let newDate = calender.date(byAdding: .hour, value: $0, to: today),
                  calender.component(.hour, from: newDate) <= 23 else {
                return
            }
            //convert date into desired format
            sortedTime.append(newDate)
        }
        return sortedTime
    }()
    
    var body: some View {
        ScrollView(.vertical)
        {
            ForEach(sortedTimeFrom, id: \.self) { date in
                VStack(alignment: .leading){
                    HStack {
                        Spacer()
                        Text(date, formatter: dateFormatter)
                        VStack{
                            Color.gray.frame(height: 1 / UIScreen.main.scale)
                        }
                    }
                }.frame(maxWidth: .infinity, alignment: .leading)
            }
        }
    }
}

CodePudding user response:

You'll have to check every row for when the hour is equal to now, then calculate the offset based on the minutes & height of each row:

struct ContentView: View {
    let dateFormatter = DateFormatter()
    
    init(){
        dateFormatter.dateFormat = "HH:mm"
    }
    
    var sortedTimeFrom: [Date] = {
        let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())!
        var sortedTime: [Date] = []
        var calender = Calendar(identifier: .iso8601)
        calender.locale = Locale(identifier: "en_US_POSIX")
        let currentHour = calender.component(.hour, from: today)
        
        (0...(24)).forEach {
            guard let newDate = calender.date(byAdding: .hour, value: $0, to: today),
                  calender.component(.hour, from: newDate) <= 23 else {
                return
            }
            //convert date into desired format
            sortedTime.append(newDate)
        }
        return sortedTime
    }()
    var currentDate: (Int, Double) {
        let calendar = Calendar(identifier: .iso8601)
        let hour = calendar.component(.hour, from: Date())
        let minutes: Double = Double(calendar.component(.month, from: Date()))/60
        return (hour, minutes)
    }
    var body: some View {
        ScrollView(.vertical) {
            VStack(spacing: 0) {
                ForEach(sortedTimeFrom, id: \.self) { date in
                    VStack(alignment: .leading){
                        HStack {
                            Spacer()
                            Text(date, formatter: dateFormatter)
                            VStack{
                                Color.gray.frame(height: 1 / UIScreen.main.scale)
                            }
                        }
                    }.frame(maxWidth: .infinity, alignment: .leading)
                        .frame(height: 30)
                        .overlay(
                            VStack {
                                if Calendar(identifier: .iso8601).component(.hour, from: date) == currentDate.0 {
                                    HStack {
                                        Spacer()
                                        Text(Date(), formatter: dateFormatter)
                                            .foregroundColor(.red)
                                            Color.red
                                                .frame(height: 1 / UIScreen.main.scale)
                                    }.offset(y: 30 * currentDate.1)
                                }
                            }
                        )
                }
            }
        }
    }
}
  • Related