Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // TinyConstraints+Extras.swift
- // WeThePeople
- //
- // Created by Joseph Falcone on 4/15/17.
- // Copyright © 2017 Joseph Falcone. All rights reserved.
- //
- import Foundation
- import TinyConstraints
- public 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 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
- }
- }
Add Comment
Please, Sign In to add comment