open class FUIButton : UIButton, FUIButtonClosureHandling, FUIStateSelectable, FUIBackgroundSchemeSupporting, PrepareForReuse

Subclass of UIButton, which provides for rounded edge and rounded fill styles. It also provides for per-state tint colors, persistent selection, and a closure-styled tap handler.

The FUIButton implements the Fiori Design Language in default configuration.



Init button with expected style (for default, use .none).

To use FUIButton style variants in Interface Builder, the convenience subclasses FUIRoundedButton (.fuiRounded) and FUIRoundedFillButton (.fuiRoundedFilled) are also available.

// init with expected style.

let normalButton = FUIButton() // equivalent to FUIButton(style: .none)
let roundedOutlineButton = FUIButton(style: .fuiRounded)       // equivalent to `FUIRoundedButton()`
let roundedFilledButton = FUIButton(style: .fuiRoundedFilled)  // equivalent to `FUIRoundedFillButton()`

Setting title(s)

UIButton provides two techniques for setting its title:

  1. setTitle(_:, for:)
  2. titleLabel.text

The behavior of the (2) is inconsistent, and discouraged by Apple. As a result, titleLabel.text should be avoided in favor of technique setTitle(_:_:). The FUIButton will correct the behavior of titleLabel.text, if setTitle(_:_:) is not used. However, if the developer at any point invokes setTitle(_:, for:) directly, FUIButton will cease to correct for titleLabel.text, and will defer to the developer to use the API correctly.

button.setTitle("Follow", for: .normal)
button.setTitle("Unfollow", for: .selected)

Specify Selection Behavior

The default behavior of UIButton is to toggle between .normal and .highlighted UIControlState, on user touches started and touches ended. The .selected state is never used.

FUIButton supports toggling between .normal and .selected UIControlState, by setting the isPersistentSelection flag to true. This is particularly useful, if using the button to toggle a property. The developer may use the isSelected: Bool API to toggle cause this transition.

button.isPersistentSelection = true    // causes button to toggle between `.normal` and `.selected` states on user touch

When isPersistentSelection == true, the button may transition briefly through the .highlighted state, between .selected and .normal on user touches. Configure settings for [.selected, .highlighted], if implementing custom behavior here.

Color Configuration

Call setTintColor(_:_:) to configure tint color for states. Setting tintColor is equivalent to call setTintColor(color, for: UIControlState.normal). Default tintColor is UIColor.preferedFioriColor(for: .tintColor, background: self.backgroundColorScheme).

// set the `.normal` and `.disabled` tint colors
button.setTintColor(.preferredFioriColor(forStyle: .tintColor), for: .normal)
button.setTintColor.setTintColor(.preferredFioriColor(forStyle: .primary4), for: .disabled)

// set *either* the `.highlighted` or `.selected` tint colors
button.setTintColor(UIColor.preferredFioriColor(forStyle: .tintColorTapState), for: .highlighted)
// --or--
button.setTintColor.setTintColor(UIColor.preferredFioriColor(forStyle: .tintColorTapState), for: .highlighted)

These tint colors will be applied differently, depending upon the .style of the button. In the .fuiRounded style, the tint is applied to the layer edge and titleLabel.textColor; in the .fuiRoundedFill style, the tint is applied to the background color.

In any style, you may choose to override the background color for state, which is useful for applying an inverted style.

button.setBackgroundColor(UIColor.preferredFioriColor(forStyle: .tintColorLight), for: .highlighted)

The FUIButton also implements the FUIBackgroundSchemeSupporting protocol, which enables developers to inform the control whether it is being presented against a ‘light’ background, or ‘dark’ background. The default style of the button will adapt to the background color scheme; defaults to .light.

Size Calculation

The FUIButton calculates an intrinsicContentSize from its imageView and titleLabel, its various insets, and its layoutMargins.

To manage the width of the text in the titleLabel, use the regular UILabel API to configure the wrapping behavior.

button.titleLabel?.preferredMaxLayoutWidth = 200
button.titleLabel?.lineBreakMode = .byWordWrapping

