• Stars
    star
    325
  • Rank 129,046 (Top 3 %)
  • Language
    Swift
  • License
    Mozilla Public Li...
  • Created over 7 years ago
  • Updated almost 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An unintrusive & light-weight iOS app-theming library with support for animated theme switching.

jumbotron

Gestalt

Gestalt is an unintrusive and light-weight framework for application theming with support for animated theme switching.

screencast

Usage

Let's say you want to theme a view controller with a single label:

import Gestalt

struct Theme: Gestalt.Theme {
    let view: ViewTheme = .init()

    static let light: Theme = .init(view: .light)
    static let dark: Theme = .init(view: .dark)
}

struct ViewTheme: Gestalt.Theme {
    let font = UIFont.preferredFont(forTextStyle: .headline)
    let color: UIColor
    let backgroundColor: UIColor

    static let light: Theme = .init(
        color: UIColor.black
        backgroundColor: UIColor.white
    )

    static let dark: Theme = .init(
        color: UIColor.white
        backgroundColor: UIColor.black
    )
}

// In `AppDelegate.application(_:didFinishLaunchingWithOptions:)`
// assign a default theme (or user's choice from user defaults):
ThemeManager.default.theme = Theme.light

class ViewController: UIViewController {
    @IBOutlet var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.observe(theme: \Theme.view)
    }
}

extension ViewController: Themeable {

    typealias Theme = ViewTheme

    func apply(theme: Theme) {
        self.view.backgroundColor = theme.backgroundColor
        self.label.textColor = theme.color
        self.label.font = theme.font
    }
}

The call self.observe(theme: \Theme.view) registers the receiver for theme observation on ThemeManager.default for future theme changes and then calls it once immediately. The initial call is not animated, any further changes however are animated.

To change the current theme (even while the app is running) simply assign a different theme to your given ThemeManager in use:

ThemeManager.default.theme = Theme.dark

This will cause all previously registered closures on the given ThemeManager to be called again.

See the GestaltDemo target for a more realistic/elaborate usage example.

Note:

  1. It is generally sufficient to use ThemeManager.default. It is however possible to create dedicated ThemeManagers via let manager = ThemeManager().

Usage in App Extensions

The use appearance proxies after a view has already been loaded this library uses a hack that removes and re-adds the root view of the application from the main window to activate the proxies. This is not possible in app extensions, such as a today widget, because the extension safe API restricts access to the main window. So to use this library in app extensions you need to manually trigger the reload of the root view by adding something like this to your root view controller after you set up your themes.

ThemeManager.default.observe(theme: Theme.self) { [weak self] _ in
        if let strongSelf = self, let superview = strongSelf.view.superview {
            strongSelf.view.removeFromSuperview()
            superview.addSubview(strongSelf.view)
        }
    }

Important:

  1. The body of func apply(theme: Theme) should be idempotent to avoid unwanted side-effects on repeated calls.

Installation

The recommended way to add Gestalt to your project is via Carthage:

github 'regexident/Gestalt' ~> 2.0.0

or via Cocoapods:

pod 'Gestalt', '~> 2.0.0'

or via Swift Package Manager:

let package = Package(
    name: "GestaltDemo",
    dependencies: [
        .package(url: "https://github.com/regexident/Gestalt.git", from: "2.0.0")
    ],
    targets: [
        .target(name: "GestaltDemo", dependencies: [ "Gestalt" ])
    ]
)

License

Gestalt is available under the MPL-2.0 license. See the LICENSE file for more info.

More Repositories

1

cargo-modules

Visualize/analyze a Rust crate's internal structure
Rust
723
star
2

DLWidgetMenu

Versatile solution for displaying widget menus. Easily adjustable with custom layouts and/or animations.
Objective-C
414
star
3

DLAlertView

UIAlertView replacement that can embed custom content views, is fully themable and let's you use a delegate and/or blocks.
Objective-C
286
star
4

Pulsar

A versatile solution for displaying pulse animations as known from Apple Maps.
Swift
158
star
5

Rainbows

A Metal-backed, blazingly fast alternative to CAGradientLayer.
Swift
87
star
6

EventBus

A safe-by-default pure Swift alternative to Cocoa's `NSNotificationCenter`
Swift
76
star
7

swift-watch

Watches over your Swift project's source
Swift
48
star
8

DLConstraintLayout

Implementation of CAConstraint/CAConstraintLayoutManager for iOS that is compatible with equivalent OSX APIs.
Objective-C
37
star
9

Strategist

Algorithms for building strong immutable AIs for round-based games.
Swift
36
star
10

DLPDFRenderer

Lightweight solution for generating multi-page PDFs on iOS from arbitrary HTML input.
Objective-C
30
star
11

Sandbox

A simple to use yet versatile API for dealing with sandboxed file access.
Swift
25
star
12

AsyncOperation

A hassle-free implementation of asynchronous NSOperations/NSBlockOperations.
Swift
22
star
13

median

An implementation of an efficient O(n) median filter in Rust.
Rust
21
star
14

rust-seal

Rust implementation of Needleman-Wunsch & Smith-Waterman sequence alignment
Rust
18
star
15

Blues

A type-safe high-level wrapper around Core Bluetooth for iOS
Swift
17
star
16

apply_attr

A syntax extension providing higher-order attributes to Rust.
Rust
16
star
17

Forest

A collection of persistent immutable trees.
Swift
14
star
18

DLColorPicker

Modular color picker for iOS that uses no image resources for rendering
Objective-C
14
star
19

CollectionViewMultiColumnLayout

A tiled waterfal/mosaic UICollectionViewLayout with support for explicit columns.
Swift
13
star
20

XCConfig

XCConfig is a simple Swift implementation of a parser for ".xcconfig" files.
Swift
10
star
21

EnhancedRoundedRectangle

A reimplementation of SwiftUI's RoundedRectangle with support for non-uniform corner radii
Swift
5
star
22

Sync

Useful synchronization primitives in Swift
Swift
5
star
23

DLLog

NSLog-like logging API with support for level and context filtering.
Objective-C
3
star
24

SortedCollection

A sorted collection type for safely performing binary search operations in Swift
Swift
2
star
25

ScopedDefaults

Type-safe and structured UserDefaults in Swift
Swift
2
star
26

github-labels

Set of reasonable default labels and pleasant colors for GitHub projects
2
star
27

var_float

A universal representation of IEEE 754 floating-point numbers convertible between arbitrary precisions.
C++
2
star
28

tryexpand

Test harness for ui tests of macro expansion and its diagnostics
Rust
2
star
29

sitrep

Frontend-agnostic progress reporting for Rust
Rust
2
star
30

talks

Collection of tech-talks I've given over the last years
1
star
31

lasean

Latent Semantic Analysis (LSA) for Ruby.
Ruby
1
star
32

PseudoRandom

Implementations of pseudo-random number generators in Swift
Swift
1
star
33

Interner

Swift implementation of general-purpose interners for every use case
Swift
1
star
34

Captain

Type-safe iOS app routing/coordination
Swift
1
star