SwiftUI Datepicker changes size when first time choosing a date - ios

I have a date picker inside a bottom sheet view.
When the bottom sheet opens, the first time I choose a day, the date picker height changes.
P.S: If I set a custom height for the picker using .frame, the date picker just becomes smooshed inside the frame.
var body: some View {
VStack {
HStack {
Text("date_picker_title".ld())
.font(.custom(Font.rRegular, size: 12))
.padding()
Spacer()
}
HStack {
Text(date.prettyDate)
.font(.custom(Font.rMedium, size: 28))
Spacer()
Text(date.prettyHour)
.font(.custom(Font.rMedium, size: 28))
}.padding(.horizontal)
Seperator(cellHeight: 0).frame(height: 2)
Spacer().frame(height: 6)
DatePicker("", selection: $date, in: Date()..., displayedComponents: .date)
.datePickerStyle(.graphical)
.labelsHidden()
.tint(Color.appPurple)
.padding(.horizontal)
.padding(.bottom, -10)
Seperator(cellHeight: 0).frame(height: 2)
HStack {
Text("date_picker_enter_time".ld())
.font(.custom(Font.rRegular, size: 12))
DatePicker("", selection: $date, displayedComponents: .hourAndMinute)
.labelsHidden()
.tint(Color.appPurple)
Spacer()
}.padding()
HStack {
Button {
completion(nil)
} label: {
Text("date_picker_cancel".ld())
.font(.custom(Font.rRegular, size: 14))
.foregroundColor(Color.appPurple)
}
Spacer()
Button {
completion(date)
} label: {
Text("date_picker_ok".ld())
.font(.custom(Font.rRegular, size: 14))
.foregroundColor(Color.appPurple)
}
}.padding(.horizontal)
Spacer().frame(height: 50)
}
.frame(maxWidth: .infinity)
.background(Color.appLightPurple)
.padding(.bottom, -50)
}

Related

iOS 15 Keyboard hides textfield

