I am using the TinyConstraints library, and have always found it inconvenient to work with labels and text fields due to the fact that you must manually account for ascender/descender in the offset. This extension should make things easier, but I'm thinking there may be more elegant design patterns for accomplishing this.////  TinyConstraints+Extras.swift//  WeThePeople////  Created by Joseph Falcone on 4/15/17.//  Copyright  2017 Joseph Falcone. All rights reserved.//import Foundationimport TinyConstraintspublic struct TextLayoutOptions : OptionSet{    public let rawValue : Int    public init(rawValue:Int){ self.rawValue = rawValue}    public static let IgnoreAscender  = TextLayoutOptions(rawValue:1)    public static let IgnoreDescender = TextLayoutOptions(rawValue:2)}public struct ViewEdge : OptionSet, Hashable{    public let rawValue: Int    public init(rawValue:Int){ self.rawValue = rawValue}    public var hashValue: Int {        return self.rawValue    }    static let top      = ViewEdge(rawValue: 1 << 0)    static let right    = ViewEdge(rawValue: 1 << 1) // try not to use right and left    static let bottom   = ViewEdge(rawValue: 1 << 2)    static let left     = ViewEdge(rawValue: 1 << 3) // leading and trailing are better for text    static let leading  = ViewEdge(rawValue: 1 << 4) // left for western users    static let trailing = ViewEdge(rawValue: 1 << 5) // right for western users    static func test(){}}public extension Constrainable{    @discardableResult    public func edges(to view: Constrainable, excludingEdges: ViewEdge = [], insets: EdgeInsets = .zero, priority: ConstraintPriority = .required, isActive: Bool = true) -> Constraints {        var constraints = [NSLayoutConstraint]()        if !excludingEdges.contains(.top){            constraints.append(topAnchor.constraint(equalTo: view.topAnchor, constant: insets.top).with(priority))        }        if !excludingEdges.contains(.leading) || !excludingEdges.contains(.left){            constraints.append(leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: insets.left).with(priority))        }        if !excludingEdges.contains(.bottom){            constraints.append(bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: insets.bottom).with(priority))        }        if !excludingEdges.contains(.trailing) || !excludingEdges.contains(.right){            constraints.append(trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: insets.right).with(priority))        }        if isActive {            Constraint.activate(constraints)        }        return constraints    }    // These autolayout extensions are designed for classes that display text. This returns the display font if the class type is valid.    // UILabel    // UITextField    private func getDisplayFont() -> UIFont?    {        if let v = self as? UILabel     {return v.font}        if let v = self as? UITextField {return v.font}        //if let v = self as? UITextView  {return v.font} UITextView is weird...the top align represents where the text gets cut off...        return nil    }    // NOTE: The font must be set before this returns anything of value    // NOTE: All values are positive since they are insets, even though descender is normally negative    private func typographyInsets() -> UIEdgeInsets    {        guard let font = self.getDisplayFont() else {            return UIEdgeInsets.zero        }        return UIEdgeInsets(top: (font.ascender - font.capHeight), left: 0, bottom: abs(font.descender), right: 0)    }    private func getOffsetModifier(to: Constrainable, edge: ViewEdge, toEdge: ViewEdge, textOptions: TextLayoutOptions = []) -> CGFloat    {        // Tired of labels and their ascenders/descenders being ignored.        // Let's make it easier to space these things out.        var typographyOffset : CGFloat = 0        let myTI = self.typographyInsets()        let toTI = to.typographyInsets()        if edge == toEdge {            // top to top, bottom to bottom            if edge == .top {                typographyOffset = toTI.top - myTI.top            }            if edge == .bottom {                typographyOffset = myTI.bottom - toTI.bottom            }        }        if edge == .top && toEdge == .bottom {            typographyOffset = -(myTI.top + toTI.bottom)        }        if edge == .bottom && toEdge == .top {            typographyOffset = myTI.bottom + toTI.top        }        return typographyOffset;    }    @discardableResult    public func topToBottom(of view: Constrainable, offset: CGFloat = 0, relation: ConstraintRelation = .equal, priority: ConstraintPriority = .required, textOptions: TextLayoutOptions = [], isActive: Bool = true) -> Constraint {        return top(to: view, view.bottomAnchor, offset: offset, relation: relation, priority: priority, textOptions: textOptions, isActive: isActive)    }    @discardableResult    public func top(to view: Constrainable, _ anchor: NSLayoutYAxisAnchor? = nil, offset: CGFloat = 0, relation: ConstraintRelation = .equal, priority: ConstraintPriority = .required, textOptions: TextLayoutOptions = [], isActive: Bool = true) -> Constraint {        let toEdge = (anchor != nil) ? ViewEdge.bottom : ViewEdge.top        let offsetMod = self.getOffsetModifier(to: view, edge: ViewEdge.top, toEdge: toEdge, textOptions: textOptions)        switch relation {        case .equal:            return topAnchor.constraint(equalTo:                anchor ?? view.topAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        case .equalOrLess:      return topAnchor.constraint(lessThanOrEqualTo:      anchor ?? view.topAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        case .equalOrGreater:   return topAnchor.constraint(greaterThanOrEqualTo:   anchor ?? view.topAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        }    }    @discardableResult    public func bottomToTop(of view: Constrainable, offset: CGFloat = 0, relation: ConstraintRelation = .equal, priority: ConstraintPriority = .required, textOptions: TextLayoutOptions = [], isActive: Bool = true) -> Constraint {        return bottom(to: view, view.topAnchor, offset: offset, relation: relation, priority: priority, textOptions: textOptions, isActive: isActive)    }    @discardableResult    public func bottom(to view: Constrainable, _ anchor: NSLayoutYAxisAnchor? = nil, offset: CGFloat = 0, relation: ConstraintRelation = .equal, priority: ConstraintPriority = .required, textOptions: TextLayoutOptions = [], isActive: Bool = true) -> Constraint {        let toEdge = (anchor != nil) ? ViewEdge.top : ViewEdge.bottom        let offsetMod = self.getOffsetModifier(to: view, edge: ViewEdge.top, toEdge: toEdge, textOptions: textOptions)        switch relation {        case .equal:            return bottomAnchor.constraint(equalTo:                 anchor ?? view.bottomAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        case .equalOrLess:      return bottomAnchor.constraint(lessThanOrEqualTo:       anchor ?? view.bottomAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        case .equalOrGreater:   return bottomAnchor.constraint(greaterThanOrEqualTo:    anchor ?? view.bottomAnchor, constant: offset+offsetMod).with(priority).set(active: isActive)        }    }    @discardableResult    public func centerY(to view: Constrainable, _ anchor: NSLayoutYAxisAnchor? = nil, offset: CGFloat = 0, priority: ConstraintPriority = .required, textOptions: TextLayoutOptions = [], isActive: Bool = true) -> Constraint {        // Calculate a special offset mod        let myTI = self.typographyInsets()        let toTI = view.typographyInsets()        let offsetMod = ((toTI.top+toTI.bottom)-(myTI.top+myTI.bottom))/2        let constraint = centerYAnchor.constraint(equalTo: anchor ?? view.centerYAnchor, constant: offset+offsetMod).with(priority)        constraint.isActive = isActive        return constraint    }}
Extension for TinyConstraints allowing you to include the ascender/descender in the offset automatically for UILabel/UITextView
swift;swift3