1

I have a strange problem. I have a view with a list and I add the .refreshable to it to load data. The data was loaded, but the default progressView of the pull-to-refresh was not appearing.

I load the same app on a different device (bigger screen) and it was showing there... The first thing I notice was the NavigationView title was showing as inline (it was configured with .navigationBarTitleDisplayMode(.automatic). So I start playing with those values.

First let's add some background information. Basically I have 3 views: Login (LoginView) -> Selection Menu (SelectView) -> Job Listing (JobListingView)

After successful login, I show the Selection Menu, and on that menu (it's a kind of grid with buttons) I have an option to go to the Job Listing. In that listing is where I have the .refreshable. I'm developping for iOS15.

Here are the relevant part of my views:

LoginView

Here I define the NavigationView so I can navigate through view but I do not want the navBar to be shown that's why it's hidden

public var body: some View {
    NavigationView{
        ZStack{
            LoginView(viewModel: viewModel)
                .background(Color(.white))
                .navigationBarHidden(true)     // Hides the navigation bar
            
            NavigationLink(destination: SelectView(), isActive: $viewModel.loggedIn){
                EmptyView()
            }
        }
        
    }
}

SelectView

See the comment above: .navigationBarTitleDisplayMode(.inline)

var body: some View {
    VStack{
        HStack{
            Spacer()
            
            NavigationLink(destination: JobListingView()){
                SelectItemView(name: "Jobs", icon: "icAssignment")
            }
            
            Spacer()
            SelectItemView(name: "Bitácora", icon: "icBinnacle")
            Spacer()
        }
        .padding(.bottom, 20)
        HStack{
            Spacer()
            SelectItemView(name: "Inventario", icon: "icDolly")
            Spacer()
            SelectItemView(name: "3D", icon: "icBinnacle")
            Spacer()
        }
        
        Spacer()
    }
    .navigationTitle("MY APP")
    // IF I USE .large HERE, THEN IN THE NEXT VIEW, THE DEFAULT ProgressView OF THE .refreshable IS NOT SHOWN
    .navigationBarTitleDisplayMode(.inline)
    .navigationBarBackButtonHidden(true) // hides the "back" or previous view title button
}

JobListingView

var body: some View {
    List(viewModel.jobListDTO, id: \.id) { job in
        JobItemView(item: job)
            .listRowSeparator(.hidden)
    }
    .refreshable {
        await viewModel.requestJobListing()
    }
    .onAppear {
        Task{
            await viewModel.requestJobListing()
        }
    }
    .navigationTitle("job-list-title")
    // NO MATTER WAHT I PUT HERE .large OR .inline. IF THE PARENT IS .large THEN THE ProgressView OF THE .refreshable IS NOT SHOWN
    .navigationBarTitleDisplayMode(.large)
    .listStyle(PlainListStyle())
    .frame(maxWidth: .infinity)
}

1 Answer 1

1

Workaround:

Specify navigationViewStyle as stack. Now refresh view will be visible.

NavigationView {
...
}
.navigationViewStyle(.stack)

Since the issue occurs only in smaller devices like iPhone, you can use the below for different navigation style based on device

NavigationView {
...
}
.deviceSpecificNavigationViewStyle()

extension View {
    func deviceSpecificNavigationViewStyle() -> some View {
        Group {
            if UIDevice.current.userInterfaceIdiom == .phone {
                navigationViewStyle(.stack)
            } else {
                navigationViewStyle(.automatic)
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I'll try that and let you know!

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.