Files
LCEssentials/Documentation/UIKit.md
2026-08-29 19:32:31 -03:00

14 KiB

LCEssentials — UIKit

UIKit-era helpers: programmatic layout & constraints, view/control extensions, navigation, table/collection helpers, and drop-in components (image picker, image zoom, snackbar, GIF loading).

Foundation/value-type helpers are in Extensions.md; SwiftUI helpers in SwiftUI.md.

Every section is a collapsible block — click a heading to expand it.

Contents


Layout & Constraints

UIView — programmatic constraints, chainable anchors

enum AnchorType

The anchor to pin when using setConstraintsTo. Cases: all, top, bottom, leading, trailing, left, right, centerX, centerY, width, heigth (sic), topToBottom, bottomToTop, leadingToTrailing, trailingToLeading, plus …GreaterThanOrEqualTo / …LessThanOrEqualTo variants.

@discardableResult func setConstraintsTo(parentView: UIView, anchorType: AnchorType, value: CGFloat, safeArea: Bool = false) -> Self

Activate one constraint against parentView. Remembers parentView (in viewReference) so follow-up calls can omit it. safeArea: true pins top/bottom to the safe-area guide (iOS 11+).

card.addSubview(label)
label.setConstraintsTo(parentView: card, anchorType: .top, value: 12, safeArea: false)
     .setConstraints(.leading, 16)
     .setConstraints(.trailing, -16)

@discardableResult func setConstraintsTo(_ parentView:_ anchorType:_ value:_ safeArea: Bool = false) -> Self

Positional-argument shorthand for the above.

@discardableResult func setConstraintsTo(anchorType: AnchorType, value: CGFloat, safeArea: Bool = false) -> UIView

Reuse the last parentView (viewReference). Traps with fatalError if no parentView was set first.

@discardableResult func setConstraints(_ anchorType: AnchorType, _ value: CGFloat, _ safeArea: Bool = false) -> UIView

Positional shorthand for the reuse form — the one you chain.

func setConstraints(_ toScrollView: UIScrollView, direction: UICollectionView.ScrollDirection = .vertical)

Pin self as the single content view of a scroll view (edges + matching width/height, with a low-priority constraint on the scroll axis). Traps if self is itself a UIScrollView.

scrollView.addSubview(content)
content.setConstraints(scrollView, direction: .vertical)

Constraint accessors

widthConstraint, heightConstraint, leadingConstraint, trailingConstraint, topConstraint, bottomConstraint, centerXConstraints, centerYConstraints — the first matching NSLayoutConstraint found by walking up the hierarchy.

box.widthConstraint?.constant = 120
UIView.animate(withDuration: 0.2) { self.view.layoutIfNeeded() }

func findConstraint(attribute: NSLayoutConstraint.Attribute, for view: UIView) -> NSLayoutConstraint?

Search self and ancestors for a constraint on attribute involving view.

func constraints(on anchor:) -> [NSLayoutConstraint]

Constraints touching a given NSLayoutYAxisAnchor / XAxisAnchor / Dimension of self.

@discardableResult func setHeight(size:) -> Self / setHeight(min:) / setWidth(size:) / setWidth(min:)

Activate a fixed or minimum dimension constraint.

avatar.setWidth(size: 44).setHeight(size: 44)

func setWidth(_ toView: UIView? = nil, constant: CGFloat, _ multiplier: CGFloat = 0) -> Self / setHeight(...)

Dimension relative to another view (multiplier) or fixed (multiplier == 0).

Frame setters

setX(x:), setY(y:), setFrameWidth(width:), setFrameHeight(height:) — mutate self.frame directly (manual layout, not Auto Layout).

UIView — hierarchy, appearance, effects

static var className: String

String(describing: self).

UIButton.className   // "UIButton"

func addSubview(_ subview:, translatesAutoresizingMaskIntoConstraints: Bool = false) / addSubviews(_ subviews: [UIView], …)

Add a view (or many) and set translatesAutoresizingMaskIntoConstraints in one call.

view.addSubviews([header, body, footer])   // all ready for Auto Layout

func subviews<T>(ofType _: T.Type) -> [T]

All descendants of a type, recursively.

formView.subviews(ofType: UITextField.self)

func findAView<T>(_ ofType: T.Type) -> T?

First descendant of a type.

var parentViewController: UIViewController?

Nearest owning view controller (walks the responder chain).

var borderColor: UIColor? / var borderWidth: CGFloat / var cornerRadius: CGFloat

