SwiftUI sidebar list bottom items not responding on click - ios

Here I have Sidebar list in which I am having list of item coming from my modelview.
When I tap on top items are responding. But few bottom items(cells in swift) not respond on click and row that are not responding vary depending on device I am checking.
Let suppose I am having 12 items in my list upto 7 rows are working in iPhone 8 and for iPhone 11 pro upto 9 rows are working.
SideMenuListView.swift
Here is the code for listing menu on sidebar.
List {
ForEach(self.viewModel.data,id: \.id) { item in
ZStack(alignment:.leading) {
SideMenuCell(image: Image(item.imageName), title: item.name)
.frame(height: 42)
NavigationLink.init(destination: item.view) {
EmptyView()
}
}
.buttonStyle(PlainButtonStyle())
}
}
Code for creating side menu:
SideMenuContentView.swift
GeometryReader { _ in
EmptyView()
}
.background(Color.gray.opacity(0.3))
.opacity(self.isOpen ? 1.0 : 0.0)
.animation(Animation.easeIn.delay(0.25))
.onTapGesture {
// Close Menu on click outside menu.
self.menuClose()
}
VStack(alignment: .leading, spacing: 0){
/// Set Profile View on top.
SideMenuHeader().fixedSize()
.frame(width: self.width,height: 150)
.offset(x: self.isOpen ? 0 : -self.width)
.animation(.default)
/// Set Sidemenu View.
HStack {
SideMenuListView(viewModel: SideMenuListViewModel())
.frame(width: self.width)
.background(Color.white)
.offset(x: self.isOpen ? 0 : -self.width)
.animation(.default)
.onDisappear {
// close side menu
self.isOpen = false
}
Spacer()
}
}
}
Is there something overlaying my cell? How can I debug that is there any overlay over my content.

