1+ //
2+ // SwiftLayout.swift
3+ // SwiftLayout
4+ //
5+ // Created by Anton Doudarev on 5/25/16.
6+ // Copyright © 2016 Anton Doudarev. All rights reserved.
7+ //
8+
9+ import Foundation
10+ import UIKit
11+
12+ public enum VerticalAlign {
13+ case Above // Align vertically Above
14+ case Below // Align vertically Below
15+ case Center // Align center.y vertically
16+ case Top // Align vertically to the top
17+ case Base // Align vertically to the base
18+ }
19+
20+ public enum HorizontalAlign {
21+ case Left // Align horizontally to the Left
22+ case Right // Align horizontally to the Right
23+ case Center // Align center.y horizontally
24+ case RightEdge // Align horizontally to the Right Edge
25+ case LeftEdge // Align horizontally to the Left Edge
26+ }
27+
28+
29+ // MARK: - UIView Alignment Extension
30+
31+ public extension UIView {
32+
33+ /**
34+ Align self relative to another frame.
35+
36+ This method calculate a new frame based on the alignment
37+ parameters, and sets that frame on self
38+
39+ - parameter toFrame: relative frame to align against. If not assigned, will attempt to use the superview, else defaults to CGRectZero
40+ - parameter withSize: size to set on the calculated frame, defaults to self.bounds.size
41+ - parameter horizontal: horizontal alignment relative to the toView
42+ - parameter vertical: vertical alignment relative to the toView
43+ - parameter horizontalOffset: horizontal offset to apply to the calculated relative frame, defautls to 0
44+ - parameter verticalOffset: vertical offset to apply to the calculated relative frame, defautls to 0
45+ */
46+ func align( toFrame frame : CGRect ? = nil ,
47+ withSize size : CGSize ? = nil ,
48+ horizontal : HorizontalAlign = . Center,
49+ vertical : VerticalAlign = . Center,
50+ horizontalOffset : CGFloat = 0.0 ,
51+ verticalOffset : CGFloat = 0.0 ) {
52+
53+ let newRect = rectAligned ( toFrame : frame,
54+ withSize : size,
55+ horizontal : horizontal,
56+ vertical : vertical,
57+ horizontalOffset : horizontalOffset,
58+ verticalOffset : verticalOffset)
59+
60+ if CGRectEqualToRect ( self . frame, newRect) == false {
61+ self . frame = newRect
62+ }
63+ }
64+
65+ /**
66+ Calculates,vand returns a frame based on the alignment parameters.
67+
68+ This is a handy method to use when performing animations, you can ask the view to return
69+ the frame it would align to without aligning it self to the returned value.
70+
71+ See the CGRect Extension provided with this framework, you can query a CGRect
72+ for it's bounds and center. Since the frame property is not animatable, you
73+ may cancreate an animation group with two separate animations, one for position,
74+ and one for hte bounds
75+
76+ - parameter toFrame: relative frame to align against. If not assigned, will attempt to use the superview, else defaults to CGRectZero
77+ - parameter withSize: size to set on the calculated frame, defaults to self.bounds.size
78+ - parameter horizontal: horizontal alignment relative to the toView
79+ - parameter vertical: vertical alignment relative to the toView
80+ - parameter horizontalOffset: horizontal offset to apply to the calculated relative frame, defautls to 0
81+ - parameter verticalOffset: vertical offset to apply to the calculated relative frame, defautls to 0
82+
83+ - returns: returns the final aligned frame
84+ */
85+ func rectAligned( toFrame frame : CGRect ? = nil ,
86+ withSize size : CGSize ? = nil ,
87+ horizontal : HorizontalAlign = . Center,
88+ vertical : VerticalAlign = . Center,
89+ horizontalOffset : CGFloat = 0.0 ,
90+ verticalOffset : CGFloat = 0.0 ) -> CGRect {
91+
92+ var referenceFrame = frame
93+
94+ if let relativeFrame = frame {
95+ if CGRectEqualToRect ( CGRectZero, relativeFrame) {
96+ if let superviewFrame = superview? . bounds {
97+ referenceFrame = superviewFrame
98+ }
99+ }
100+ } else {
101+ if let superviewFrame = superview? . bounds {
102+ referenceFrame = superviewFrame
103+ }
104+ }
105+
106+ var calculatedFrame = self . bounds
107+
108+ if let newSize = size {
109+ calculatedFrame. size = newSize
110+ }
111+
112+ calculatedFrame. origin. x = alignedHorizontalOrigin ( forRect : calculatedFrame,
113+ relativeToRect : referenceFrame!,
114+ withAlignment : horizontal)
115+
116+ calculatedFrame. origin. y = alignedVerticalOrigin ( forRect : calculatedFrame,
117+ relativeToRect : referenceFrame!,
118+ withAlignment : vertical)
119+
120+ calculatedFrame. origin. x += horizontalOffset
121+ calculatedFrame. origin. y += verticalOffset
122+
123+ return calculatedFrame
124+ }
125+ }
126+
127+
128+ // MARK: - Private Alignment Calculations Extension
129+
130+ extension UIView {
131+
132+ /**
133+ Private Method. Calculates a horizontally aligned frame for the source frame relative to
134+ the destination frame
135+ */
136+ final private func alignedHorizontalOrigin( forRect sourceRect : CGRect ,
137+ relativeToRect toRect : CGRect ,
138+ withAlignment alignment : HorizontalAlign ) -> CGFloat {
139+
140+ var origin = sourceRect. origin. x
141+
142+ switch ( alignment) {
143+ case . Left:
144+ origin = toRect. origin. x - sourceRect. size. width;
145+ case . Right:
146+ origin = CGRectGetMaxX ( toRect) ;
147+ case . Center:
148+ origin = toRect. origin. x + ( ( toRect. size. width - sourceRect. size. width) / 2.0 ) ;
149+ case . LeftEdge:
150+ origin = toRect. origin. x;
151+ case . RightEdge:
152+ origin = CGRectGetMaxX ( toRect) - sourceRect. size. width;
153+ }
154+
155+ return round ( origin)
156+ }
157+
158+ /**
159+ Private Method. Calculates a vertically aligned frame for the source frame relative to
160+ the destination frame
161+ */
162+ final private func alignedVerticalOrigin( forRect sourceRect : CGRect ,
163+ relativeToRect toRect : CGRect ,
164+ withAlignment alignment : VerticalAlign ) -> CGFloat {
165+ var origin = sourceRect. origin. x
166+
167+ switch ( alignment) {
168+ case . Top:
169+ origin = toRect. origin. y
170+ case . Base:
171+ origin = CGRectGetMaxY ( toRect) - sourceRect. size. height
172+ case . Center:
173+ origin = toRect. origin. y + ( ( toRect. size. height - sourceRect. size. height) / 2.0 )
174+ case . Above:
175+ origin = toRect. origin. y - sourceRect. size. height
176+ case . Below:
177+ origin = CGRectGetMaxY ( toRect)
178+ }
179+
180+ return round ( origin)
181+ }
182+ }
0 commit comments