Announcing Darkscreen - A Dark App
October 6, 2019I’m so excited to announce that my first iOS app, Darkscreen - A Dark App, has a public beta on Testflight! Ever since I was given my first iPod (all the way back in 7th grade!) I’ve dreamed of creating something that millions of people have the ability to enjoy, and I can’t express how excited I am. Here’s the official description:
Darkscreen allows you to use other iPad apps in Split View without any distractions, no hassle.
Darkscreen provides multiple themes, including:
- Dark
- Light
- 80s
- 90s
- Outrun
Download using Testflight today!
Why Darkscreen?
I really love using Apollo for Reddit by Christian Selig, but he hasn’t gotten a chance to create a true iPad experience for his Reddit client yet. I use Darkscreen next to Apollo in Split View so that Apollo can be in an iPhone-sized container while keeping the rest of the screen black.
For example, posts shown in Apollo don’t quite look right when in full horizontal mode on iPad:
Now with Darkscreen, I can browse Apollo in its intended view size without being distracted by other apps:
Switching to a new theme in Darkscreen automatically updates the table view as well as the root view underneath:
My next goal, of course, is for Darkscreen to respond to the system-wide Dark Mode setting.
Why Open Source?
I found it an interesting challenge to modify the appearance of all of all views in the app immediately after a user selects a theme in a UITableView
, and I hope this brief example can help other developers implement their own theme system.
Even though iOS 13 introduces system-wide Dark Mode, this example app can be helpful to support any custom themes that go beyond the default dark and light styles.
How to Update the Theme for a View
I’ve implemented the theme system using a Settings Bundle, so the BaseViewController
can subscribe to settings (theme) changes:
func registerForSettingsChange() {
NotificationCenter.default.addObserver(self,
selector: #selector(BaseViewController.settingsChanged),
name: UserDefaults.didChangeNotification,
object: nil)
}
A Theme
corresponds to UI styles and colors:
class Theme {
// ...
init(_ name: String, statusBar: UIStatusBarStyle, background: UIColor, primary: UIColor, secondary: UIColor) {
self.name = name
statusBarStyle = statusBar
backgroundColor = background
primaryColor = primary
secondaryColor = secondary
}
}
When a setting changes, BaseViewController
updates its UI elements:
@objc func settingsChanged() {
updateTheme()
}
func updateTheme() {
// Status bar
setNeedsStatusBarAppearanceUpdate()
// Background color
self.view.backgroundColor = Settings.shared.theme.backgroundColor
// Navigation bar
self.navigationController?.navigationBar.updateTheme()
}
And UINavigationBar
is extended to support theme switching:
public extension UINavigationBar {
func updateTheme() {
// Background color
barTintColor = Settings.shared.theme.backgroundColor
// Bar item color
tintColor = Settings.shared.theme.secondaryColor
// Title text color
titleTextAttributes = [NSAttributedString.Key.foregroundColor: Settings.shared.theme.secondaryColor]
// Status bar style
barStyle = Settings.shared.theme.navbarStyle
// Tell the system to update it
setNeedsDisplay()
}
}