Auto hide/show List Section header in SwiftUI - swiftui

I make a list in SwiftUI with header like following, how to make the header auto hide when I scroll up and comeback when scroll down?
List{
Section(header: headerView){
ForEach(customers.filter{
...
}
}
}

Related

Applying different LabelStyle conditionally fails

I want my users to be able to define whether they want .iconOnly or .titleAndIcon behaviour for their label.
Unexpectedly to me though I am not able to apply on or the other style conditionally at the top of my view hierarchy:
Any suggestions on what needs to be done here?
Here is a possible approach. Tested with Xcode 13.4 / iOS 15.5
extension View {
#ViewBuilder
func labelStyle(includingText: Bool) -> some View {
if includingText {
self.labelStyle(.titleAndIcon)
} else {
self.labelStyle(.iconOnly)
}
}
}
and usage like
TabView {
// .. your code
}
.labelStyle(includingText: labelStyleShowText)

How do I cast ViewModifier Content to anticipated type?

So I think I could be using ViewModifiers incorrectly, but is it possible to cast the Content of a ViewModifier to the anticipated type, e.g. Text? I want to use .fontWeight(.bold) but that is not part of the base/aliastype Content. Alternatively what should I use to achieve this effect? A custom Style function?
struct ButtonTextModifier: ViewModifier {
func body(content: Content) -> some View {
(content as Text) //<--- ERROR HERE
.fontWeight(.bold) //<--- Because I want to use this
.font(.largeTitle)
.padding()
}
}
The error I get:
Cannot convert value of type 'ButtonTextModifier.Content' (aka '_ViewModifier_Content<ButtonTextModifier>') to type 'Text' in coercion
You might have to add a new method on Text by declaring it in it's extension.
extension Text {
func buttonTextModifier() -> some View {
self
.fontWeight(.bold)
.font(.largeTitle)
.padding()
}
}

How to initialize an ObservedObject from a view created with a NavigationLink?

My apologies if this is not the right question to ask, as I am completely new to SwiftUI and iOS programming in general. The question indicates what I want to do, and the error I'm getting I believe is a red herring because of the SwiftUI compiler. It's likely that I am taking the incorrect approach to solving this problem altogether.
I am using XCode Version 11.2.1 (11B500)
View utilizing the ObservedObject:
struct Results: View {
var jobId: String
#ObservedObject var jobDetailService: JobDetailService
init(jobId: String) {
self.jobId = jobId
jobDetailService = JobDetailService(jobId: jobId)
}
var body: some View {
//... view code here
}
}
And it is within this view that I am getting the error (at the ZStack line) "Generic parameter 'C0' could not be inferred". When I comment out the NavigationLink block, the error goes away. Further, when the Results view does not depend on the jobId parameter (and we construct JobDetailService inline with #ObservedObject var jobDetailService = JobDetailService(), this all works. However, I need to be able to pass the jobId parameter to the JobDetailService in order to make the network call to fetch and publish the data.
struct JobList: View {
#ObservedObject var jobListService = JobListService()
var body: some View {
NavigationView {
List(jobListService.jobs) {job in
ZStack {
JobCard(name: job.fullName, date: job.lastUpdated)
NavigationLink(destination: Results(jobId: job.jobId)) {
EmptyView()
}
}
}
}
}
}
After reading this article, and thinking about Asperi's advice on not solely relying on initialization, I opted to do the following:
Remove custom initializer from JobDetailService and instead instantiate the service inside my Results view. Then in an .onAppear method on the Results view, call the getJobDetail method from JobDetailService which in turn makes the network call that populates the #ObservedObject. This allows me to pass in the parameters I need and control when the network call is made. Maybe not the right pattern for this problem but it works for my use case for now.
I assume the following should help you:
Declaration...
struct Results: View {
#ObservedObject var jobDetailService: JobDetailService
var body: some View {
//... view code here
}
}
... and usage
NavigationLink(destination: Results(jobDetailService: JobDetailService(jobId: jobId))) {
EmptyView()
}

Laying out Rectangle() Views in SwiftUI inside of ForEach?

So, I am trying to layout Rectangle shapes on a SwiftUI View, like this:
I am not sure how to best go about this. Any suggestion?
EDIT:
I added this and it now works. Is there a better more proper solution?
extension CGRect: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(NSCoder.string(for: self).hashValue)
}
}
The error saying you the reason. I recommend you to create a class. So you will able to make it BindableObject if needed and add more properties like Color if needed
class RectangleModel: NSObject, Identifiable {
var rect: CGRect
init(rect: CGRect) {
self.rect = rect
}
}
Or the best is to create one more model(like RectangleStore) that will be a BindableObject and will contain array of RectangleModels. It will be much flexible

In SwiftUI, what's the difference between .modifier and .layout

I cannot seem to find any difference between applying a ViewModifier using either .modifier or .layout. They both produce the same result. Anyone knows what's the difference between these two. There's no documentation whatsoever.
For example, given this modifier:
struct RedTitle: ViewModifier {
func body(content: Content) -> some View {
return content.foregroundColor(.red).font(.title)
}
}
These two views turn out to look identical:
Text("Hello world!").layout(RedTitle())
Text("Hello world!").modifier(RedTitle())
UPDATE
As of Xcode 11 beta 4, the layout modifier has been marked deprecated:
extension View {
#available(*, deprecated, renamed: "modifier")
#inlinable public func layout<T>(_ layout: T) -> some SwiftUI.View where T : SwiftUI.ViewModifier {
return modifier(layout)
}
}
ORIGINAL
There is no difference as of Xcode 11 beta 2. That doesn't mean there will always be no difference. Possibly layout is left over from an older design and needs to be removed, or perhaps a later beta will make it behave differently.
The complete interface exported by SwiftUI can be found in this file:
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface
Looking in that file, you can find the declaration of func modifier:
extension View {
public typealias Modified<T> = _ModifiedContent<Self, T> where T : SwiftUI.ViewModifier
#inlinable public func modifier<T>(_ modifier: T) -> Modified<T> where T : SwiftUI.ViewModifier {
return .init(content: self, modifier: modifier)
}
}
And the declaration of func layout:
extension View {
#inlinable public func layout<T>(_ layout: T) -> Modified<T> where T : SwiftUI.ViewModifier {
return modifier(layout)
}
}
Because both modifier and layout are declared #inlinable, Swift includes the function bodies in the .swiftinterface file. We can see that layout just calls modifier and does nothing else.