RVS_Spinner

@available(iOS 13.0, *)
@IBDesignable
open class RVS_Spinner : UIControl, UIPickerViewDelegate, UIPickerViewDataSource

This is a “spinner” control, which acts a bit like a circular UIPickerView.

However, instead of having the values provided by a delegate/datasource, the values are associated directly with the control in an Array.

This control has a lot of “little things” to make it usable and intuitive. It has “inertia,” where you can start it spinning, it has “one-tap increment/decrement,” and it has haptic and audio feedback.

It can switch between the circular spinner, and a standard UIPickerView, if there are too many items to handle efficiently in a spinner. You can choose to either always use the picker, or never use the picker.

There is a delegate protocol, and the control will also emit “valueChanged” messages (the selected item changed), and “touchUpInside” messages (the center was tapped).

Public Properties

  • This is an optional delegate object that can be informed of selected values.

    This cannot be made inspectable, because the delegate class is not one that can be accessed as ObjC.

    Declaration

    Swift

    public weak var delegate: RVS_SpinnerDelegate?
  • This is the display font that we’ll use in the picker. Default is system bold 20. It can be overridden.

    Declaration

    Swift

    public var displayFont: UIFont? { get set }
  • This is the selected index of the value Array. It is 0-based.

    Declaration

    Swift

    public var selectedIndex: Int { get set }
  • This property represents the values to be selected and displayed by the spinner. Instead of a datasource, we use an instance property. This can be overloaded to make it dynamic. At minimum, each value needs an icon to be displayed. Optionally, it can have a title String, a description String, with more information, and abritrary associated data. The associated data is an “Any?” item. It can be anything (or nothing). It is up to the implementor to cast and manage this. This is just a “context hook.” The order is not changed by the spinner. Values are displayed in the order they are set in this Array, clockwise.

    Declaration

    Swift

    public var values: [RVS_SpinnerDataItem] { get set }
  • If this is true, then the spinner is open. Setting this will open or close the control. Default is false.

    Declaration

    Swift

    public var isOpen: Bool { get set }
  • If this is true, then center of the spinner will rotate against any rotation applied to its container, making it “straight up.” Default is true.

    Declaration

    Swift

    public var isCompensatingForContainerRotation: Bool { get set }

Public Calculated Propeties

  • This calculated property will return either the currently selected item, or nil. READ-ONLY

    Declaration

    Swift

    public var value: RVS_SpinnerDataItem? { get }
  • If we have either a border color (tint), or a background color, then we display the icons enclosed in a frame. If that is the case, then the icon is displayed slightly smaller. READ-ONLY

    Declaration

    Swift

    public var framedIcons: Bool { get }

    Return Value

    True, if the images should be framed.

  • Declaration

    Swift

    public var opensAsSpinner: Bool { get }

    Return Value

    True, if the control will open as a spinner (as opposed to a picker). READ-ONLY

  • Declaration

    Swift

    public var count: Int { get }

    Return Value

    The number of values. READ-ONLY

  • Declaration

    Swift

    public var isEmpty: Bool { get }

    Return Value

    Yes, we have no bananas. READ-ONLY

Public Enums

  • This is just a convenient way to denote the spinner modes.

    See more

    Declaration

    Swift

    public enum SpinnerMode : Int

Public Overridden IB Properties

  • This is the background color associated with the “closed” control. We use the UIView’s backgroundColor as the source.

    This is set from the view background color.

    Declaration

    Swift

    public override var backgroundColor: UIColor? { get set }
  • This is the tint color , which governs the display of the border, and of text in the picker.

    This is set from the view background color.

    Declaration

    Swift

    public override var tintColor: UIColor? { get set }

Public IB Properties

  • This is the background color associated with the “open” control “pie-slices.” Default is nil (clear).

    Declaration

    Swift

    @IBInspectable
    public var openBackgroundColor: UIColor? { get set }
  • This is the spinner mode. It determines which control is displayed when the spinner is open.

    • both (default) is 0 The spinnerThreshold is used to determine which will be displayed.
    • radial spinner only is -1
    • picker only is 1

    Declaration

    Swift

    @IBInspectable
    public var spinnerMode: Int { get set }
  • This is the maximum number of elements that can be displayed in a spinner. Above this, needs to be displayed in a picker. Default is 15.

    Declaration

    Swift

    @IBInspectable
    public var spinnerThreshold: Int { get set }
  • If true, the control will play sounds. Default is true.

    Declaration

    Swift

    @IBInspectable
    public var isSoundOn: Bool
  • If true, the control will play haptics (on devices that support haptics). Default is true.

    Declaration

    Swift

    @IBInspectable
    public var isHapticsOn: Bool
  • This is an alternative fixed center image. If left alone, the selected value image will be used. Default is nil (use selected value image).

    Declaration

    Swift

    @IBInspectable
    public var centerImage: UIImage? { get set }
  • If true, then the various options will be set to emulate a “HUD” display. Default is false.

    Declaration

    Swift

    @IBInspectable
    public var hudMode: Bool { get set }
  • If true, and an explicit image has been assigned to the center, when the cotrol is opened, the image will be replaced with the current selection. This is ignored, if centerImage is nil. Default is false.

    Declaration

    Swift

    @IBInspectable
    public var replaceCenterImage: Bool { get set }

