swiftuiswiftui-navigationview

How to move Text to NavigationTitle when scrolling past it


A lot of apps (for example the Apple Music app) move some text only to the NavigationTitle once a user scrolls past it. Is there a way to do this in SwiftUI (preferably without using GeometryReader or ScrollviewReader)?

Here’s what I’m looking for: example in the Apple Music app


Solution

  • So the simplest way to achieve this is to use onAppear and onDisappear for the content you want to be a title. I.e. something like this:

    struct SomeView: View {
    
        @State var songTitle = "Whenever You Need Somebody" // Probably comes form some data model
        @State var screenTitle = "" // <-- what to show in screen title, nothing by default
    
        var body: some View {
            ScrollView { // Just taking this combo as example, could be a list, or a form, or anything else with scroll
                LazyVStack {
                    // ... some elements
                    Text(songTitle)
                        .onAppear {
                            screenTitle = "" // <-- hides title when this text is visible
                        } 
                        .onDisappear {
                            screenTitle = songTitle // <-- shows title when this text is not visible
                        }
                    // ... some elements
                }
            }
        }
    }
    

    This basic solution will work well on some layouts, but may require some fine tuning on others. This is because SwiftUI's onAppear and onDisappear are not at exactly the moment when view is shown or hidden, it's rather done a few lines ahead of time (for onAppear), and a few lines after for onDisappear. So in some layouts you may need to have these events for some elements that come before and after the text you want to use for a title. Or you may implement a more sophisticated solution using GeometryReader (example)