I am trying to create a messaging page layout but the keyboard hides the textfield and moves everything to the the top. I have looked at many tutorials online and replicated them exactly but none of them seem to work.
Here is all the code I have written:
struct MessagingPage: View {
var user: OfficialUserModel
#ObservedObject private var vm = TheUserModel()
#State var screenWidth = UIScreen.main.bounds.width
#State var imageSize = UIScreen.main.bounds.width / 12
#State var text = ""
#State var show = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
ZStack{
VStack{
HStack{
Spacer()
NavigationLink(destination: UserDisplayPage(user: user)) {
HStack{
WebImage(url: URL(string: user.imageURL ))
.resizable()
.aspectRatio( contentMode: .fill)
.frame(width: imageSize, height: imageSize
)
.cornerRadius(imageSize/2)
VStack(alignment: .leading){
Text(user.FullName)
.font(.body)
.fontWeight(.bold)
.foregroundColor(.white)
Text("\(user.City) , \(user.Country)")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.white)
}
}
}
Spacer()
HStack{
Button{
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.down")
.font(.title)
.foregroundColor(.myWhite)
}
}
.padding(.trailing)
}
.padding(.top, 30)
.frame(height: 75)
.background(Color.mainBlack)
ScrollView{
Spacer()
ForEach(0..<2){ num in
HStack{
Spacer()
HStack{
Text("Hello \(user.firstName)")
.foregroundColor(.orange)
}
.padding()
.background(Color.mainBlack)
.cornerRadius(15)
.shadow(color: .orange, radius: 2)
}
.padding(.horizontal)
.padding(.top, 8)
}
HStack{Spacer()}
HStack{
HStack{
Text("\(user.FullName) is unable to recieve your message at this time. Please try again at a later time.")
.foregroundColor(.green)
}
.padding()
.background(Color.mainBlack)
.cornerRadius(15)
.shadow(color: .green, radius: 2)
Spacer()
}
.padding(.horizontal)
.padding(.top, 8)
HStack{Spacer()}
}
.background(Color.mainBlack)
ZStack{
HStack{
HStack{
HStack{
TextField("Say Something...", text: self.$text)
.placeholder(when: text.isEmpty) {
Text("Say Something...").foregroundColor(.myWhite.opacity(0.5))
}
.frame(width: screenWidth - 200, height: screenWidth/25)
.foregroundColor(.myCyan)
.accentColor(.myCyan)
.background(Color.mainBlack)
.textContentType(.emailAddress)
if !text.isEmpty{
Button{
print(text)
self.text = ""
}label: {
Image(systemName: "paperplane")
.foregroundColor(.myCyan)
.font(.system(size: 20))
}
}
else{
Button{
print("Show more options")
}label: {
Image(systemName: "plus")
.foregroundColor(.myCyan)
.font(.system(size: 20))
}
}
}
.frame(width: screenWidth - 150, height: screenWidth/25)
.padding()
.background(Color.mainBlack)
.cornerRadius(30)
.shadow(color: .myCyan, radius: 5)
.padding(.bottom,5)
}
}
.padding(.bottom, 50)
.frame(width: screenWidth)
}
}
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.mainBlack)
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
I want the the textfield to move up as well as the messages in the scrollview but the top HStack with the user image and back/dismiss button should remain in place.
You really have a lot of code in there - and two reasons to clean it up:
To get a good answer, you need to post a minimal, reproducible example, which may also help you debug the code before posting it
Many lines of code are redundant or useless, for example:
Why using things like HStack{Spacer()} instead of Spacer(), which by the way is not needed in this context?
Why having a stack that has only another stack inside?
Coming to your issue, the problem is that one of the redundant modifiers is preventing the text file to move up, and this is the line to delete:
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
Why setting a frame that is as high and large as much as the screen? This is forcing the text field to stay at the bottom.
I tried to do some clean up, I bet some more can be done - see the code below, now the keyboard does not cover the text field anymore:
struct MessagingPage: View {
// Removed some lines of code to reproduce your issue
#State var screenWidth = UIScreen.main.bounds.width
#State var imageSize = UIScreen.main.bounds.width / 12
#State var text = ""
#State var show = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
// What is the purpose of this ZStack???
// ZStack{
VStack{
HStack{
Spacer()
NavigationLink(destination: Text("Hello")) {
Text("Top bar")
}
Spacer()
HStack{
Button{
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.down")
.font(.title)
.foregroundColor(.white)
}
}
.padding(.trailing)
}
.padding(.top, 30)
.frame(height: 75)
.background(Color.black)
ScrollView{
// All the views inside the Scrollview need to be inside a VStack
VStack {
// Why this spacer???
// Spacer()
ForEach(0..<2){ num in
HStack{
Spacer()
HStack{
Text("Hello username")
.foregroundColor(.orange)
}
.padding()
.background(Color.black)
.cornerRadius(15)
.shadow(color: .orange, radius: 2)
}
.padding(.horizontal)
.padding(.top, 8)
}
HStack{Spacer()}
HStack{
HStack{
Text("User is unable to receive your message at this time. Please try again at a later time.")
.foregroundColor(.green)
}
.padding()
.background(Color.black)
.cornerRadius(15)
.shadow(color: .green, radius: 2)
Spacer()
}
.padding(.horizontal)
.padding(.top, 8)
// Why a Spacer inside an HStack???
// HStack{Spacer()}
}
.background(Color.black)
}
// What is the purpose of this ZStack???
// ZStack{
// Why an HStack that has only an HStack inside??
// HStack{
// Why an HStack that has only an HStack inside??
// HStack{
HStack{
TextField("Say Something...", text: self.$text)
.frame(width: screenWidth - 200, height: screenWidth/25)
.foregroundColor(.cyan)
.accentColor(.cyan)
.background(Color.white)
.textContentType(.emailAddress)
if !text.isEmpty{
Button{
print(text)
self.text = ""
}label: {
Image(systemName: "paperplane")
.foregroundColor(.cyan)
.font(.system(size: 20))
}
}
else{
Button{
print("Show more options")
}label: {
Image(systemName: "plus")
.foregroundColor(.cyan)
.font(.system(size: 20))
}
}
}
// Are you sure you want set the height of this stack based on the width?
// .frame(width: screenWidth - 150, height: screenWidth/25)
.frame(width: screenWidth - 150)
.padding()
.background(Color.black)
.cornerRadius(30)
.shadow(color: .black, radius: 5)
.padding(.bottom,5)
// }
// }
.padding(.bottom, 50)
.frame(width: screenWidth)
// }
}
// }
// Why setting a frame that is high and large as much as the screen??
// .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.black)
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}

SwiftUI: Build View from bottom alignment in scrollView

