1

To be clear, i'm not asking how to use the ViewModifier protocol to create a struct with the body function that can then be used to modify a view. This question is a little bit different.

I'm trying to create a reusable alternative to the NavigationView struct, which has been mostly successful using @Viewbuilder to enable trailing closure syntax which enables me to use the view i've named 'NavBarView' like this:

NavBarView(foregroundColor: .gray) {
        Text("Child view")
    }

Which uses the following initializer:

init(foregroundColor: Color, @ViewBuilder content: () -> Content) {
    self.foregroundColor = foregroundColor
    self.content = content()
}

I can post all the code here for the NavBarView struct if you'd like to see it, but I haven't for brevity.

This code compiles fine and creates the desired effect which looks like this:

enter image description here

However, I'd like to be able to implement the optional ability to add items to the 'navigation bar', similar to how you can call .navigationBarItems(trailing: ) on views inside a navigation view. I'm not sure I could go about implementing this though.

What i've tried so far is creating an optional state property in the NavBarView struct called item, where it's type Item conforms to View as follows:

@State var item: Item?

This item is then placed into an HStack so that when it isn't optional it should be showed next to the "Parent View" text.

I've then written the following function within the NavBarView struct:

func trailingItem(@ViewBuilder _ item: () -> Item) -> some View {
    self.item = item()
    return self
}

I've then attempted to call the function like this:

NavBarView(foregroundColor: .gray) {
        Text("Child view")
    }.trailingItem{Text("test test")}

However, I'm not getting any text appearing, and the debug button which i've hooked up to print out what is in the item property prints out nil, so for some reason that function isn't setting the item property as Text("test test").

Am I going about this completely the wrong way? Could someone shed any light on how I might go about achieving the desired behavior?

1 Answer 1

1

This is possible approach, the only small correction to your modifier

extension NavBarView {
    func trailingItem(@ViewBuilder _ item: @escaping () -> Item) -> some View {
        var view = self    // make modifiable
        view.item = item()
        return view
    }
}

and so you don't need to have it as @State, just declare it as

fileprivate var item: Item?

Tested with Xcode 11.4

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer! This does indeed work. I'm wondering if this is actually the correct way to implement this sort of thing though? Is this how the .navigationBarItems(trailing: ) modifier is implemented I wonder.
@テッド, how exactly implemented standard components only Apple knows, but considered variant is not the one of course, possible alternate is view preferences.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.