As an additional configuration option, the FUIButton provides a flag isPreservingPreferredMaxLayoutWidth, which uses the preferredMaxLayoutWidth as a minimum width for the titleLabel when calculating intrinsicContentSize. This is useful, when implementing a fixed-width button with variable texts, or toggling variable-width texts on state.

Note: This will not affect the titleLabel text wrapping behavior.

button.isPreservingPreferredMaxLayoutWidth = true

Selection handler:

Optional closure-based substitute for addTarget(_:_:_:) method for handling user taps. Passes self as input parameter. Is compatible with addTarget(_:_:_:) selector registration.

If used in combination with the target-action selector registration, handlers will be invoked in the following order:

  1. didSelectHandler
  2. target-action selector


Support Button class paths:

Button {}
fdlFUIButton {}

Supported Button attributes:

tint-color { -selected | -highlighted | -selected-highlighted | -selected-disabled | -disabled } (Color)
background-color { -normal | -selected | -highlighted | -selected-highlighted | -selected-disabled | -disabled } (Color)
background-image { -selected | -highlighted | -selected-highlighted | -selected-disabled | -disabled } (Image)
content-insets (Box)
image-insets (Box)
title-insets (Box)
shadow-color (Color)
shadow-offset (Offset)
shadow-opacity (Number)
shadow-radius (Number)

Supported Text attributes:

font-color { -selected | -highlighted | -selected-highlighted | -selected-disabled | -disabled } (Color)
font-name (FontName)
font-style (UIFontTextStyle)
font-size (Number)
text-align (TextAlign)
text-alpha (Number)
text-auto-fit (Boolean)
text-line-clamp (Integer)
text-shadow-color { -selected | -highlighted | -selected-highlighted | -selected-disabled | -disabled } (Color)
text-shadow-offset (Offset)

Supported ImageView attributes:

image { -highlighted | -selected | -selected-highlightecd | -selected-disabled | -disabled } (Image)


The tint-color { -* } attribute will override the font-color { -* } attribute on a state-by-state basis. E.g. tint-color-highlighted will override font-color-highlighted, but will not affect font-color.
  • Specialized init method, implementing the common ‘rounded’ button style.

    Applies default contentEdgeInsets = UIEdgeInsets(top: 7, left: 16, bottom: 7, right: 16)



    public convenience init(style: FUIButtonStyle)



    { .none, .fuiRounded, .fuiRoundedFilled }

  • Initializer with type == .custom and style == .none



    public convenience init()
  • Sets button style



    public var style: FUIButtonStyle { get set }
  • Declaration


    public var backgroundColorScheme: FUIBackgroundColorScheme { get set }
  • Sets tint color for UIControlState provided.

    When style == { .none | .fuiRounded} , invokes setTitleColor(_:_:) for state, and if style is not .none, applies tint color to imageView.

    When style == .fuiRoundedFilled, invokes the setBackgroundColor(_:_:) for state.



    open func setTintColor(_ color: UIColor, for state: UIControlState)



    tint color


    control state (as determined by UIButton superclass)

  • Sets background color for UIControlState for most button configurations.



    public func setBackgroundColor(_ color: UIColor, for state: UIControlState)



    background color


    control state (as determined by UIButton superclass)

  • Sets whether the border color is appled based onUIControlState



    public func setIsApplyingBorderColor(_ value: Bool, for state: UIControlState)





    control state (as determined by UIButton superclass)

  • Optional closure handler, for responding to UIControlEvent.primaryActionTriggered.



    open var didSelectHandler: ((FUIButton) -> Void)?
  • Enables UIControlState.selected to be persisted after user tap. Requires that user re-tap button to de-select, or that developer invoke isSelected = false setter. Defaults to false.


    If set to true, button will skip UIControlState.highlighted on tap, and return UIControlState.selected, while isSelected == true.



    public var isPersistentSelection: Bool { get set }
  • Instructs the intrinsicContentSize calculation to use the button’s titleLabel?.preferredMaxLayoutWidth as the constant width of the titleLabel subview.



    public var isPreservingPreferredMaxLayoutWidth: Bool