https://github.com/ivan-magda/swiftui-interface-orientation
Per-view orientation locking for SwiftUI apps, solving the lack of built-in orientation control.
https://github.com/ivan-magda/swiftui-interface-orientation
interface-orientation ios ios-development orientation screen-rotation swift swift-package-manager swiftui uikit view-modifier
Last synced: 4 months ago
JSON representation
Per-view orientation locking for SwiftUI apps, solving the lack of built-in orientation control.
- Host: GitHub
- URL: https://github.com/ivan-magda/swiftui-interface-orientation
- Owner: ivan-magda
- License: mit
- Created: 2025-03-17T05:29:59.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-01-15T13:40:59.000Z (5 months ago)
- Last Synced: 2026-01-16T21:35:55.728Z (5 months ago)
- Topics: interface-orientation, ios, ios-development, orientation, screen-rotation, swift, swift-package-manager, swiftui, uikit, view-modifier
- Language: Swift
- Homepage: https://ivan-magda.github.io/swiftui-interface-orientation/
- Size: 46.9 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# SwiftUI Interface Orientation
[](https://swift.org)
[](https://developer.apple.com/ios/)
[](https://swift.org/package-manager/)
[](LICENSE)
**Lock screen orientation per-view in SwiftUI. No UIKit subclassing, no hacks.**
```swift
Text("This view stays portrait")
.supportedInterfaceOrientations(.portrait)
```
That's it. The view locks to portrait. Navigate away, it unlocks. Conflicting constraints across multiple views? Handled automatically.
## The Problem
SwiftUI has no native way to lock orientation for specific views. You either lock the entire app in Info.plist, or dive into UIKit lifecycle callbacks scattered across AppDelegate, SceneDelegate, and view controllers.
This package gives you a single view modifier that just works.
## Installation
### Swift Package Manager
```swift
dependencies: [
.package(url: "https://github.com/ivan-magda/swiftui-interface-orientation.git", from: "1.1.0")
]
```
Or in Xcode: **File β Add Packages** β paste the URL above.
## Quick Start
### 1. Configure the manager (once, at app launch)
```swift
import SwiftUIInterfaceOrientation
@main
struct MyApp: App {
init() {
InterfaceOrientationManager.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
```
### 2. Wire up iOS orientation callbacks
```swift
class OrientationDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?
) -> UIInterfaceOrientationMask {
InterfaceOrientationManager.shared.supportedInterfaceOrientations
}
}
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(OrientationDelegate.self) var delegate
init() {
InterfaceOrientationManager.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
```
### 3. Lock any view to specific orientations
```swift
struct PortraitOnlyView: View {
var body: some View {
Text("Locked to portrait")
.supportedInterfaceOrientations(.portrait)
}
}
struct LandscapeOnlyView: View {
var body: some View {
VideoPlayer(player: player)
.supportedInterfaceOrientations([.landscapeLeft, .landscapeRight])
}
}
```
## How It Works
The package uses a centralized `InterfaceOrientationManager` that tracks orientation constraints from all active views:
1. When a view with `.supportedInterfaceOrientations()` appears, it registers its constraint
2. When the view disappears, the constraint is removed
3. The manager computes the intersection of all active constraints
4. If constraints conflict (intersection is empty), it falls back to your app's defaults from Info.plist
This means nested views with different constraints "just work"βthe most restrictive common orientation wins.
## API
### View Modifier
```swift
func supportedInterfaceOrientations(_ orientations: UIInterfaceOrientationMask) -> some View
```
### Configuration
```swift
// Use defaults from Info.plist
InterfaceOrientationManager.configure()
// Or specify custom defaults
InterfaceOrientationManager.configure(
configuration: .init(defaultOrientations: .portrait)
)
```
### Orientation Masks
```swift
.portrait // Portrait only
.landscapeLeft // Landscape, home button on right
.landscapeRight // Landscape, home button on left
.portraitUpsideDown // Upside down (iPad only effectively)
.landscape // Both landscape orientations
.all // All orientations
.allButUpsideDown // All except upside down
```
## Requirements
- iOS 14.0+
- Swift 6
- Xcode 16.0+
## License
MIT License. See [LICENSE](LICENSE) for details.
## Contributing
Issues and PRs welcome.