Layer border/corner shortcuts (cornerRadius also sets masksToBounds).

card.cornerRadius = 12
card.borderWidth = 1
card.borderColor = .separator

func setRadius(top: Bool, bottom: Bool, radius: CGFloat = 8)

Round only the top and/or bottom corners.

sheet.setRadius(top: true, bottom: false, radius: 16)

func applyShadow(color:offSet:radius:opacity:shouldRasterize: Bool = true, rasterizationScaleTo: = UIScreen.main.scale) / func removeShadow()

Layer shadow with rasterisation on by default.

card.applyShadow(color: .black, offSet: CGSize(width: 0, height: 2),
                 radius: 6, opacity: 0.15)

func insertBlurView(style: UIBlurEffect.Style, color: UIColor = .black, alpha: CGFloat = 0.9)

Insert a full-bleed UIVisualEffectView behind the content.

func drawCircle(inCoord x:y:with radius:strokeColor: = .red, fillColor: = .gray, isEmpty: Bool = false) -> [String: Any]

Add a circular CAShapeLayer; returns ["path": UIBezierPath, "layer": CAShapeLayer].

var isRightToLeft: Bool

Effective RTL layout direction.

var screenshot: UIImage? / func asImage() -> UIImage

Render the view to an image (screenshot via the legacy context, asImage via UIGraphicsImageRenderer).

let png = chartView.asImage().pngData()

var globalPoint: CGPoint? / var globalFrame: CGRect? / var absolutePosition: CGRect

Origin/frame converted to window coordinates.

func fadeIn(withDuration: TimeInterval = 1, withDelay: TimeInterval = 0, completionHandler: @escaping (Bool) -> Void) / func fadeOut(...)

Animate alpha to 1 / 0. (Completion-handler API — pre-dates async/await.)

overlay.fadeOut { _ in overlay.removeFromSuperview() }

var viewReference: UIView?

Scratch reference used internally by the chained setConstraintsTo calls.

GradientOrientation / EnumBorderSide

enum GradientOrientation

topRightBottomLeft, topLeftBottomRight, horizontal, vertical — maps to a CAGradientLayer start/end point pair. Passed to gradient helpers elsewhere in the package.

enum EnumBorderSide

top, bottom, left, right — which edge to draw a single-side border on.

UIStackView — convenience init, bulk arranged-subview ops (iOS 9+)

convenience init(arrangedSubviews: [UIView]? = nil, axis: = .vertical, spacing: = 0, alignment: = .fill, distribution: = .fill, layoutMargins: = .zero, isMarginsRelative: Bool = true)

One-call configured stack view.

let stack = UIStackView(arrangedSubviews: [title, subtitle],
                        axis: .vertical, spacing: 4)

func addArrangedSubviews(_ views: [UIView], translateAutoresizing: Bool = false)

Add many arranged subviews, setting their autoresizing flag.

func removeAllArrangedSubviews(deactivateConstraints: Bool = true)

Remove and dispose every arranged subview.

func removeSubview(view: UIView, deactivateConstraints: Bool = true)

Remove one arranged subview (optionally deactivating its constraints and removing from the hierarchy).

func addSpace(_ size: CGFloat, backgroundColor: UIColor = .clear)

Insert a fixed-size spacer view sized along the stack's axis.

stack.addArrangedSubviews([row1, row2])
stack.addSpace(24)
stack.addArrangedSubview(row3)

NSLayoutConstraint helpers (constraintWithMultiplier, matches(view:anchor:)) and [NSLayoutConstraint].filtered(view:anchor:) are internal — used by the UIView.constraints(on:) accessors above, not called directly.

Views & Controls

UIButton — per-state accessors, all-state setters

Per-state properties

imageForNormal / imageForHighlighted / imageForSelected / imageForDisabled, titleForNormal / …Highlighted / …Selected / …Disabled, titleColorForNormal / …Highlighted / …Selected / …Disabled — get/set shortcuts for the matching UIControl.State (also @IBInspectable).

button.titleForNormal = "Save"
button.titleColorForDisabled = .tertiaryLabel

func setTitleForAllStates(_:) / func setTitleColorForAllStates(_:) / func setImageForAllStates(_:)

Apply one value to .normal, .selected, .highlighted, .disabled at once.

button.setTitleColorForAllStates(.white)

func centerTextAndImage(spacing: CGFloat)

