An ambient light accessibility framework for iOS.

Related tags

Styling Ambience
Overview

Ambience

Brightness aware accessibility theme switching without coding.

CI Status Version License Platform

Ambience States

Special thanks

I'd like to thank Meng To and Marcos Griselli and all the Design+Code team for the support given to this project. Design+Code app is the place to go if you want to learn more about design and iOS development. The app is also the App Store debut of Ambience.

You may also follow the Ambience tutorial on Design+Code.

Thanks a lot guys!

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

If you find that pod install responds Unable to find a specification for Ambience, you may pod repo update.

Installation

Ambience is available through CocoaPods and it's highly recommended you use it. To install it, simply add the following line to your Podfile:

pod 'Ambience'

To enable it you have to call the Ambience singleton on your App Delegate like this:

import UIKit
import Ambience

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        _ = Ambience.shared

        return true
    }
}

Pretty standard stuff, right?

Ambience is so very convenient because it does a little bit of black magic under the hood. If you feel curious about how this work, scroll down to the Nitty-Gritty section.

Built-in support

Ambience has built-in support for the background color for the following Interface Builder objects:

  • View and all its children;
  • Search, Navigation and Tab bars and all of its children;
  • Text View, Button, and Label and all of its children.

There is also support for the text color for:

  • Text View, Button, and Label and all of its children.

And there is also support for dark and light bar styles on:

  • Search, Navigation and Tab bars and all of its children.

Customizing a view

To customize an Interface Builder view, use the Inspectable Properties on the Attributes Inspector. Don't forget to turn Ambience On for that view.

Attributes Inspector

Search, Navigation, and Tab need to be turned on but their respective styles are not customizable.

Custom Behaviors

It's also possible to define custom Ambience behavior on any Object that inherits from NSObject. Follow the instructions.

Define an Override of the Ambience Method

In this example, we are implementing the current behavior for Search, Navigation and Tab bars. It guards the notification data for the current state as an Ambience State and sets the bar style accordingly.

public override func ambience(_ notification : Notification) {

    super.ambience(notification)

    guard let currentState = notification.userInfo?["currentState"] as? AmbienceState else { return }

    barStyle = currentState == .invert ? .black : .default
}

The notification user info dictionary also comes with the previous state so that more complex stateful behaviors can be implemented. It may also come with an animated boolean attribute the is usually set to true and, at the first run, set to false so as not to have animation upon view appearance.

Turning Ambience On

If your object is set on Interface Builder, use the Attributes Inspector and set to On the Ambience value.

In case you are setting this object programmatically, just set its ambience boolean value to true before placing it.

Known issues

Text View inside collection

If you are using a Text View inside a Table View Cell or a Collection View Cell and, in the process of dequeuing it you set its attributed text, beware. Right after assigning the new Attributed Text will need to write a mandatory single line of code to have Ambience work in the Text View properly.

Follow the example:

// Inside the respective Table View Controller

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell : TextTableCell! = tableView.dequeueReusableCell(withIdentifier: "Cell with text") as! TextTableCell

    cell.textView?.reinstateAmbience()

    return cell
}

It's simple yet mandatory.

I could have set some observers inside Text View so it could perform it on its own, but I won't do it at the risk of referencing cycles and swizzling madness.

Nitty-Gritty

Yes. You need only a line of code to have Ambience work right out of the box. But there is a detail. For this to work, Awake From Nib is swizzled when you call Ambience.shared.

If you don't know what swizzling is, here goes a little explanation.

Swizzling two methods is nothing but swapping two method addresses. What do I mean by address? Why did I do this?

I wanted every UIView to have access to Ambience. To have that, I had to do some configuration in the UIView before it reaches the device's screen. I chose to do this in the Awake From Nib method because it's guaranteed to be called right before the view hits the screen and on most of the UIView objects, such as Navigation Bar, Search Bar and Tab Bar, that have a different lifecycle from a regular UIView.

