Add SwiftUI Sidebar next to PDF View on iOS
Display the PDFViewController
next to a Sidebar using SwiftUI.
//// Copyright © 2019-2025 PSPDFKit GmbH. All rights reserved.//// The Nutrient sample applications are licensed with a modified BSD license.// Please see License for details. This notice may not be removed from this file.//
import Combineimport PSPDFKitimport PSPDFKitUIimport SwiftUI
private extension NSNotification.Name { static let DismissHostingController = NSNotification.Name("DismissHostingControllerNotification")}
class SwiftUISidebarExample: Example {
override init() { super.init()
title = "SwiftUI Sidebar Example" contentDescription = "Shows how to show a PDFView in SwiftUI with sidebar." category = .swiftUI priority = 10 // We present this modal, as SwiftUI controls the navigation controller here. wantsModalPresentation = true embedModalInNavigationController = false }
private var dismissSink: AnyCancellable?
override func invoke(with delegate: ExampleRunnerDelegate) -> UIViewController? { let document = AssetLoader.document(for: .welcome) let swiftUIView = SwiftUISidebarExampleView(document: document)
let hostingController = DismissableHostingViewController(rootView: swiftUIView) hostingController.modalPresentationStyle = .fullScreen
dismissSink = NotificationCenter.default.publisher(for: .DismissHostingController) .sink { _ in hostingController.dismiss(animated: true, completion: nil) }
return hostingController }}
final private class DismissableHostingViewController: UIHostingController<SwiftUISidebarExampleView> { override init(rootView: SwiftUISidebarExampleView) { super.init(rootView: rootView) self.rootView.dismiss = dismiss }
@objc required dynamic init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func dismiss() { dismiss(animated: true, completion: nil) }}
private struct SwiftUISidebarExampleView: View { @ObservedObject var document: Document
// Logic is connected from the hosting view controller. var dismiss: (() -> Void)?
@State private var sidebarActionHandler = SidebarActionHandler(didSelectAnnotation: { _ in }, didSelectBookmark: { _ in }, didSelectOutline: { _ in })
var body: some View { NavigationView { Sidebar(dismiss: dismiss!) CombinedSidebar(document: document, actionHandler: sidebarActionHandler) // aka "PrimaryView" DetailView(document: document, sidebarActionHandler: $sidebarActionHandler) .navigationBarTitleDisplayMode(.inline) } }}
private struct Sidebar: View { let dismiss: (() -> Void)
var body: some View { Button("Exit Example", action: dismiss) }}
private struct DetailView: View { let document: Document @Binding var sidebarActionHandler: SidebarActionHandler private let actionEventPublisher = PassthroughSubject<PDFView.ActionEvent, Never>() @State private var selectedAnnotations: [Annotation] = []
var body: some View { PDFView(document: document, selectedAnnotations: $selectedAnnotations, actionEventPublisher: actionEventPublisher) { $0.pageTransition = .scrollContinuous $0.scrollDirection = .vertical $0.pageMode = .single $0.spreadFitting = .adaptive } .onAppear { // connect the sidebar handler with the event publisher sidebarActionHandler = SidebarActionHandler { annotation in selectedAnnotations = [annotation] } didSelectBookmark: { bookmark in actionEventPublisher.send(.setPageIndex(index: bookmark.pageIndex)) } didSelectOutline: { outlineElement in actionEventPublisher.send(.setPageIndex(index: outlineElement.pageIndex)) } } }}
// MARK: Previews
struct SwiftUISidebarExamplePreviews: PreviewProvider { static var previews: some View { let document = AssetLoader.document(for: .welcome) SwiftUISidebarExampleView(document: document) }}
This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.