Stylish v0.9.2 Release Notes

Release Date: 2018-10-03 // over 5 years ago
  • Compatibility Note:

    ๐Ÿš€ This release has breaking API changes for projects which have create their own custom Styleable components or which for some other reason call Stylish.applyStyleNames() directly. The first change is an addition to the Styleable protocol which now requires a get/set property stylesheet: String?. For Stylish's built-in styleable components as well as for custom components, this should be implemented as an IBInspectable property. The didSet for this property (as well as for the existing styles property) should simply call through to Stylish like this:

    @IBDesignable class CustomStyleableView: UIView, Styleable {
        @IBInspectable public var styles: String = "" {
            didSet {
                Stylish.applyStyleNames(styles, to: self, using: stylesheet)
            }
        }
        @IBInspectable public var stylesheet: String? = nil {
            didSet {
                Stylish.applyStyleNames(styles, to: self, using: stylesheet)
            }
        }
    }
    

    ๐Ÿ’… The second change is the new using stylesheet: String? parameter for the applyStyleNames() method above. For any places where this method was being called that wasn't in a custom component didSet as above, the existing behavior will be maintained by simply passing nil for the parameter.

    ๐Ÿ†• NEW: Cascading Stylesheet Overrides

    ๐Ÿ’… Until now, the most recent versions of Stylish have used a single global stylesheet which gets set for IBDesignable preview in the prepareForInterfaceBuilder() override, or in the app at startup (or anytime the global style should change).

    ๐Ÿ’… The single global stylesheet was used to apply all the styles set on all UI elements in the app.

    With this update, styleable components get a new inspectable property called stylesheet in Interface Builder and in code. The default value is nil, which uses the global stylesheet as usual. But setting a non-nil value on a styleable component will cause that component and all its descendant views to use that override stylesheet instead of the global stylesheet.

    ๐Ÿ’… In practical terms, this is useful for when apps have a light color scheme and a dark color scheme, with specific styling for buttons, text, etc. within each. Now, it's possible to set a single section of the screen to use one color scheme (and cascade that scheme down through its subviews) while the rest of the screen or app uses the other. This is also useful for A/B testing, user customization, or other scenarios where the whole app should retain its usual style, but some sub-section of it needs to use a secondary or tertiary stylesheet.

    ๐Ÿ’… In terms of organization this is also a win. Instead of a single monolithic stylesheet with styles named along the lines of:

    primaryBackground
    secondaryBackground
    primaryTextOnPrimaryBackground
    secondaryTextOnPrimaryBackground
    primaryTextOnSecondaryBackground
    secondaryTextOnSecondaryBackground

    etc.

    ๐Ÿ’… You can now have two stylesheets:

    ๐Ÿ’… ####Primary Stylesheet
    background
    primaryText
    secondaryText

    ๐Ÿ’… ####Secondary Stylesheet
    background
    primaryText
    secondaryText

    ๐Ÿ’… And instead of assigning the primaryTextOnSecondaryBackground style to labels, you can simply assign all labels either "primaryText" or "secondaryText" and then override the stylesheet for the section they are in to be "Secondary" if you wish to flip a group of labels to the "primary text on secondary background" style.

    ๐Ÿ’… Registering Stylesheets

    ๐Ÿ’… In order to connect the override stylesheet names you provide in Interface Builder or set in code to actual Stylesheets, you must register them with Stylish. To see override stylesheets working and cascading in Interface Builder / IB Designable previews, you must add this registration to your prepareForInterfaceBuilder() override, where you also set the global stylesheet, for example:

    extension UIView {
        // This is the only entry point for setting global variables in Stylish for Interface Builder rendering (since App Delegate doesn't get run by IBDesignable. So we are setting up the global stylesheet that we want used for IBDesignable rendering here.
        open override func prepareForInterfaceBuilder() {
            Stylish.stylesheet = Graphite()
            Stylish.register(stylesheet: Graphite(), named: "Graphite")
            Stylish.register(stylesheet: Aqua(), named: "Aqua")
            Stylish.register(stylesheet: JSON(), named: "JSON")
        }
    }
    

    ๐Ÿ’… In the above example, you could now use the override stylesheet names "Graphite", "Aqua" and "JSON" in your storyboards to use a different stylesheet for some section of the screen.

    ๐Ÿ’… Don't forget to also register the same stylesheets in your App Delegate or somewhere similar so they are also available at runtime (not just for Interface Builder previews!)

    Approaching v1.0

    Based on feedback, Stylish is being used successfully in a lot of real-world projects now. It feels like it's about time to officially call it a version 1.0, suitable for use in most applications. If you have encountered any issues or have concerns as to why it might not be ready for prime time, please get in touch!