{"id":18867501,"url":"https://github.com/leekurg/navigationviewelastic","last_synced_at":"2026-01-27T12:01:44.629Z","repository":{"id":187713904,"uuid":"668672571","full_name":"leekurg/NavigationViewElastic","owner":"leekurg","description":"Mimic of NavigationView + ScrollView, with ability to add any content under title of top bar","archived":false,"fork":false,"pushed_at":"2025-04-04T10:28:02.000Z","size":92,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T11:19:57.297Z","etag":null,"topics":["navigationbar","navigationview","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leekurg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-20T10:44:44.000Z","updated_at":"2025-03-26T20:46:23.000Z","dependencies_parsed_at":"2023-08-11T22:04:07.927Z","dependency_job_id":"55b27d87-f176-4d89-89e1-efa76af70a99","html_url":"https://github.com/leekurg/NavigationViewElastic","commit_stats":null,"previous_names":["leekurg/navigationviewelastic"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leekurg%2FNavigationViewElastic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leekurg%2FNavigationViewElastic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leekurg%2FNavigationViewElastic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leekurg%2FNavigationViewElastic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leekurg","download_url":"https://codeload.github.com/leekurg/NavigationViewElastic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248897142,"owners_count":21179546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["navigationbar","navigationview","swiftui"],"created_at":"2024-11-08T05:09:35.847Z","updated_at":"2026-01-27T12:01:44.618Z","avatar_url":"https://github.com/leekurg.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NavigationViewElastic\n`NavigationViewElastic` is a SwiftUI `View` that replicates the behavior of navigation bar for the system `NavigationView` combined with `ScrollView`, while adding the capability to use custom content beneath the navigation bar title. Requires **iOS 15** or later.\n\n\u003ctable\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e \u003cp align=\"center\"\u003e \u003cstrong\u003eiOS 15\u003c/strong\u003e \u003c/p\u003e \u003c/td\u003e\n            \u003ctd\u003e \u003cp align=\"center\"\u003e \u003cstrong\u003eiOS 26\u003c/strong\u003e \u003c/p\u003e \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n              \u003cimg src=\"https://github.com/user-attachments/assets/70497361-57d8-461a-a497-3d917469e236\" width=\"250\"\u003e\n            \u003c/td\u003e\n            \u003ctd\u003e\n              \u003cimg src=\"https://github.com/user-attachments/assets/41d549a3-1d6c-465e-a37d-d368254cd331\" width=\"250\"\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e \u003cp align=\"center\"\u003e \u003cstrong\u003eiOS 15\u003c/strong\u003e \u003c/p\u003e \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n             \u003ctd\u003e\n              \u003cimg src=\"https://github.com/user-attachments/assets/e2bac2e4-d187-42c0-94e5-871d811915a5\" width=\"530\"\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e \u003cp align=\"center\"\u003e \u003cstrong\u003eiOS 26\u003c/strong\u003e \u003c/p\u003e \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n              \u003cimg src=\"https://github.com/user-attachments/assets/60500b7b-7d78-49fe-835b-0d96644b1c73\" width=\"530\"\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n### What is NavigationViewElastic\n`NavigationViewElastic` is not meant to replace `NavigationStack` or `NavigationView`, nor does it propose alternative navigation flows. Instead, it offers a way to create customizable navigation bars for specific parts of your app where enhanced interactivity and visual appeal are desired. **NVE** adds new functionality by enabling interactive, resizable, and customizable content at the bottom of the navigation bar. This is achieved through a simple, SwiftUI-friendly API, with full support for color schemes and device orientation.\n\n### Features\n1. **Transparent Navigation Bar**: Mimics the behavior of the system navigation bar.\n2. **Automatic adoption to system dysign language**: Adapts to ``iOS 26`` Liquid Glass design if available.\n3. **Custom Background Styles**: Apply any background style to the navigation bar.\n4. **Interactive, Resizable Content**: Add custom content at the bottom of the navigation bar.\n5. **Custom Toolbar Items**: Easily add leading or trailing toolbar items.\n6. **Title Display Control**: Adjust the navigation bar title's display mode (`large`, `inline`, or `auto`).\n7. **Editable Configurationl**: Configure sizes, padding, and spacing using a simple `NVE.Config` API.\n8. **Integration with Vanilla Navigation** Smooth integration with emdedded `NavigationStack`/`NavigationView`\n9. **Color Scheme Support**: Automatically adapts to the device's light or dark mode.\n10. **Orientation Support**: Works seamlessly in both portrait and landscape orientations.\n11. **Safe Area Configuration**: Customize the safe areas for **NavigationViewElastic** content. Bar items respects device's safe area.\n12. **Optional Back Button**: Include a `NVE.BackButton` when **NavigationViewElastic** is nested in a navigation hierarchy.\n13. **Pull-to-Refresh API**: Implement pull-to-refresh functionality using a closure. When the task is complete, provide a `Bool` to hide the progress indicator. If no closure is passed, the progress indicator will not be shown.\n\n### Usage\nYou can use example project located here: [NavigationViewElastic Example](https://github.com/leekurg/NavigationViewElasticExample).\n\n```swift\nvar body: some View {\n    NavigationViewElastic {\n        VStack {\n            ///...\n        }\n        .nveTitle(\"Title\")               // Set navigation bar title\n        .nveTitleDisplayMode(.inline)    // Navigation bar title appears in minimized form\n    } subtitleContent: {\n        Button(\"Subtitle button\") { }    // Subtitle content for navigation bar\n    } leadingBarItem: {\n        NVE.BackButton()                 // Back button for leading bar placement\n    } trailingBarItem: {\n        Button(\"Bar button\") { }         // Button for trailing bar placement\n    }\n    .refreshable(stopRefreshing: .constant(false), onRefresh: { } )    // Perform action on swipe-to-refresh gesture\n    .nveConfig { config in\n        config.barCollapsedStyle = AnyShapeStyle(.ultraThinMaterial)    // Style bar's background in collapsed form\n    }\n}\n```\n\n#### Title Display Modes\n\nWith `.nveTitleDisplayMode()`, you can control how the navigation bar's title is displayed. There are three modes available:\n\n1. **`large`**: The title is initially displayed in a large format and collapses into a smaller title as you scroll down.\n2. **`inline`**: The title always appears in its small form.\n3. **`auto`**: This is the default mode, where the title appears in `large` form in portrait orientation and switches to `inline` in landscape orientation.\n\n#### Config\n\n**NavigationViewElastic** relies on `NVE.Config` to configure various aspects, such as sizes, padding, and spacing. The `NVE.Config` is set in the \n`SwiftUI` Environment and affects all **NavigationViewElastic** instances down the view hierarchy. You can use a convenient view extension to customize the `NVE.Config`:\n\n```swift\n.nveConfig { config in\n    config.barCollapsedStyle = AnyShapeStyle(.red)    /// Applies a red background color to the bar when collapsed\n    config.largeTitle.topEdgeInset = 10               /// Sets the top edge inset for the large title\n    config.smallTitle.topPaddingPortrait = 5          /// Sets the top padding for the small title in portrait mode\n    config.contentIgnoresSafeAreaEdges = .horizontal  /// NVE content will ignore horizontal safe area insets\n    ...\n}\n```\n\n#### Observation and control\n`NavigationViewElastic` provides a set on observation and control methods to notify the client about changes happened and allow programmatic control for varoius aspects of using it. You can observe and process following parameters:\n- ``onNveTitleDisplayModeChanged(_:)`` - triggers on title display mode change.\n- ``onNveScrollPositionChanged(_:)`` - triggers on scroll position change.\n- ``onNveScrollRectChanged(_:)`` - triggers on scroll position change.\n\nTo do both observe and programmatically control scroll position you can utilize ``scrollableToAnchor(to:)`` method. It accepts a ``Binding`` value with current ``NVE.ScrollAnchor``, changing this value will cause animated scroll to target position.\n\n#### Wrapping in NavigationStack\nSince `NavigationViewElastic` is a `View`, you can use it within a `NavigationStack` (or within `NavigationView` for older systems) just like any other view. Here's an example of how a navigation chain might look:\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/user-attachments/assets/06732307-0bc4-4ec1-b128-c1bf537b4db9\" width=\"250\"\u003e\n\u003c/p\u003e\n\nIn this example, the first and fourth screens display standard navigation titles, while the second and third screens showcase customized `NavigationViewElastic` titles. To achieve this smooth transition behavior, make sure to hide the system navigation bar on any **NVE** screen within the navigation sequence by adding the following code:\n\n```swift\nNavigationViewElastic {\n    ...\n}\n.toolbar(.hidden, for: .navigationBar)\n```\nAdditionally, if you want the *swipe-back* gesture to work on **NVE** screens, you need to implement this extension in your project (credit to [this answer](https://stackoverflow.com/a/68650943)):\n\n```swift\nextension UINavigationController {\n    override open func viewDidLoad() {\n        super.viewDidLoad()\n        interactivePopGestureRecognizer?.delegate = nil\n    }\n}\n```\n\n### Install\n`SPM` installation: in **Xcode** tap «**File → Add packages…**», paste is search field the URL of this page and press «**Add package**».\n\n#### Roadmap\n## Roadmap\n- [x] Landscape orientation\n- [x] Title display modes\n- [x] Hideable subtitle content\n- [x] Handy config API\n- [x] Safe area\n- [ ] Custom title content\n- [ ] Searchable\n- [ ] Hide subtitle on scroll option\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleekurg%2Fnavigationviewelastic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleekurg%2Fnavigationviewelastic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleekurg%2Fnavigationviewelastic/lists"}