SwiftUI DatePicker Custom Font - swiftui

Is there any straight way, that is not DatePickerStyle, to change the font and weight of a DatePicker
DatePicker("Start date",
selection: Binding(get:{goal.startDate!},set:{goal.startDate = $0}),
displayedComponents: .date
)
.font(.custom("HelveticaNeue-Thin", size: 10, relativeTo: .caption))//<-- do nothing
.labelsHidden()

Related

SwiftUI - Custom DatePicker - Show layer or backgorund on top of all or how to do it as DatePicker

I'm trying two write a custom Datepicker so that I can modify the button style. As far as I know, SwiftUI doesn't allow to modify it. My base design based on this answer that I've already improved it.
struct CustomDatePickerView: View {
#State private var showPicker = false
#State var selectedText: String
#State var selectedDateLocal : Date = Date()
var body: some View {
VStack {
Button {
withAnimation {
showPicker.toggle()
}
} label: {
Text(selectedText)
.padding()
.padding(.horizontal)
.foregroundColor(.black)
.background(
RoundedRectangle( cornerRadius:10, style: .continuous).fill(Color.yellow.opacity(0.2))
)
.overlay(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.strokeBorder(Color.black, lineWidth: 1)
)
.id(selectedText)
}
.background(
DatePicker("", selection: $selectedDateLocal, in: closedRange, displayedComponents: [.date,.hourAndMinute])
.datePickerStyle(.graphical)
.frame(width: 400, height: 400)
.clipped()
.background(Color.yellow.opacity(0.1).cornerRadius(10))
.opacity(showPicker ? 1 : 0 )
.offset(x: 0, y: 230)
).onChange(of: selectedDateLocal) { newValue in
let format = DateFormatter()
format.timeStyle = .none
format.dateStyle = .short
print("Name changed to \(format.string(from: newValue))!")
selectedText = format.string(from: newValue)
withAnimation {
showPicker.toggle()
}
}
}
}
}
It was working excellent on test view (sorry image upload failure).
When it is placed on the real application, the background/overlay was behind of other views.
I cannot change the Z-level since the UI a bit complicated.
How can we show the DatePicker displayed on background/overlay on top of everything as the DatePicker does? What is the proper way to do this?

Tap outside picker text not opening picker menu

I have a Picker like this
Picker ("", selection: $itemIndex){
ForEach (0..<items.count, id: \.self){ index in
Text(items[index])
}
}
.frame(maxWidth: .infinity)
.background(.red)
The issue is that the picker extends to the screen width but the text displaying on the Picker is not that lengthy, maybe about 1/20 of the Picker length
Now when I click on the text, the Picker menu opens up, but when I click outside the text, still within the picker visibility, the menu don't open.
In the image above, when I tap on the red side, the menu opens up, but when I tap on both green sides it doesn't
Do anyone have an idea why this is happening?
Note: the picker is not in a Form or a NavigationController
Okay... So through the help of this question, I was able to customize my own Picker style. Below is the code to achieve this
struct CustomPickerStyle: ViewModifier {
#Binding var index: Int
var items: [String]
var font: SwiftUI.Font
var padding: CGFloat
func body(content: Content) -> some View {
Menu {
content
} label: {
HStack {
if let labelText = items[index] {
Text(labelText)
.font(font)
Spacer()
Image(systemName: "triangle.fill")
.resizable()
.frame(width: 12, height: 8)
.rotationEffect(.degrees(180))
}
}
.padding(padding)
.frame(alignment: .leading)
.background(Colors.white)
}
}
}
extension View {
func customPickerStyle(index: Binding<Int>, items: [String], font: SwiftUI.Font, padding: CGFloat) -> some View {
self.modifier(CustomPickerStyle(index: index, items: items, font: font, padding: padding))
}
}
And I this is how I used it in my UI
Picker("", selection: $itemIndex){
ForEach(0..<items.count, id: \.self){ index in
Text(items[index])
}
}
.customPickerStyle(index: $itemIndex, items: items, font: .system(size: 17), padding: 10)
.frame(width: UIScreen.main.bounds.width - 50)
.overlay(RoundedRectangle(cornerRadius: 10.0).stroke(.blue, lineWidth: 1.0))
And here is the result
I assume you wanted this
Picker ("", selection: $itemIndex){
ForEach (0..<items.count, id: \.self) { index in
Text(items[index])
.frame(maxWidth: .infinity) // << here !!
}
}
.background(.red)
or this if you told about Menu
Menu {
// content here
} label: {
Text("Menu")
.frame(maxWidth: .infinity) // << here !!
}
the general rule is - give space for label which is actually shown, instead of containing control, because hit testing is usually set up by intrinsic content.

SwiftUI: Compact DatePicker with custom design

I need a custom "label" with the behavior of opening the date picker in some kind of popover, even on the iPhone.
When I use the built in DatePicker with compact format, I have the behavior with opening the wheels in a popover, but I cannot customize the look of the "collapsed" version with the gray background (in fact, I can change it to some other color, but not to white e.g., it simply doesn't work).
Another option would be to have a custom Text wrapped inside a Button and then open the DatePicker, but I don't know how to achieve the popover effect on the iPhone. So I guess the first option would be the easier one, but how can I achieve a custom layout for the compact date picker? Nothing super fancy, just something like this:
instead of something like this
its more of a proof of concept, but this might be a way:
import SwiftUI
struct ContentView: View {
#State private var showPicker = true
#State var selectedDate = Date()
Button {
withAnimation {
showPicker.toggle()
}
} label: {
Text(Text(selectedDate.getFormattedDate(format:"HH:mm:")))
.padding()
.padding(.horizontal)
.background(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray)
)
}
.background(
DatePicker("", selection: $selectedDate, displayedComponents: .hourAndMinute)
.datePickerStyle(.wheel)
.frame(width: 200, height: 100)
.clipped()
.background(Color.gray.cornerRadius(10))
.opacity(showPicker ? 1 : 0 )
.offset(x: 50, y: 90)
).onChange(of: selectedDate) { newValue in
withAnimation {
showPicker.toggle()
}
}
}
Note that DidSet or willSet is not possible for Objects, however, we had a nice workaround onChange. When date changed, just toggle, done.

Background of Selected Item in Picker

I have a picker that looks like this:
With the code being this:
#State var typeSelection: String = "Socialism"
var typeOptions = ["Socialism", "Democratic Socialism", "Capitalism", "Authoritarianism"]
...
Picker("Please pick a Type", selection: $typeSelection) {
ForEach(typeOptions, id: \.self) {
Text($0)
.foregroundColor(.white)
.font(.system(size: 30, weight: .medium, design: .default))
}
}
How do I make the background color of the selected one darker, like if say it's opacity is 30% of a black color right now how do I bump that to 70%?

Any date range in DatePicker for SwiftUI

Normally we need a range, for example:
DatePicker(selection: $birthDate, in: ...Date(), displayedComponents: .date)
We can select a date for previous date. How can we create a DatePicker which is able to select any date?
There is a method to allow to select a date within a specific range:
var dateClosedRange: ClosedRange<Date> {
let min = Calendar.current.date(byAdding: .day, value: -10000, to: Date())!
let max = Calendar.current.date(byAdding: .day, value: 10000, to: Date())!
return min...max
}
Is there a better way?
Just leave the range out:
DatePicker("Date of birth", selection: $birthDate, displayedComponents: .date)
or:
DatePicker(selection: $birthDate, displayedComponents: .date) { Text("Date of birth") }