Skip to content

Commit 8ad1a30

Browse files
committed
Added extension for UIView constrain center
1 parent dea921b commit 8ad1a30

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// UIView+constrainCenter.swift
3+
// YCoreUI
4+
//
5+
// Created by Dharmik Ghelani on 20/10/22.
6+
// Copyright © 2022 Y Media Labs. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
extension UIView {
12+
/// Struct to define center attribute
13+
struct Center: OptionSet {
14+
let rawValue: UInt
15+
static let x = Center(rawValue: 1 << 0)
16+
static let y = Center(rawValue: 1 << 1)
17+
static let all: Center = [.x, .y]
18+
}
19+
20+
/// Constrain the receiving view with provided center attributes
21+
/// - Parameters:
22+
/// - center: Center attribute of view to constrain to (default `.all`)
23+
/// - view2: View object to which constrain to (pass `nil` to constrain to superview)
24+
/// - relation: Relation to evaluate (default `.equal`)
25+
/// - offset: Offset to apply to attribute(center X and Y) (default `.zero`)
26+
/// - priority: Constraint priority (default `.required`)
27+
/// - isActive: Whether to activate the constraint or not (default `true`)
28+
/// - Returns: The created layout constraint
29+
func constrainCenter(
30+
_ center: Center = .all,
31+
to view2: Anchorable? = nil,
32+
relatedBy relation: NSLayoutConstraint.Relation = .equal,
33+
offset: UIOffset = .zero,
34+
priority: UILayoutPriority = .required,
35+
isActive: Bool = true
36+
) -> [NSLayoutConstraint.Attribute: NSLayoutConstraint] {
37+
var constraints: [NSLayoutConstraint.Attribute: NSLayoutConstraint] = [:]
38+
let otherView: Anchorable! = view2 ?? superview
39+
40+
if center.contains(.x) {
41+
constraints[.centerX] = constrain(
42+
.centerXAnchor,
43+
to: otherView.centerXAnchor,
44+
relatedBy: relation,
45+
constant: offset.horizontal,
46+
priority: priority,
47+
isActive: isActive
48+
)
49+
}
50+
51+
if center.contains(.y) {
52+
constraints[.centerY] = constrain(
53+
.centerYAnchor,
54+
to: otherView.centerYAnchor,
55+
relatedBy: relation,
56+
constant: offset.vertical,
57+
priority: priority,
58+
isActive: isActive
59+
)
60+
}
61+
62+
return constraints
63+
}
64+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//
2+
// UIView+constrainCenterTests.swift
3+
// YCoreUI
4+
//
5+
// Created by Dharmik Ghelani on 20/10/22.
6+
// Copyright © 2022 Y Media Labs. All rights reserved.
7+
//
8+
9+
import XCTest
10+
@testable import YCoreUI
11+
12+
final class UIViewConstrainCenterTests: XCTestCase {
13+
func testCenterX() {
14+
let (sut, offset) = makeSUT()
15+
16+
let constraints = sut.view1.constrainCenter(.x, offset: offset)
17+
let centerXConstraint = constraints[.centerX]
18+
19+
XCTAssertFalse(sut.view1.translatesAutoresizingMaskIntoConstraints)
20+
XCTAssertEqual(constraints.count, 1)
21+
XCTAssertNotNil(centerXConstraint)
22+
XCTAssertEqual(centerXConstraint?.firstItem as? UIView, sut.view1)
23+
XCTAssertEqual(centerXConstraint?.firstAttribute, .centerX)
24+
XCTAssertEqual(centerXConstraint?.secondItem as? UIView, sut)
25+
XCTAssertEqual(centerXConstraint?.secondAttribute, .centerX)
26+
XCTAssertEqual(centerXConstraint?.constant, offset.horizontal)
27+
}
28+
29+
func testCenterY() {
30+
let (sut, offset) = makeSUT()
31+
32+
let constraints = sut.view1.constrainCenter(.y, offset: offset)
33+
let centerYConstraint = constraints[.centerY]
34+
35+
XCTAssertFalse(sut.view1.translatesAutoresizingMaskIntoConstraints)
36+
XCTAssertEqual(constraints.count, 1)
37+
XCTAssertNotNil(centerYConstraint)
38+
XCTAssertEqual(centerYConstraint?.firstItem as? UIView, sut.view1)
39+
XCTAssertEqual(centerYConstraint?.firstAttribute, .centerY)
40+
XCTAssertEqual(centerYConstraint?.secondItem as? UIView, sut)
41+
XCTAssertEqual(centerYConstraint?.secondAttribute, .centerY)
42+
XCTAssertEqual(centerYConstraint?.constant, offset.vertical)
43+
}
44+
45+
func testCenterBoth() {
46+
let (sut, offset) = makeSUT()
47+
48+
let constraints = sut.view1.constrainCenter(offset: offset)
49+
50+
let anchorAttributes: [
51+
(NSLayoutConstraint.Attribute, CGFloat)
52+
] = [
53+
(.centerX, offset.horizontal),
54+
(.centerY, offset.vertical)
55+
]
56+
57+
XCTAssertFalse(sut.view1.translatesAutoresizingMaskIntoConstraints)
58+
XCTAssertEqual(constraints.count, 2)
59+
60+
anchorAttributes.forEach {
61+
let constraint = constraints[$0.0]
62+
XCTAssertNotNil(constraint)
63+
XCTAssertEqual(constraint?.firstItem as? UIView, sut.view1)
64+
XCTAssertEqual(constraint?.firstAttribute, $0.0)
65+
XCTAssertEqual(constraint?.secondItem as? UIView, sut)
66+
XCTAssertEqual(constraint?.secondAttribute, $0.0)
67+
XCTAssertEqual(constraint?.constant, $0.1)
68+
}
69+
}
70+
}
71+
72+
extension UIViewConstrainCenterTests {
73+
func makeSUT(
74+
file: StaticString = #filePath,
75+
line: UInt = #line
76+
) -> (MockLayoutContainer, UIOffset) {
77+
let container = MockLayoutContainer()
78+
let offset = UIOffset(horizontal: 30, vertical: 20)
79+
80+
trackForMemoryLeak(container, file: file, line: line)
81+
82+
return (container, offset)
83+
}
84+
}

0 commit comments

Comments
 (0)