Is there a way to build UI elements in SwiftUI inside scroll view with bottom Alignment?
My use case: I have a screen where the screen has
Spacer (What ever is left after allocating below elements)
LogoView
Spacer() - 30
Some Text - 4/5 lines
Spacer() - 50 (this will be calculated off of GR size Height)
HStack with Two Button - This should be pinned to bottom of view / ScrollView
I would like to know how Can I pin the HStack view to ScrollView Bottom
I've replicated my setup and reproduced my problems in a Swift playground like so
struct ContentView: View {
var body: some View {
GeometryReader { gr in
ScrollView {
VStack {
Spacer()
Image(systemName: "applelogo")
.resizable()
.frame(width: gr.size.width * 0.5, height: gr.size.height * 0.3, alignment: .center)
Spacer().padding(.bottom, gr.size.height * 0.01)
Text("SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME")
.fontWeight(.regular)
.foregroundColor(.green)
.multilineTextAlignment(.center)
.padding(.top, gr.size.height * 0.05)
.padding(.horizontal, 40)
.layoutPriority(1)
Spacer()
.frame(minHeight: gr.size.height * 0.12)
HStack {
Button(action: {
}, label: {
Text("Button 1")
})
.foregroundColor(Color.white)
.padding(.vertical)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(8)
Button(action: {
}, label: {
Text("Button 2")
})
.foregroundColor(Color.white)
.padding(.vertical)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(8)
}
.padding(.horizontal, 20)
}
//.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
}
I understand that when scrollView is introduced in SwiftUI view Spacer length is changed to Zero, Would like to know what's the best way to achieve this
struct SampleView: View {
var body: some View {
GeometryReader { gr in
VStack {
ScrollView {
VStack {
// Fills whatever space is left
Rectangle()
.foregroundColor(.clear)
Image(systemName: "applelogo")
.resizable()
.frame(width: gr.size.width * 0.5, height: gr.size.height * 0.3, alignment: .center)
.padding(.bottom, gr.size.height * 0.06)
Text("SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME TEXT SOME")
.fontWeight(.regular)
.foregroundColor(.green)
.multilineTextAlignment(.center)
.padding(.horizontal, 40)
.layoutPriority(1)
// Fills 12 %
Rectangle()
.frame(height: gr.size.height * 0.12)
.foregroundColor(.clear)
HStack {
Button(action: {
}, label: {
Text("Button 1")
})
.foregroundColor(Color.white)
.padding(.vertical)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(8)
Button(action: {
}, label: {
Text("Button 2")
})
.foregroundColor(Color.white)
.padding(.vertical)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(8)
}
.padding(.horizontal, 20)
.padding(.bottom, 20)
}
// Makes the content stretch to fill the whole scroll view, but won't be limited (it can grow beyond if needed)
.frame(minHeight: gr.size.height)
}
}
}
}
}
I wanted the scrollview to appear bottom to top instead of top to bottom. This had my answer: https://www.thirdrocktechkno.com/blog/implementing-reversed-scrolling-behaviour-in-swiftui/
TLDR: .rotationEffect(Angle(degrees: 180)).scaleEffect(x: -1.0, y: 1.0, anchor: .center) on the scrollview AND on the items in the scrollview

.Clipped() not working on Pickers SwiftUI

I need to create a view that has 2 Pickers and 2 DatePickers.
In order to avoid having them overlapping each other, I used .clipped(). However, this is not working.
I can successfully resize the pickers, but I cannot limit the "selection area" to their frame size.
Here is my code:
VStack(spacing: 10) {
Picker(selection: self.$dayTypeSelectedIndex, label: Text("")) {
ForEach(0 ..< self.dayTypes.count, id: \.self) {
Text(self.dayTypes[$0])
.foregroundColor(Color.black)
}
}
.pickerStyle(SegmentedPickerStyle())
.labelsHidden()
.clipped()
Spacer()
Group {
DatePicker("", selection: self.$dateIntervalStart, displayedComponents: .hourAndMinute)
.labelsHidden()
.colorInvert()
.colorMultiply(Color.black)
.frame(maxHeight: 50)
.clipped()
Spacer()
Text("às")
.foregroundColor(Color.black)
Spacer()
DatePicker("", selection: self.$dateIntervalEnd, displayedComponents: .hourAndMinute)
.labelsHidden()
.colorInvert()
.colorMultiply(Color.black)
.frame(maxHeight: 50)
.clipped()
}
Spacer()
HStack {
Picker(selection: self.$tripNotificationDelta, label: Text("")) {
ForEach(0...60, id: \.self) {
Text($0 < 10 ? "0\($0)" : "\($0)")
.foregroundColor(Color.black)
}
}
.labelsHidden()
.frame(maxWidth: 50, maxHeight: 50)
.clipped()
Text("mins before trip")
.foregroundColor(Color.black)
}
}
}
What am I doing wrong?
I'm using XCode 12. Plus, this interface is being built for devices not running iOS 14.
Thanks!
So, I figured it out. Just put .compositingGroup() before .clipped(). Something like this:
DatePicker("", selection: self.$dateIntervalEnd, displayedComponents: .hourAndMinute)
.labelsHidden()
.colorInvert()
.colorMultiply(Color.black)
.frame(maxHeight: 50)
.compositingGroup()
.clipped()
As mentioned in here
Adding this simple extension solves the problem with overlapping scroll areas. You don't need to add .compositingGroup() and .clipped()
extension UIPickerView {
override open var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: super.intrinsicContentSize.height)
}
}

SwiftUI Button not being tapped

