Unable to change iOS 15 SwiftUI List Section header padding - swiftui

We are using SwiftUI and custom view for List Section's header.
But when compiling with Xcode13/iOS15 SDK, there seems to be extra left/right 20px + top/bottom 6px padding fixed in the header container view. I even created the bare minimum testing app, it seems unable to be customized.
This is not related to the newly introduced sectionHeaderTopPadding, so setting it to 0 doesn't work for me. I also tried .environment(\.defaultMinListHeaderHeight, 16) from this post, it also doesn't change the padding.
Here is snippet and screenshot:
List {
Section(header:
Text("Big header")
.foregroundColor(.red)
.background(Color.gray)
.frame(height: 30)
.padding(0)
) {
Text("Hello, world! 1")
.padding()
Text("Hello, world! 2")
.padding()
Text("Hello, world! 3")
.padding()
}
}
.environment(\.defaultMinListHeaderHeight, 1)
.listStyle(PlainListStyle())
Thanks a lot for helping :) cheers

Finally found the answer myself.
In iOS15, to remove padding for section header, you need to use .listRowInsets(EdgeInsets()) just like list cell.

Related

Navigation View Formatting Trouble

I'm a newbie, using XCode 13.0 to create a very basic app that needs to have a Settings view. I'd like to navigate to the Settings view on tapping a label. To do that, it seemed sensible to use a NavigationView with a NavigationLink.
Unfortunately, I'm encountering a formatting issue that creates a mess of the HStack in which the Setting label (gear icon) resides, as show below:
This is what I want, a result of the following code:
HStack(spacing: 25) {
... other labels
Label ("", systemImage: "gear")
.foregroundColor(.gray)
.font(.title)
.onTapGesture(perform: {
// Set a state variable that triggers an extension
// that brings up the SettingsView
})
}
This is what happens when NavigationView encapsulates the gear icon label. Note the vertical and horizontal white space around it.
HStack(spacing: 25) {
... other labels
NavigationView {
NavigationLink(destination: SettingsView()) {
Label ("", systemImage: "gear")
.foregroundColor(.gray)
.font(.title)
}.navigationBarTitle(Text(""))
}
}
I've, literally, spent weeks (sporadically) on this issue, looking up dozens of answers and trying various formatting options, without luck. I've also tried encapsulating parent and grandparent stacks into the NavigationView. To no avail. Surely, this is something trivial. Can somebody point me in the right direction?
p.s. there are other issues in that that Navigation link opens as a sub-window; I plan to tackle that later.
Edit: Right, so I tried using Yrb's code:
HStack(spacing: 25) {
... other labels
NavigationView {
NavigationLink(destination: Text("Linked View")) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
}
.fixedSize()
.background(Color.red)
}
]
Unfortunately, there's no substantive change...
In diagnosing these sort of issues, it helps to throw a .background() with a color on. You can then see the issue. In this case, it was twofold, one, you need to use a .fixedSize to shrink the view to its smallest dimensions necessary. That would leave you with the icon plus a little space. That was due to you using a label as it was leaving a spot for the Text("") that you used as a fill in. Since you only want the image, use Image(systemName:) The code then comes out like this:
struct NavLinkNoSpace: View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("Linked View")) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
}
.fixedSize()
// Setting this shows you what space you are using. Remove it when you are done
.background(Color.red)
}
}
}
A couple more things. If you have not ever set the NavigationTitle, you don't need to set it to "". In your example, there was no title, so I simply removed it and there was no effect.
More importantly, and it was addressed by some of the comments, you should only have one NavigationView in the view hierarchy. As long as you are in the hierarchy, you do not need to wrap things like NavigationLink to have them work. You can always throw one around your view call in the preview provider if you are in a child view, to show what things look like, and to test NavigationLinks, etc., but do not just put them in to your main code. It will lead to undesirable outcomes.
To summarize what worked to fix the primary problem, that of formatting: The key was in figuring what to encapsulate within the NavigationView. My mistake was to assume that only the NavigationLink needed to be in the NavigationView.
What worked was to place all the contents of the body into the NavigationView, like below:
var body: some View {
NavigationView {
VStack(spacing: -10) {
Text(appName)
.font(.largeTitle)
.foregroundColor(.blue)
.padding(.bottom)
// ...
// includes a bunch of VStacks and HStacks
// ... and finally
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
// ... more stuff
// ... and finally
}.padding(.top, -100) // NavigationView
} // body

SwiftUI PageView iOS 13 - Navigation link not working as expected

My project is target for iOS 13 onwards hence could not use PageTabViewStyle(). I tried with Mr. John suggestion from this link
SwiftUI create image slider with dots as indicators
Now I need to open the detail view on clicking the image in the slideshow. But now when I try to move the images the detail view is opening and could not move the images as in Pageview. I implemented the below code. Please let me know the solution to fix this. Thanks in advance.
PagingView(index: $index.animation(), maxIndex: images.count - 1){
ForEach(articles, id: \.self) { article in
NavigationLink(destination: ArticleDetailUIView(article: articles[self.index], isBookmark: false) , isActive: $areYouGoingToArticleView)
{
Image(article.image)
.resizable()
.scaledToFill()
.accessibility(identifier: "articleImage")
}
}
}
.aspectRatio(4/3, contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: 15))
After few browsing, the workaround was using the stepper to move around the slide show instead of scrolling the images. I added the below lines.
Stepper("Index: (index)", value: $index.animation(.easeInOut), in: 0...images.count-1)
.font(Font.body.monospacedDigit())
.labelsHidden()

