aswinter90/SwiftyDrawer
Customisable SwiftUI drawer component available on iOS 15+
🔩 Installation
You can add SwiftyDrawer to an Xcode project by adding it as a package dependency. The required minimum platform version is iOS 15.
From the File menu, select Add Package Dependencies... Enter "https://github.com/aswinter90/SwiftyDrawer" into the package repository URL text field.
Or add it to your Swift package by referencing it in your package manifest:
let package = Package(
name: "MyLibrary",
platforms: [.iOS(.v15)],
products: [
.library(
name: "MyLibrary",
targets: ["MyLibrary"]),
],
dependencies: [
.package(url: "https://github.com/aswinter90/SwiftyDrawer", from: "1.0.0")
],
targets: [
.target(
name: "MyLibrary",
dependencies: ["SwiftyDrawer"]
),
]
)📱 Examples
The project contains multiple demo applications with showcases for displaying the SwiftyDrawer in different usage scenarios.
Minimal setup
<img width="350" height="761" alt="image" src="https://github.com/user-attachments/assets/b192581e-9a37-41d3-9898-7ccf1f99b9ed" />
import SwiftUI
import SwiftyDrawer
struct ContentView: View {
@State private var drawerState = DrawerState(case: .partiallyOpened)
var body: some View {
MySwiftLogo()
.drawerOverlay(
state: $drawerState,
content: {
VStack {
ForEach(0..<30) { index in
Text("Item \(index)")
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
}
.padding(.top, 8)
}
)
}
}With sticky header and changing alignments
As shown in the video the drawer can be modified with a sticky header, which stays on top of the safe area or the tab bar when the drawer is closed. The default drag handle can also be replaced with any other given view. Finally the DrawerState is mutable and changing it from the outside will update the drawer position automatically.
https://github.com/user-attachments/assets/107b48e3-2f99-47ac-a7a9-5430d77b444a
State based drawer content
This is a demonstration for how the drawer content can be updated by observing a ViewModel state.
https://github.com/user-attachments/assets/0b127664-3b4d-40a6-8a0a-98061e0b6680
Customization
There are several modifiers for changing the drawer appearance and behaviors:
MySwiftLogo()
.drawerOverlay(
state: $drawerState,
content: {...}
)
.drawerStyle(drawerStyle: DrawerStyle) // Color, corner radius, shadows, etc.
.drawerFloatingButtonsConfiguration(configuration: DrawerFloatingButtonsConfiguration) // Circular buttons that are shown over the drawer
.drawerLayoutStrategy(layoutStrategy: DrawerContentLayoutStrategy) // Defines which collection-view–based layout approach the drawer uses—either a robust classic flow layout or a smoother but occasionally glitchy modern compositional layout.
.drawerAnimation(animation: Animation) // Define the animation type for opening and closing animations
.isDrawerHapticFeedbackEnabled(isEnabled: Bool) // If true the device vibrates after the drawer finished its opening and closing animation
.isApplyingRenderingOptimizationToDrawerHeader(Bool) // Set to false to prevent the drawer header being rendered as an offscreen image (using the `drawingGroup` modifier). This can be helpful if the header contains interactable content, like a horizontal scrollview
.drawerContentOffsetController(DrawerContentOffsetController?) // Used for reading or changing the content's scroll offset
.drawerOriginObservable(DrawerOriginObservable?) // Used for reading the drawer position💥 Known issues
- Bugs and glitches on older iOS versions like 15 must be expected. In some scenarios the drawer content is not scrollable in other the content's scroll level resets randomly.
- The drawer always requires a modifyable
statebinding, meaning that passing a constant binding will not work:.drawerOverlay(state: Binding.constant(.init(case: .fullyOpened)), ...) - Your content gets updated but it is not reflected in the drawer? Make sure to define your content as a dedicated view, which obsorves changes of a
Bindingor anObservableObjector take a look at theSwiftyDrawer-Map-Demo.
Package Metadata
Repository: aswinter90/SwiftyDrawer
Stars: 6
Forks: 1
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
README: README.md