Balance title/image edge insets so text + icon sit centred with spacing between them.

button.centerTextAndImage(spacing: 8)
UILabel

func lineNumbers() -> Int

Rendered line count at the current width.

if bodyLabel.lineNumbers() > 3 { showMoreButton() }

var getEstimatedHeight: CGFloat

Height the label would need to show its full text/attributed text unclipped.

UITextField

var placeholderColor: UIColor

Get/set the placeholder text colour (rebuilds attributedPlaceholder; setter is a no-op if no placeholder text is set).

field.placeholder = "Email"
field.placeholderColor = .secondaryLabel

func addPaddingLeft(_ padding: CGFloat)

Inset the text from the left with an empty spacer view.

func addPaddingLeftIcon(_ image: UIImage, padding: CGFloat)

Left view = an icon plus trailing padding.

field.addPaddingLeftIcon(UIImage(systemName: "magnifyingglass")!, padding: 8)
UIImageView (@MainActor)

func changeColorOfImage(_ color: UIColor, image: UIImage?) -> UIImageView

Set a template-rendered image tinted to color; returns self.

iconView.changeColorOfImage(.systemBlue, image: UIImage(named: "star"))

var encodeToBase64: String?

JPEG (quality 0.6) of the current image as a Base64 string.

func addAspectRatioConstraint() / func removeAspectRatioConstraint()

Add / remove a width-to-height constraint matching the current image's ratio.

photoView.image = photo
photoView.addAspectRatioConstraint()
UIImage — recolour, resize, thumbnails, masks, init

func imageWithColor(color: UIColor) -> UIImage / func tintImage(color: UIColor) -> UIImage

Return a copy filled / tinted with color (keeps the alpha shape).

let redIcon = icon.tintImage(color: .systemRed)

func backgroundColorTransparent(initialColor: UIColor, finalColor: UIColor) -> UIImage?

Make pixels in a colour range transparent.

class func outlinedEllipse(size: CGSize, color: UIColor, lineWidth: CGFloat = 1) -> UIImage?

Generate a stroked-ellipse image.

UIImage.outlinedEllipse(size: CGSize(width: 24, height: 24), color: .label)

func resizeImage(newWidth: CGFloat) -> UIImage

Scale to newWidth, keeping the aspect ratio.

func createThumbnail(_ maxPixelSize: UInt) -> UIImage

Fast down-sampled thumbnail via CGImageSource.

let thumb = fullImage.createThumbnail(200)

func maskWithAlphaImage(maskImage: UIImage) -> UIImage

Use another image's alpha as a mask.

func isAnimated() -> Bool

Whether the image has more than one frame.

init?(base64String: String, scale: CGFloat = 1)

Decode a Base64 string to an image.

init(view: UIView)@MainActor

Rasterise a view into an image.

let snapshot = UIImage(view: cardView)
UIColor — hex, components

convenience init(hex: String)

Parse #RGB, #RGBA, #RRGGBB, or #RRGGBBAA (with or without #).

view.backgroundColor = UIColor(hex: "#1E88E5")
UIColor(hex: "FF0000CC")   // red at 80% alpha

var hexString: String?

#RRGGBB (or #RRGGBBAA when alpha < 1).

var redValue / var greenValue / var blueValue / var alphaValue

Individual channel values (CGFloat, via CIColor).

UIColor.systemBlue.redValue   // 0.0…1.0
UIScrollView — snapshot, visible rect, paged scrolling

var snapshot: UIImage?

Image of the entire content size (not just the visible part) — works on UITableView / UICollectionView too.

var visibleRect: CGRect

The currently visible content region.

var offsetInPage: CGFloat

Fractional position within the current page height (0.01.0).

func scrollUp(animated:) / scrollDown(animated:) / scrollLeft(animated:) / scrollRight(animated:)

Move one page (respects isPagingEnabled). animated defaults to true.

nextButton.onTap = { scrollView.scrollRight() }

enum orientation

horizontal / vertical — helper enum used by scroll utilities.

UITapGestureRecognizer

func didTapAttributedTextInLabel(label: UILabel, textToTouch: String) -> Bool

Whether the tap landed on a given substring of a label's attributed text — for making part of a label tappable.

@objc func handleTap(_ g: UITapGestureRecognizer) {
    if g.didTapAttributedTextInLabel(label: termsLabel, textToTouch: "Terms of Use") {
        openTerms()
    }
}

Navigation & Controllers

Collections & Tables

Media & Components