Created
June 28, 2025 08:26
-
-
Save haojianzong/417758e36ff7530e2f1911892f983681 to your computer and use it in GitHub Desktop.
UIView+Pin.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) Microsoft Corporation. All rights reserved. | |
// | |
import Foundation | |
import UIKit | |
// A small utility for NSLayoutDimension shortcuts, easily reduce lots of auto layout codes. | |
public protocol PinObject { | |
var topAnchor: NSLayoutYAxisAnchor { get } | |
var bottomAnchor: NSLayoutYAxisAnchor { get } | |
var leadingAnchor: NSLayoutXAxisAnchor { get } | |
var trailingAnchor: NSLayoutXAxisAnchor { get } | |
} | |
extension UIView: PinObject {} | |
extension UILayoutGuide: PinObject {} | |
public extension UIView { | |
struct PinOptions: OptionSet { | |
public let rawValue: Int | |
public static let all: PinOptions = [.top, .trailing, .bottom, .leading] | |
public static let top = PinOptions(rawValue: 1 << 0) | |
public static let trailing = PinOptions(rawValue: 1 << 1) | |
public static let bottom = PinOptions(rawValue: 1 << 2) | |
public static let leading = PinOptions(rawValue: 1 << 3) | |
public init(rawValue: Int) { | |
self.rawValue = rawValue | |
} | |
} | |
/// Add layout constraints. Also sets translatesAutoresizingMaskIntoConstraints to false. | |
/// | |
/// - Parameters: | |
/// - pinObject: The pinObject that this view is pined to. Maybe a UIView or an UILayoutGuideObject | |
/// - edges: Choose which edge to pin | |
func pin(to pinObject: PinObject, edges: PinOptions, priority: UILayoutPriority) { | |
translatesAutoresizingMaskIntoConstraints = false | |
var constraints = [NSLayoutConstraint]() | |
if edges.contains(.leading) { | |
constraints.append(leadingAnchor.constraint(equalTo: pinObject.leadingAnchor)) | |
} | |
if edges.contains(.trailing) { | |
constraints.append(trailingAnchor.constraint(equalTo: pinObject.trailingAnchor)) | |
} | |
if edges.contains(.top) { | |
constraints.append(topAnchor.constraint(equalTo: pinObject.topAnchor)) | |
} | |
if edges.contains(.bottom) { | |
constraints.append(bottomAnchor.constraint(equalTo: pinObject.bottomAnchor)) | |
} | |
constraints.forEach { $0.priority = priority } | |
if !constraints.isEmpty { | |
NSLayoutConstraint.activate(constraints) | |
} | |
} | |
/// Pin to parentView edges | |
func pinEdges(to parentView: UIView, edges: PinOptions = .all, priority: UILayoutPriority = .required) { | |
pin(to: parentView, edges: edges, priority: priority) | |
} | |
/// Pin to parentView layoutMarginsGuide | |
func pinToMargins(of parentView: UIView, edges: PinOptions = .all, priority: UILayoutPriority = .required) { | |
pin(to: parentView.layoutMarginsGuide, edges: edges, priority: priority) | |
} | |
/// Pin to parentView safeAreaLayoutGuide | |
func pinToSafeArea(of parentView: UIView, edges: PinOptions = .all, priority: UILayoutPriority = .required) { | |
pin(to: parentView.safeAreaLayoutGuide, edges: edges, priority: priority) | |
} | |
func pinToEdges(of parentView: UIView, insets: UIEdgeInsets, edges: PinOptions = .all, priority: UILayoutPriority = .required) { | |
translatesAutoresizingMaskIntoConstraints = false | |
var constraints = [NSLayoutConstraint]() | |
if edges.contains(.leading) { | |
constraints.append(leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: insets.left)) | |
} | |
if edges.contains(.trailing) { | |
constraints.append(trailingAnchor.constraint(equalTo: parentView.trailingAnchor, constant: -insets.right)) | |
} | |
if edges.contains(.top) { | |
constraints.append(topAnchor.constraint(equalTo: parentView.topAnchor, constant: insets.top)) | |
} | |
if edges.contains(.bottom) { | |
constraints.append(bottomAnchor.constraint(equalTo: parentView.bottomAnchor, constant: -insets.bottom)) | |
} | |
constraints.forEach { $0.priority = priority } | |
NSLayoutConstraint.activate(constraints) | |
} | |
} | |
public extension UILayoutPriority { | |
static var almostRequired: UILayoutPriority { | |
return .required - 1 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment