Show Datepicker Hourandminute on Print Statement Swiftui

Show DatePicker hourAndMinute on print statement SwiftUI

Use DateFormatter, for example something like:

var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
return formatter
}

Section(header: Text("Notifications will be triggered only between \(dateFormatter.string(from: startDay)) and \(dateFormatter.string(from: endDay))")) {
DatePicker("Start day", selection: $startDay, displayedComponents: .hourAndMinute)
DatePicker("End day", selection: $endDay, displayedComponents: .hourAndMinute)
}

Picker with hours and minutes SwiftUI

DatePicker only does date. You will have to make 2 custom pickers side by side, eg:

@State var hours: Int = 0
@State var minutes: Int = 0

var body: some View {
HStack {
Picker("", selection: $hours){
ForEach(0..<4, id: \.self) { i in
Text("\(i) hours").tag(i)
}
}.pickerStyle(WheelPickerStyle())
Picker("", selection: $minutes){
ForEach(0..<60, id: \.self) { i in
Text("\(i) min").tag(i)
}
}.pickerStyle(WheelPickerStyle())
}.padding(.horizontal)
}

How do I get the total time in hours and minutes from an selected start time to a selected end time?

I think you really want to use a date formatter and a time interval. See the comments in the code, but you are trying to hard to make a variable have what you want to display. You can simply cause the display itself to format it the way you want. All you need to save is the actual time interval.

struct DateDifferences: View {

@State private var startTime = Date()
@State private var endTime = Date()
var totalTime: TimeInterval {
// This provides a time interval (difference between 2 dates in seconds as a Double
endTime.timeIntervalSince(startTime)
}

// The DateComponentsFormatter handles how that time interval is displayed
var dateFormatter: DateComponentsFormatter {
let df = DateComponentsFormatter()
// Limits the display to hours and mintues
df.allowedUnits = [.hour, .minute]
// Adds short units to hour and minutes as hr & min
df.unitsStyle = .short
return df
}

var body: some View {

Form {
DatePicker("Start Time", selection: $startTime, displayedComponents: .hourAndMinute)
DatePicker("End Time", selection: $endTime, displayedComponents: .hourAndMinute)
Text("Total: \(totalTime)")
Text(dateFormatter.string(from: totalTime) ?? "")
}
}
}

Detect when user taps out of or saves on DatePicker

You could try rolling your own DatePickerView, such as this approach:

struct ContentView: View {
@State private var birthdate = Date()

var body: some View {
DatePickerView(date: $birthdate)
}
}

struct DatePickerView: View {
@Binding var date: Date
@State var hasChanged = false

var body: some View {
ZStack {
Color.white.opacity(0.01).ignoresSafeArea()
.onTapGesture {
if hasChanged {
print("---> do a network call now with: \(date)")
hasChanged = false
}
}
DatePicker("Birth Date", selection: $date, displayedComponents: .hourAndMinute)
.pickerStyle(.wheel)
.onChange(of: date) { val in
hasChanged = true
}
}
}
}

How can I set countDownTimer mode in DatePicker on SwiftUI?

The only way to get the countdown behavior right now is by wrapping UIDatePicker in a custom view.

Here is a simplified version of Ailton Vieira Pinto Filho's code using countDownDuration.

import SwiftUI

struct DurationPicker: UIViewRepresentable {
@Binding var duration: TimeInterval

func makeUIView(context: Context) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer
datePicker.addTarget(context.coordinator, action: #selector(Coordinator.updateDuration), for: .valueChanged)
return datePicker
}

func updateUIView(_ datePicker: UIDatePicker, context: Context) {
datePicker.countDownDuration = duration
}

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

class Coordinator: NSObject {
let parent: DurationPicker

init(_ parent: DurationPicker) {
self.parent = parent
}

@objc func updateDuration(datePicker: UIDatePicker) {
parent.duration = datePicker.countDownDuration
}
}
}

Add Colon (:) between Hour and Minute & Disable default AM/PM in UIDatePicker

I think your best solution is to simply use a normal UIPickerView. This way you can control pretty much everything. As demonstration I created this all-in-code example which should nearly do what you seem to want:

class ViewController: UIViewController {

private let pickerView: UIPickerView = UIPickerView(frame: CGRect(x: 0.0, y: 300.0, width: 100.0, height: 300.0))

override func viewDidLoad() {
super.viewDidLoad()

view.addSubview(pickerView)
pickerView.dataSource = self
pickerView.delegate = self
pickerView.reloadAllComponents()
pickerView.selectRow(50000, inComponent: 0, animated: false)
pickerView.selectRow(50000, inComponent: 1, animated: false)

view.addSubview({
let label = UILabel(frame: .zero)
label.text = ":"
label.sizeToFit()
label.center = pickerView.center
label.isUserInteractionEnabled = false
return label
}())
}

}

extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate {

private func hourValueAtIndex(index: Int) -> Int {
return index%12
}
private func minuteValueAtIndex(index: Int) -> Int {
return index%60
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 100000
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
switch component {
case 0: return String(hourValueAtIndex(index: row))
case 1: return String(minuteValueAtIndex(index: row))
default: return ""
}
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let calendarToUse = Calendar.autoupdatingCurrent
var components = calendarToUse.dateComponents([.year, .month, .day], from: Date())
components.hour = hourValueAtIndex(index: pickerView.selectedRow(inComponent: 0))
components.minute = minuteValueAtIndex(index: pickerView.selectedRow(inComponent: 1))
let selectedDate = calendarToUse.date(from: components)

print("Selected new time (in UTC): \(selectedDate!)")

let formatter = DateFormatter()
formatter.calendar = calendarToUse
formatter.dateStyle = .short
formatter.timeStyle = .short
print("Selected new time (local): \(formatter.string(from: selectedDate!))")
}

}

I would put this all in storyboard or even in xib to have it reusable if needed. The positioning and styling of colon may need some work but this depends on what designs you want. I just used a 100k value for components to mimic infinite scroll. At least some constant should have been defined for that.

Notice hourValueAtIndex and minuteValueAtIndex; those can be manipulated to use pretty much anything you need. To have it 0-23 hours you would simply use index%24. To have it 1-24 would need a bit more work though: You would return index%24 + 1 but when constructing a date you would need to handle the value of 24 as exception. You would use a 0 and add an extra day. But you can not add an extra day directly to components because you can then overflow for situations like 32nd of July. You do need to use add a day at the end:

selectedDate = calendarToUse.date(byAdding: DateComponents(day: 1), to: selectedDate)


Related Topics



Leave a reply



Submit