Required Init

  • The NSCoder init.

    Declaration

    Swift

    required public init?(coder inDecoder: NSCoder)

    Parameters

    coder

    The decoder with the view state.

Public Overrides

  • This is called when the control is about to be drawn.

    Declaration

    Swift

    override public func draw(_ inRect: CGRect)

    Parameters

    inRect

    The rect to be drawn into.

  • This is required for a designable.

    Declaration

    Swift

    override public init(frame inRect: CGRect)

    Parameters

    frame

    The new frame for the view.

  • This is called when we start tracking a pan.

    Declaration

    Swift

    override public func beginTracking(_ inTouch: UITouch, with inEvent: UIEvent?) -> Bool

    Parameters

    inTouch

    The touch object associated with this event.

    with

    The event that triggered this.

  • This is called repeatedly while we are tracking a pan. We just make sure that we keep updating the display.

    Declaration

    Swift

    override public func continueTracking(_ inTouch: UITouch, with inEvent: UIEvent?) -> Bool

    Parameters

    inTouch

    The touch object associated with this event.

    with

    The event that triggered this.

  • We end the tracking, and make sure that we update the display properly.

    Declaration

    Swift

    override public func endTracking(_ inTouch: UITouch?, with inEvent: UIEvent?)

    Parameters

    inTouch

    The touch object associated with this event.

    with

    The event that triggered this.

  • We cancel the tracking, and make sure that we update the display.

    Declaration

    Swift

    override public func cancelTracking(with inEvent: UIEvent?)

    Parameters

    with

    The event that triggered this.

  • This is called before the subviews (aren’t any) will get laid out. We use it to switch out the background color. We use the set background color as the “closed” control background color. We use the tint color as the border color.

    Declaration

    Swift

    override public func layoutSubviews()

Public Instance Methods

  • A convenience init with a preset values array and value.

    Declaration

    Swift

    public convenience init(values inValuesArray: [RVS_SpinnerDataItem]? = nil, selectedIndex inSelectedIndex: Int = 0, frame inFrame: CGRect = CGRect.zero, spinnerMode inSpinnerMode: SpinnerMode = .both, delegate inDelegate: RVS_SpinnerDelegate? = nil)

    Parameters

    values

    The values to be associated with the control. It is optional, and default is nil.

    selectedIndex

    An initial selected index for the control. It is 0-based, and optional. Default is 0.

    frame

    Any initial frame for the control. It is optional, and default is an empty frame.

    spinnerMode

    An integer, eith -1 (Spinner only), 0 (Both), or 1 (Picker only). It is optional, and default is 0 (Both).

    delegate

    A delegate instance for the spinner. It is optional, and default is nil.

  • A convenience “quiet” init.

    Declaration

    Swift

    public convenience init()

Public UIPickerViewDataSource/Delegate Protocol Methods

  • Simple number of components response (always 1)

    Declaration

    Swift

    public func numberOfComponents(in inPickerView: UIPickerView) -> Int

    Parameters

    in

    The UIPickerView doing the querying.

  • This returns how many rows will be displayed by the pickerview.

    Declaration

    Swift

    public func pickerView(_ inPickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int

    Parameters

    inPickerView

    The pickerview doing the querying.

    numberOfRowsInComponent

    The 0-based index (always 0, and ignored) of the component we are asking after.

  • Declaration

    Swift

    public func pickerView(_ inPickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat

    Parameters

    inPickerView

    The pickerview doing the querying.

    rowHeightForComponent

    The 0-based index (always 0, and ignored) of the component we are asking after.

    Return Value

    float, with the row height for that component.

  • This builds one row view, including the icon and the text. It will center them over the center of the Spinner.

    Declaration

    Swift

    public func pickerView(_ inPickerView: UIPickerView, viewForRow inRow: Int, forComponent inComponent: Int, reusing inView: UIView?) -> UIView

    Parameters

    inPickerView

    The pickerview doing the querying.

    viewForRow

    the 0-based index of the row (used to index our values).

    forComponent

    The 0-based index (always 0, and ignored) of the component we are asking after.

    reusing

    The view object to reuse.

    Return Value

    a new (or refurbed) view object.

  • This is called when a row is selected in the picker.

    Declaration

    Swift

    public func pickerView(_ inPickerView: UIPickerView, didSelectRow inRow: Int, inComponent: Int)

    Parameters

    inPickerView

    The pickerview doing the querying.

    didSelectRow

    the 0-based index of the row (used to index our values).

    inComponent

    The 0-based index (always 0, and ignored) of the component we are asking after.