It is not possible to test provided code, so just by code reading, I assume the issue is due to .offset
SideMenuHeader().fixedSize()
.frame(width: self.width,height: 150)
.offset(x: self.isOpen ? 0 : -self.width) // << here !!
.animation(.default)
/// Set Sidemenu View.
HStack {
SideMenuListView(viewModel: SideMenuListViewModel())
.frame(width: self.width)
.background(Color.white)
.offset(x: self.isOpen ? 0 : -self.width) // << here !!
that's because .offset does not change layout/frame/contentArea of view, it shifts only visual representation rendered on screen, so real view is not at the place where user see it and try to interact.
Thus the solution is to remove those offsets and rethink layout.

Related

SwiftUI Button Disable styling does not work in some cases

I have the following button in a custom view that I reuse in multiple places
Button(action: { selectedDate = date }) {
VStack {
Text(day.shortName)
.font(.caption2)
.foregroundColor(isSelectedDate ? .white : .primary)
.frame(maxWidth: .infinity)
Spacer().frame(height: 7)
Text("\(date.dayOfMonth)")
.bold()
.foregroundColor(isSelectedDate ? .white : .primary)
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.purple.brightness(isSelectedDate ? 0 : 0.6))
.clipped()
}.disabled(isInPast)
Dates in the past supposed to be disabled, and I confirmed that they are actually disabled as expected; however, the disabled styling looks different in multiple screens although it's the exact same view being used.
What could cause the disable state to not be styled accordingly in some screens?
In both screenshots dates from 25-29 are disabled
In both usages I simply add the view to a VStack
var body: some View {
VStack {
WeekView(selectedDate: $booking.selectedDate).padding()
var body: some View {
VStack(spacing: 0) {
WeekView(selectedDate: $selectedDate)
.padding(.horizontal)
.padding(.bottom)
Don't rely on primary color. Use a custom color and use isInPast to make an opacity.
Figured it out, the parent in one of the screens had .buttonStyle(.plain) which makes the disabled styling work as expected. So I just dded that to the component itself to make sure the disabled styling is always in place

Click the button to move to the next iteration

I'm trying to make a quiz app using SwiftUI. Since I am doing mobile programming for the first time, I am inexperienced and I may have basic mistakes. I keep the questions that I will use in app in a CSV file. I am reading this CSV file with a foreach loop, but all questions are loaded on the screen because the loop is expected to end in the view section. What I want is for the foreach loop to go to the next iteration only when the button is clicked.
//
// QuestionView.swift
// csvQuestions
//
//
import SwiftUI
struct QuestionView: View {
var brandGradient = Gradient(colors: \[Color (.systemPurple), Color(.systemIndigo)\])
#State var Questionx:\[Question\]
var body: some View {
ZStack{
//ARKA PLAN
Image("Image")
.resizable()
.scaledToFill()
.frame(width: UIScreen.main.bounds.width*1,height: UIScreen.main.bounds.height*1)
VStack{
RoundedRectangle(cornerRadius: 20)
.fill(LinearGradient(colors: \[.white,.yellow\], startPoint: .top, endPoint: .bottom))
.frame(width: UIScreen.main.bounds.width*0.9,height: UIScreen.main.bounds.height*0.7)
.padding(80)
.opacity(0.85)
Spacer()
}
VStack(){
ForEach(Questionx){
question in
Text(question.detail)
.font(.callout)
.fontWeight(.semibold)
.multilineTextAlignment(.center)
.fontWidth(.standard)
.frame(width:UIScreen.main.bounds.width*0.9,height: UIScreen.main.bounds.height*0.1)
.offset(y:115)
Spacer()
ForEach (optionsGenerator(day: String(question.date), year: String(question.year)),id:.self) { i in
Button {
if ((question.date) == "\(i[0]) \(i[1])") && (String(question.year) == i[2])
{
print ("true")
}
else {
print ("false")
}
} label: {
Text ("(i\[0\]) " + String(i\[1\]) + " " + i\[2\])
.frame(width: UIScreen.main.bounds.width*0.75,height:UIScreen.main.bounds.height*0.075)
.foregroundColor (.white)
.background (RadialGradient (gradient: brandGradient, center: .center, startRadius: 25,
endRadius: 120))
.clipShape (Capsule())
}
}
}
Spacer()
}.frame(width: UIScreen.main.bounds.width*1,height: UIScreen.main.bounds.height*1)
}
}
}
struct QuestionView_Previews: PreviewProvider {
static var previews: some View {
QuestionView(Questionx: loadCSData())
}
}
I looked at the development of similar applications on YouTube but I could not find a solution. I also tried to set up the loop in different ways but with no results.
When I add multiple line of CSV file:
When I add only a single line of CSV file, everything looks like what I want:

How to ignore safe area for container and respect safe area for content in swift UI

I'm trying to create a bottom sheet in swift ui that looks something like this
https://user-images.githubusercontent.com/33900517/172068237-4dd58374-b6e6-4340-a913-7085fb64b254.mp4
My issue is that I have an animated bottom sheet, but because it is ignoring the safe area, when I click into the textfield it does not expand with the keyboard.
How would I fix this so the view expands with the keyboard but the white at the bottom still goes beyond the safe area?
I.e. the containing view should ignore the safe area, and the content within should adhere to the safe area.
Here is the bottom sheet code snippet, full example can be found here
https://gist.github.com/CTOverton/4fbfb8db2de31f3b5f5ef9ee88e8f744
var body: some View {
GeometryReader { geometry in
VStack() {
self.content
}
.padding(.vertical, 34)
.padding(.horizontal, 16)
// .frame(width: geometry.size.width, height: geometry.size.height * heightRatio, alignment: .top)
.frame(width: geometry.size.width, height: self.maxHeight, alignment: .top)
.background(Color(.white))
.cornerRadius(Constants.radius)
.frame(height: geometry.size.height, alignment: .bottom)
.offset(y: max(self.offset + self.translation, 0))
.animation(.interactiveSpring())
.gesture(
DragGesture().updating(self.$translation) { value, state, _ in
state = value.translation.height
}.onEnded { value in
let snapDistance = self.maxHeight * Constants.snapRatio
guard abs(value.translation.height) > snapDistance else {
return
}
self.isOpen = value.translation.height < 0
}
)
}
.edgesIgnoringSafeArea([.bottom, .horizontal])
.shadow(color: Color(hue: 1.0, saturation: 0.0, brightness: 0.0, opacity: 0.08), radius: 12, y: -8)
}
I've tried various configurations of .ignoreSafeArea() and .safeAreaInset() but I just can't seem to get it quite right.
Here are some pictures for reference as well
Actually instead of ignoring safe area for everything (that results in issue), we need it only in background, so the question is how to correctly construct background in this case.
Note: the .cornerRadius is also not appropriate here, because it clips content
Here is a main part of a fix. Tested with Xcode 13.4 / iOS 15.5
.background(
RoundedRectangle(cornerRadius: Constants.radius) // corners !!
.fill(.white) // background !!
.edgesIgnoringSafeArea([.bottom, .horizontal]) // << only here !!
)
Complete test module is here

Adjust View up with Keyboard show in SwiftUI 3.0 iOS15

I have sign up page with a VStack embedded in a ScrollView that's embedded in a VStack. In the innermost VStack I have a series of TextFields with a custom TextFieldStyle.
The UI of the signup page looks like this:
VStack {
ScrollView {
VStack(spacing: 24) {
TextField(text: $firstNameText) {
Text(.firstNameLabel)
}
.textFieldStyle(.customTextfieldStyle())
TextField(text: $lastNameText) {
Text(.lastNameLabel)
}
.textFieldStyle(.customTextfieldStyle())
}
}
Spacer()
Button(action: submit) {
Text(.nextButtonTitle)
}
}
Next, the customTextfieldStyle looks like this:
VStack(alignment: .leading, spacing: 0) {
configuration
.font(.bodyBook14)
.padding(.bottom, 16)
Rectangle()
.fill(errors.isEmpty ? Color.primary : .errorRed)
.frame(height: 1)
ForEach(errors) { error in
Text(error.title)
.font(.bodyBook14)
.foregroundColor(.errorRed)
.padding(.top, 8)
}
}
In my custom textfield style I added a rectangle and an error text. The problem I'm having is with this custom style, the rectangle and error messages below the textfield is being covered on focus. the keyboard avoidance doesn't offset enough of the scrollview to display them to the user. The keyboard properly offsets the view just enough to show only the textfield but not the rectangle and error messages. Is it possible to make the keyboard recognize the entire custom textfield style should shift up?
Screenshot below shows how error text is all covered by the keyboard / button.

When there are different sized Text in a HStack, top alignment doesn’t apply to larger sized text

I have a HStack with multiple elements, particularly two Texts with different font sizes. I want both text to be aligned to the top of the view.
HStack(alignment: .top) {
Image(systemName: "cloud.drizzle.fill")
Text("14°")
.font(.largeTitle)
Text("86%")
.font(.callout)
Spacer()
}
However, the first (larger) Text is outputted below the other two:
Actually it's aligned correctly , add backgrounds to each Text and you will find that the frame of the Text is aligned correctly
but to solve the case that you are looking for , I did a hack for you , by doing some calculs
The result:
1) Alignement of the two Text
Put both of them in one HStack , with alignment: .firstTextBaseline
Then play on the second text , by adding a baselineOffset with (bigFont.capHeight - smallFont.capHeight)
You can learn more about fonts , but the main information that you need is this :
So your code will be :
HStack(alignment: .firstTextBaseline) {
Text("14°")
.font(Font(bigFont))
.background(Color.blue)
Text("86%")
.font(Font(smallFont))
.baselineOffset((bigFont.capHeight - smallFont.capHeight))
.background(Color.yellow)
Spacer()
}
2) Align the Image with the text :
by adding a padding which will be equal to bigFont.lineHeight-bigFont.ascender (go back to the picture on top , to see how I calculated it )
And the final code :
struct ContentView: View {
#State var pickerSelection = ""
let bigFont = UIFont.systemFont(ofSize: 50)
let smallFont = UIFont.systemFont(ofSize: 15)
var body: some View {
HStack(alignment:.top) {
Image(systemName: "cloud.drizzle.fill")
.background(Color.red)
.padding(.top, bigFont.lineHeight-bigFont.ascender)
HStack(alignment: .firstTextBaseline) {
Text("14°")
.font(Font(bigFont))
.background(Color.blue)
Text("86%")
.font(Font(smallFont))
.baselineOffset((bigFont.capHeight - smallFont.capHeight))
.background(Color.yellow)
Spacer()
}
}
}
}
PS : I added backgrounds to show you the real frames of each view
Currently the texts are aligned by top. but the large text has ascent height that is larger than small text. so the align is not top of text.
Unfortunately, SwiftUI doesn't support the alignment of top of text.
But you can align the top of text manually like as following code.
HStack(alignment: .top) {
Image(systemName: "cloud.drizzle.fill")
Text("14°")
.font(.largeTitle).padding(.top, -5.0)
Text("86%")
.font(.callout)
Spacer()
}

Resources