I Have a button embedded inside a Hstack inside a Vstack inside a ZStack inside a Vstack inside a geometryReader in swiftui that does not get tapped. I put a print statement inside and whenever I tried to Tap the button, the print statement won't print. Can anyone help me out here? Thanks. Heres my code:
struct DetailedGroupView: View {
#State var actrualImage: Image?
#State var title = "title"
#State var description = "description"
#State var sgName = "sgName"
#State var membersCount = 0
#Environment(\.presentationMode) var presentationMode
var body: some View {
GeometryReader{ geo in
VStack{
ZStack{
(self.actrualImage ?? Image("earthPlaceholder"))
.resizable()
.aspectRatio(contentMode: .fill)
VStack{
Spacer()
HStack{
//This button doesn't work
Button(action: {
print("Button Tapped")
self.presentationMode.wrappedValue.dismiss()
}, label: {
Image(systemName: "chevron.left").foregroundColor(.white)
}).padding()
Text(self.title)
.font(.largeTitle)
.fontWeight(.bold)
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.padding()
.minimumScaleFactor(0.5)
Spacer()
}
HStack{
Text(self.description)
.font(.custom("Open Sans", size: 18))
.fontWeight(.ultraLight)
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.padding()
Spacer()
}
Spacer()
HStack{
Image(systemName: "person.2.fill").foregroundColor(.white).padding(.leading)
Text("\(self.membersCount)")
.font(.custom("Open Sans", size: 12))
.fontWeight(.semibold)
.foregroundColor(.white)
Spacer()
Text(self.sgName)
.font(.custom("Open Sans", size: 12))
.fontWeight(.semibold)
.foregroundColor(.white)
.padding()
}.padding()
}.frame(width: geo.size.width, height: 294)
}.frame(width: geo.size.width, height: 294)
.clipShape(RoundedRectangle(cornerRadius: 12))
.edgesIgnoringSafeArea(.top)
Spacer()
ScrollView(showsIndicators: false){
VStack{
Spacer()
}.onAppear{
self.actrualImage = Image("globePlaceholder")
}
}
}
}.navigationBarBackButtonHidden(true)
}
}
Just tested this same code on both XCode 11.5 and 12.0, and the button works fine... be sure to test it on a simulator not on the preview/canvas

How can I add a NavigationLink without changing my UI?

My question is how I can add a NavigationLink to the code below without changing the UI. I tried around for a few hours, but unfortunately without success. So if someone could help me that would be nice. I also found this but unfortunately, the answers did not work for me. Maybe I did something wrong
import SwiftUI
struct ContentView: View {
var body: some View {
UITableView.appearance().separatorStyle = .none
return NavigationView {
List {
CardView()
.listRowInsets(EdgeInsets())
}
.navigationBarTitle("Title")
}
}
}
struct CardView: View {
var body: some View {
VStack {
// NavigationLink(destination: EmptyView()) {
Image("Image")
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
VStack(alignment: .leading) {
Text("Title")
.font(.system(size: 20))
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(3)
Text("Subtitle")
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
Image(systemName: SFSymbolName.chevron_right)
.foregroundColor(.secondary)
.font(Font.body.weight(.semibold))
}
.padding([.leading, .bottom, .trailing], 16)
.padding(.top, 5)
// }
}
.background(Color("CustomCardViewColor"))
.cornerRadius(10)
.padding(.all, 0.1)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(.sRGB, red: 150/255, green: 150/255, blue: 150/255, opacity: 0.1), lineWidth: 1)
)
.padding([.top, .leading, .trailing])
}
}
The reason your UI changes drastically is that NavigationLink wraps its content in an implicit HStack, placing your Image to the left of your HStack. You have a couple options, depending on whether you want to use the automatic disclosure chevron or your own styled one.
To use the system chevron:
HStack {
VStack(alignment: .leading) {
Text("Title")
.font(.system(size: 20))
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(3)
Text("Subtitle")
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
// this simply places the chevron approximately where yours is
NavigationLink(destination: EmptyView()) {
EmptyView()
}
}
If you want your own:
HStack {
VStack(alignment: .leading) {
Text("Title")
.font(.system(size: 20))
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(3)
Text("Subtitle")
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
// this hidden NavigationLink makes the whole row clickable
NavigationLink(destination: EmptyView()) {
EmptyView()
}.opacity(0)
// your chevron is displayed
Image(systemName: SFSymbolName.chevron_right)
.foregroundColor(.secondary)
.font(Font.body.weight(.semibold))
}
The top is with the system chevron, the bottom uses yours
You may just wrap it around the image of chevron_right. So you can click it to the next page
HStack {
VStack(alignment: .leading) {
Text("Title")
.font(.system(size: 20))
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(3)
Text("Subtitle")
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
NavigationLink.init(destination: Text("Temp Link")) {
Image(systemName: SFSymbolName.chevron_right)
.foregroundColor(.secondary)
.font(Font.body.weight(.semibold))
}
}

Resources