static let classInit : Void = {

    swizzling(forClass: UIView.self, originalSelector: #selector(awakeFromNib), swizzledSelector: #selector(swizzled_awakeFromNib))
}()

@objc open func swizzled_awakeFromNib () {

    let name = String(describing:type(of: self))

    guard !NSObject.forbiddenNames.contains(name) else { return }

    swizzled_awakeFromNib()

    if ambience {
        _ = notificationManager
    }
}

The swizzling is going to happen to the address of Awake From Nib but will not affect inner calls. Let me explain. When UI Kit calls awakeFromNib on a UIView, what is actually going to happen is view.swizzled_awakeFromNib. Nonetheless, when swizzled_awakeFromNib is called inside swizzled_awakeFromNib, it actually calls awakeFromNib, thus, giving us access to the default implementation.

In another word, this is a complicated way of adding this few lines to every single UIView and any of its children:

if ambience {
    _ = notificationManager
}

Final note

If you have a nice idea or think that some edit of it might apply to a larger audience, feel free to create a pull request.

I'd like Apple to open the Trait Environment API so I may apply for my Trait Collection extension and delete a few hundred lines of code. If you are there Apple: please, open it.

Author

tmergulhao, [email protected]

License

Ambience is available under the MIT license. See the LICENSE file for more info.

You might also like...
Switchboard - easy and super light weight A/B testing for your mobile iPhone or android app. This mobile A/B testing framework allows you with minimal servers to run large amounts of mobile users.

Switchboard - easy A/B testing for your mobile app What it does Switchboard is a simple way to remote control your mobile application even after you'v

TTProgressHUD is a light weight HUD written in SwiftUI meant to display the progress of an ongoing task on iOS.
TTProgressHUD is a light weight HUD written in SwiftUI meant to display the progress of an ongoing task on iOS.

TTProgressHUD TTProgressHUD is a light weight HUD written in SwiftUI meant to display the progress of an ongoing task on iOS. TTProgressHUD (left) was

Light weight charts view generater for iOS. Written in Swift.
Light weight charts view generater for iOS. Written in Swift.

# ###Light weight charts view generater for iOS. Written in Swift. Requirements iOS 8.0+ XCode 7.3+ Installation CocoaPods $ pod init specify it in yo

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

Gestalt Gestalt is an unintrusive and light-weight framework for application theming with support for animated theme switching. Usage Let's say you wa

Custom camera with AVFoundation. Beautiful, light and easy to integrate with iOS projects.

🚨 Warning This repository is DEPRECATED and not maintained anymore. Custom camera with AVFoundation. Beautiful, light and easy to integrate with iOS

A light weight & simple & easy camera for iOS by Swift.
A light weight & simple & easy camera for iOS by Swift.

DKCamera Description A light weight & simple & easy camera for iOS by Swift. It uses CoreMotion framework to detect device orientation, so the screen-

Demo project to sync color changes to an Raspberry Pi Mood Light via iOS/Android
Demo project to sync color changes to an Raspberry Pi Mood Light via iOS/Android

Raspberry Pi Mood Light Demo project to remotely control an Raspberry Pi Mood Light over Bluetooth via iOS and Android. 📺 Watch the video Overview In

A light-weight, extensible package for building pixel-perfect iOS settings screens.
A light-weight, extensible package for building pixel-perfect iOS settings screens.

SettingsKit A light-weight, extensible package for easily building pixel-perfect iOS settings screens in a pinch. Installation SettingsKit can be inst

Light weight tool for detecting the current device and screen size written in swift.
Light weight tool for detecting the current device and screen size written in swift.

Device detect the current  device model and screen size. Installation CocoaPods Device is available through CocoaPods. To install it, simply add the

💡 A light Swift wrapper around Objective-C Runtime
💡 A light Swift wrapper around Objective-C Runtime

A light wrapper around Objective-C Runtime. What exactly is lumos? lumos as mentioned is a light wrapper around objective-c runtime functions to allow

DIContainer Swift is an ultra-light dependency injection container made to help developers to handle dependencies easily. It works with Swift 5.1 or above.

🏺 DIContainer Swift It is an ultra-light dependency injection container made to help developers to handle dependencies easily. We know that handle wi

A light-weighted Promise library for Objective-C

RWPromiseKit Desiciption A light-weighted Promise library for Objective-C About Promise The Promise object is used for deferred and asynchronous compu

Light and scrollable view controller for tvOS to present blocks of text
Light and scrollable view controller for tvOS to present blocks of text

TvOSTextViewer Light and scrollable view controller for tvOS to present blocks of text Description TvOSTextViewer is a view controller to present bloc

Light wrapper of UIButton that allows extra customization for tvOS
Light wrapper of UIButton that allows extra customization for tvOS

FocusTvButton Light wrapper of UIButton that allows extra customization for tvOS If you would like to have the same level of customization in tablevie

Light wrapper of UITableViewCell that allows extra customization for tvOS
Light wrapper of UITableViewCell that allows extra customization for tvOS

TvOSCustomizableTableViewCell Light wrapper of UITableViewCell that allows extra customization for tvOS If you would like to have the same level of cu

A feature-light wrapper around Core Data that simplifies common database operations.
A feature-light wrapper around Core Data that simplifies common database operations.

Introduction Core Data Dandy is a feature-light wrapper around Core Data that simplifies common database operations. Feature summary Initializes and m

Light-weight, operator-overloading-free complements to CoreGraphics!

Graphicz 🎨 Light-weight, operator-overloading-free complements to CoreGraphics! Even though I shipped it with my app, I still need to invest the time

Light weight tool for detecting the current device and screen size written in swift.
Light weight tool for detecting the current device and screen size written in swift.

Device detect the current  device model and screen size. Installation CocoaPods Device is available through CocoaPods. To install it, simply add the

Comments
  • Localization

    Localization

    Hello,

    First of all thanks for the library 👍

    How can i set opitons titles of AmbienceObject ActionSheet, programmatically?

    I dont want to localize the storyboards. I already have one localization file and all localizations are handled programmaticly in my project.

    Best

    opened by ergunkocak 1
  • Not working in code

    Not working in code

    It is not working when i tried it with my views written programmatically

    label.ambience = true
    label.contrastColor = .blue
    label.invertColor = .green
    
    opened by sagaya 3
  • public override func ambience(_ notification : Notification) method not called

    public override func ambience(_ notification : Notification) method not called

    Hi , i am trying implementing the above method and in contrast to the example you gave, in my project it is not called but the color do change accordingly to what i fixed in the story board, any suggestions? (using swift 4 and xcode 9.3 ) thanks in advanced !

    opened by roei46 4
Releases(0.1.2)
  • 0.1.0(Jan 13, 2018)

    Ambience persists over app sessions using UserDefaults and also anchors its Ambience Object popover to the sender being it either a UIView or a Bar Button Item

    Source code(tar.gz)
    Source code(zip)
  • 0.0.6(Jan 10, 2018)

  • 0.0.5(Jan 6, 2018)

    Known issues

    Text View inside Collection

    If you are using a Text View inside a Table View Cell or a Collection View Cell and, in the process of dequeuing it you set its attributed text, beware. Right after assigning the new Attributed Text will need to write a mandatory single line of code to have Ambience work in the Text View properly.

    Follow the example:

    
    // Inside the respective Table View Controller
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell : TextTableCell! = tableView.dequeueReusableCell(withIdentifier: "Cell with text") as! TextTableCell
        
        cell.textView?.reinstateAmbience()
        
        return cell
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 0.0.2(Jan 4, 2018)

    This release adds support for user control using forced states.

    This is procured using a UI Alert View Controller associated to a Storyboard Scene or by simply instantiating a Ambience Object, setting it's view controller and asking it to present the Alert View Controller.

    Source code(tar.gz)
    Source code(zip)
  • 0.0.1(Jan 3, 2018)

    0.0.1 Bare minimal

    Ambience has built-in support for the background color for the following Interface Builder objects:

    • View and all its children;
    • Search, Navigation and Tab bars and all of its children;
    • Text View, Button, and Label and all of its children.

    There is also support for the text color for:

    • Text View, Button, and Label and all of its children.

    Custom Behaviors

    It's also possible to define custom Ambience behavior on any Object that inherits from NSObject. Follow the instructions.

    Define an Override of the Ambience Method

    In this example, we are implementing the current behavior for Search, Navigation and Tab bars. It guards the notification data for the current state as an Ambience State and sets the bar style accordingly.

    public override func ambience(_ notification : Notification) {
        
        super.ambience(notification)
        
        guard let currentState = notification.userInfo?["currentState"] as? AmbienceState else { return }
        
        barStyle = currentState == .invert ? .black : .default
    }
    

    The notification user info dictionary also comes with the previous state so that more complex stateful behaviors can be implemented. It may also come with an animated boolean attribute the is usually set to true and, at the first run, set to false so as not to have animation upon view appearance.

    Turning Ambience On

    If your object is set on Interface Builder, use the Attributes Inspector and set to On the Ambience value.

    In case you are setting this object programmatically, just set its ambience boolean value to true before placing it.

    Source code(tar.gz)
    Source code(zip)
Owner
Tiago Mergulhão
Tiago Mergulhão
Guidelines for iOS development in use at Spotify

Spotify Objective-C Coding Style Version: 0.9.0 Our general coding conventions at Spotify are documented on an internal wiki, but specifics for Object

Spotify 239 Nov 11, 2022
Good ideas for iOS development, by Futurice developers.

iOS Good Practices Just like software, this document will rot unless we take care of it. We encourage everyone to help us on that – just open an issue

Futurice 10.7k Dec 29, 2022
Automatically set your keyboard's backlight based on your Mac's ambient light sensor.

QMK Ambient Backlight Automatically set your keyboard's backlight based on your Mac's ambient light sensor. Compatibility macOS Big Sur or later, a Ma

Karl Shea 29 Aug 6, 2022
This project is built to show how to support accessibility features in iOS applications in UIKit.

ACCESSIBILITY EXAMPLE This project is built to show how to support accessibility features in iOS applications in a blog post. For the sake of Accessib

iremkaraoglu 4 Aug 12, 2022
SwiftUICharts - A simple line and bar charting library that supports accessibility written using SwiftUI.

SwiftUICharts - A simple line and bar charting library that supports accessibility written using SwiftUI.

Majid Jabrayilov 1.4k Jan 9, 2023
Keep track of accessibility settings, leverage high contrast colors, and use scalable fonts to enable users with disabilities to use your app.

Accessibility for iOS, macOS, tvOS, and watchOS ?? What's new in Capable 2.0 ?? Here are the most important changes: ?? New framework architecture and

Christoph Wendt 230 Jan 4, 2023
Accessibility Abstraction Layer (axabl) for macOS window management

axabl accessibility abstraction layer axabl is an abstraction layer over the accessibility API (and more) provided by Apple to make window management

null 2 Jul 31, 2022
FlightLayout is a light weight, and easy to learn layout framework as an extension of the UIView.

FlightLayout Introduction FlightLayout is a light weight, and easy to learn layout framework as an extension of the UIView. Functionally, it lives som

Anton 23 Apr 21, 2022
A light-weight server-side service framework written in the Swift programming language.

Smoke Framework The Smoke Framework is a light-weight server-side service framework written in Swift and using SwiftNIO for its networking layer by de

Amazon 1.4k Dec 22, 2022
A light-weight TDD / BDD framework for Objective-C & Cocoa

Specta A light-weight TDD / BDD framework for Objective-C. FEATURES An Objective-C RSpec-like BDD DSL Quick and easy set up Built on top of XCTest Exc

Specta / Expecta 2.3k Dec 20, 2022