SwiftUI overlay cancels touches

I have a button and I'd like to put a semi-transparent gradient overlay on top of it.
Button(action: {
print("Pressed")
}) {
Text("Press me")
}
.overlay(
LinearGradient(
gradient: Gradient(colors: [.clear, Color.black.opacity(0.3)]),
startPoint: .top,
endPoint: .bottom
).disabled(true)
)
Even though the gradient has disabled(true) it still eats the touches and doesn't forward them to the actual button. .allowsHitTesting(false) provides the same result.
Any idea what can be wrong?
Note: I know I can put the overlay just to Text("Press me") but I don't want it. (This is just example code showcasing the problem)
Edit: This issue is solved in Xcode 11.2 ✅
The following code works on Xcode 11.2 / iOS 13.2
struct TestButtonWithOverlay: View {
var body: some View {
Button(action: {
print("Pressed")
}) {
Text("Press me")
.padding()
}
.overlay(
LinearGradient(
gradient: Gradient(colors: [.clear, Color.black.opacity(0.3)]),
startPoint: .top,
endPoint: .bottom
)
.allowsHitTesting(false) // !!! must be exactly here
)
}
}
When working with a ScrollView the correct fix is to use the .background content modifier on the ScrollView:
https://developer.apple.com/documentation/swiftui/form/background(alignment:content:)
It will as expected with your "background" appearing above the content of the ScrollView.
Example of using to create a shadow effect:
Interesting note: On the simulator .overlay works with a ScrollView, but on a physical device only .background allows scrolling.
The physical device is on iOS 14, and the simulator is iOS 15, so it's possible it might have been a regression. Although apparently this issue dates back further than either.

Rounded corners in swiftui list sections

Here is a screen shot of iOS 13 Health app - User profile. I recently started with swiftui and wondering how to develop a screen like below. I tried list styles plain and grouped. But I couldn't get the look of below layout.
Can UI like this develop purely using swiftui-list?
I am specially looking for rounded sections and including a image inside the list.
As of iOS 14, you can use the code below. It works just perfectly, just like in UIKit.
List {
Section {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
Section {
Text("Item 4")
Text("Item 5")
Text("Item 6")
}
}.listStyle(InsetGroupedListStyle()) // this has been renamed in iOS 14.*, as mentioned by #Elijah Yap
.environment(\.horizontalSizeClass, .regular)
Thank you.
As of iOS 14.0, this list-style is .listStyle(InsetGroupedListStyle()) or .listStyle(.insetGrouped)
I run into the same problem and it looks like you can not achive this with list or section.
When you put cornerRadius modifier onto a section or list it is just applied to whatever the internals are making cells rounded while section itself being unchanged.
My solution was to avoid lists and sections entirely and build custom ones.
Something like
SectionView: View {
body: some View = {
VStack {
ForEach {
CellView()
}
}
.background(Color.white)
.cornerRadius(10)
.padding()
}
}
And put those sections over a Color view in some ZStack to have a gray background.
Take in account that the huge downside is that a ForEach will render all the cells right away, like if you have a thousand of cells then onAppear() will be called for each cell and strangely enough they will be called in backward order.
Hope it helps.
According to my findings and as of Xcode 11 GM seed 2 (11A420a), making this UI is not possible just from swiftui list.
There is a new list style available for storyboards named, insetGrouped. It has the exact same look.
https://developer.apple.com/documentation/uikit/uitableview/style

Text has only one line when put in HStack with something else (SwiftUI List)

im trying to show a list of items. Every row should contain a stripe on the left in a specific color and a headline. This headline is sometimes more than a line long but only shows as one line and "...". When I remove the Stripe it shows as multiline text. I've attached the code and two pictures for comparison
Heres my code :
HStack {
Rectangle()
.foregroundColor(poll.outcome ? .green : .red)
.frame(width: 3)
VStack {
Text(poll.poll.title!).font(.headline)
.lineLimit(2)
}
}
This is how it looks without the Rectangle:
And with the Rectangle:
In a List or ScrollView the SwiftUI engine will compress back the text area. .lineLimit(x) give you a maximum of line, not a minimum ;)
To secure that the engine does not shrink back the Text height and goes up to the maximum limit, add .fixedSize(horizontal: false, vertical: true) as shown below
HStack {
Rectangle()
.foregroundColor(.red)
.frame(width: 3)
VStack {
Text("line1\nline2\nline3").font(.headline)
.lineLimit(2)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
}
}
SwiftUI has some bugs right now and it is one of them and there is some discussion on this answer that you can check out.
Although It works on my machine, if you have any trouble about sizing elements, you can use Spacers as a workaround until all SwiftUI bugs fix by Apple.
For this case, you can wrap your text between two spacers like this:
VStack {
Spacer()
Text("FirstLine\nSecondLine\nThirdLine")
.font(.headline)
.lineLimit(2)
Spacer()
}