Untitled
unknown
plain_text
2 years ago
11 kB
12
Indexable
public extension UIView {
// MARK: - Enums
enum Side {
case top
case bottom
case leading
case trailing
}
enum Dimension {
case height
case width
}
enum Center {
case vertical
case horizontal
}
// MARK: - Anchors
@discardableResult
func fillSuperviewWidth(distance: CGFloat = 0.0, priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
return alignWithSuperview(sides: [.leading, .trailing], distance: distance, priority: priority)
}
@discardableResult
func fillSuperviewHeight(distance: CGFloat = 0.0, priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
return alignWithSuperview(sides: [.top, .bottom], distance: distance, priority: priority)
}
@discardableResult
func fillSuperview(distance: CGFloat = 0.0, priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
return alignWithSuperview(sides: [.leading, .trailing, .top, .bottom], distance: distance, priority: priority)
}
@discardableResult
func alignWithSuperview(
sides: [Side],
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> [NSLayoutConstraint] {
var constraints = [NSLayoutConstraint]()
if let superview = self.superview {
for side in sides {
constraints.append(align(side, withSide: side, of: superview, distance: distance, priority: priority, relation: relation))
}
}
return constraints
}
@discardableResult
func alignWithSuperview(
_ side: Side,
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> NSLayoutConstraint {
if let constraint = alignWithSuperview(sides: [side], distance: distance, priority: priority, relation: relation).first {
return constraint
}
return .init()
}
@discardableResult
func fillSafeArea(distance: CGFloat = 0.0, priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
return alignWithSafeArea(sides: [.leading, .trailing, .top, .bottom], distance: distance, priority: priority)
}
@discardableResult
func alignWithSafeArea(
sides: [Side],
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> [NSLayoutConstraint] {
var constraints = [NSLayoutConstraint]()
if let safeArea = self.superview?.safeAreaLayoutGuide {
for side in sides {
constraints.append(
align(
side,
withSide: side,
target: safeArea,
distance: distance,
priority: priority,
relation: relation
)
)
}
}
return constraints
}
@discardableResult
func alignWithSafeArea(
_ side: Side,
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> NSLayoutConstraint {
if let constraint = alignWithSafeArea(sides: [side], distance: distance, priority: priority, relation: relation).first {
return constraint
}
return .init()
}
@discardableResult
func align(
_ side: Side,
withSide otherSide: Side,
of view: UIView,
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> NSLayoutConstraint {
return align(
side,
withSide: otherSide,
target: view,
distance: distance,
priority: priority,
relation: relation
)
}
private func align(
_ side: Side,
withSide otherSide: Side,
target: Any,
distance: CGFloat = 0.0,
priority: UILayoutPriority = .required,
relation: NSLayoutConstraint.Relation = .equal
) -> NSLayoutConstraint {
self.translatesAutoresizingMaskIntoConstraints = false
var convertedDistance = distance
if side == otherSide && (side == .trailing || side == .bottom) {
convertedDistance = -distance
}
let constraint = NSLayoutConstraint(
item: self,
attribute: layoutAttribute(for: side),
relatedBy: relation,
toItem: target,
attribute: layoutAttribute(for: otherSide),
multiplier: 1.0,
constant: convertedDistance
)
constraint.priority = priority
constraint.isActive = true
return constraint
}
// MARK: - Dimension
@discardableResult
func pinHeight(_ constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinDimension(.height, of: nil, constant: constant, priority: priority)
}
@discardableResult
func pinWidth(_ constant: CGFloat, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinDimension(.width, of: nil, constant: constant, priority: priority)
}
@discardableResult
func pinHeight(to view: UIView, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinDimension(.height, of: view, priority: priority)
}
@discardableResult
func pinWidth(to view: UIView, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinDimension(.width, of: view, priority: priority)
}
@discardableResult
func pinSize(_ constant: CGFloat, priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
return [pinHeight(constant, priority: priority), pinWidth(constant, priority: priority)]
}
@discardableResult
func aspectRatio(
for dimension: UIView.Dimension,
ratio: CGFloat,
priority: UILayoutPriority = .required
) -> NSLayoutConstraint {
self.translatesAutoresizingMaskIntoConstraints = false
let firstDimension: NSLayoutConstraint.Attribute
let secondDimension: NSLayoutConstraint.Attribute
switch dimension {
case .height:
firstDimension = .width
secondDimension = .height
case .width:
firstDimension = .height
secondDimension = .width
}
let constraint = NSLayoutConstraint(
item: self,
attribute: firstDimension,
relatedBy: .equal,
toItem: self,
attribute: secondDimension,
multiplier: ratio,
constant: 0.0
)
constraint.priority = priority
constraint.isActive = true
return constraint
}
// MARK: - Center
@discardableResult
func pinCenterHorizontally(priority: UILayoutPriority = .required) -> NSLayoutConstraint {
if let superview = self.superview {
return pinCenterHorizontally(to: superview, priority: priority)
}
return .init()
}
@discardableResult
func pinCenterVertically(priority: UILayoutPriority = .required) -> NSLayoutConstraint {
if let superview = self.superview {
return pinCenterVertically(to: superview, priority: priority)
}
return .init()
}
@discardableResult
func pinCenterHorizontally(to view: UIView, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinCenter(.horizontal, of: view, priority: priority)
}
@discardableResult
func pinCenterVertically(to view: UIView, priority: UILayoutPriority = .required) -> NSLayoutConstraint {
return pinCenter(.vertical, of: view, priority: priority)
}
@discardableResult
func pinCenter(priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
var constraints = [NSLayoutConstraint]()
constraints.append(pinCenterVertically(priority: priority))
constraints.append(pinCenterHorizontally(priority: priority))
return constraints
}
private func pinDimension(
_ dimension: Dimension,
of target: UIView?,
constant: CGFloat = 0.0,
priority: UILayoutPriority = .required
) -> NSLayoutConstraint {
return pinEqual(layoutAttribute(for: dimension), of: target, constant: constant, priority: priority)
}
private func pinCenter(
_ center: Center,
of target: UIView,
constant: CGFloat = 0.0,
priority: UILayoutPriority = .required
) -> NSLayoutConstraint {
return pinEqual(layoutAttribute(for: center), of: target, constant: constant, priority: priority)
}
private func pinEqual(
_ attribute: NSLayoutConstraint.Attribute,
of target: UIView?,
constant: CGFloat = 0.0,
priority: UILayoutPriority = .required
) -> NSLayoutConstraint {
self.translatesAutoresizingMaskIntoConstraints = false
let constraint = NSLayoutConstraint(
item: self,
attribute: attribute,
relatedBy: .equal,
toItem: target,
attribute: attribute,
multiplier: 1.0,
constant: constant
)
constraint.priority = priority
constraint.isActive = true
return constraint
}
private func layoutAttribute(for side: Side) -> NSLayoutConstraint.Attribute {
switch side {
case .top:
return .top
case .bottom:
return .bottom
case .leading:
return .leading
case .trailing:
return .trailing
}
}
private func layoutAttribute(for dimension: Dimension) -> NSLayoutConstraint.Attribute {
switch dimension {
case .height:
return .height
case .width:
return .width
}
}
private func layoutAttribute(for center: Center) -> NSLayoutConstraint.Attribute {
switch center {
case .vertical:
return .centerY
case .horizontal:
return .centerX
}
}
}Editor is loading...
Leave a Comment