├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── Align
│ └── Align.swift
└── Tests
├── AlignTests
├── AlignedTests.swift
└── XCTestManifests.swift
└── LinuxMain.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Jacob Bartlett
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Align",
7 | platforms: [
8 | .macOS(.v10_14), .iOS(.v13), .tvOS(.v13)
9 | ],
10 | products: [
11 | .library(
12 | name: "Align",
13 | targets: ["Align"]),
14 | ],
15 | dependencies: [],
16 | targets: [
17 | .target(
18 | name: "Align",
19 | dependencies: []),
20 | .testTarget(
21 | name: "AlignTests",
22 | dependencies: ["Align"]),
23 | ]
24 | )
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Align
2 |
3 | Align gives you an easy way to align views in SwiftUI.
4 |
5 | Simply `import Align` in whichever SwiftUI file you like and you're good to go. Align supplies the simple `align` ViewModifier which you can add to any view.
6 |
7 | To put your view on the leading edge, it's as simple as:
8 | ```
9 | Text("Hello, world!").align(.leading)
10 | ```
11 |
12 | There are 6 different alignments provided by the `ViewAlignment` enum:
13 | ```
14 | leading
15 | centerX
16 | trailing
17 | top
18 | centerY
19 | bottom
20 | ```
21 |
22 | The implementation is quite simple - the `.align()` modifier applies a frame modifier with max width/height set to infinity (taking up all available space) and alignment set as part of this frame modifier.
23 |
24 | Check out `Sources/Align/Align.swift` for the source code and to see SwiftUI previews for each alignment.
25 |
26 | My recommendation would be to just copy the source code directly into own project to avoid littering your code with `import Align`. If you do, I'd really appreciate a star on Github!
27 |
28 | Pull requests and constructive criticism welcome.
29 |
30 | Contributors:
31 | - Jacob Bartlett (original author)
32 | - u/lyinsteve who suggested an improvement to the alignment implementation
33 |
--------------------------------------------------------------------------------
/Sources/Align/Align.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | public enum ViewAlignment {
4 | case leading
5 | case centerX
6 | case trailing
7 | case top
8 | case centerY
9 | case bottom
10 | }
11 |
12 | public extension View {
13 |
14 | /// The `align` modifier allows you to horizontally and vertically align views using a simple syntax
15 | ///
16 | func align(_ alignment: ViewAlignment) -> some View {
17 | Group {
18 | if alignment == .leading {
19 | frame(maxWidth: .infinity, alignment: .leading)
20 | }
21 |
22 | if alignment == .centerX {
23 | frame(maxWidth: .infinity, alignment: .center)
24 | }
25 |
26 | if alignment == .trailing {
27 | frame(maxWidth: .infinity, alignment: .trailing)
28 | }
29 |
30 | if alignment == .top {
31 | frame(maxHeight: .infinity, alignment: .top)
32 | }
33 |
34 | if alignment == .centerY {
35 | frame(maxHeight: .infinity, alignment: .center)
36 | }
37 |
38 | if alignment == .bottom {
39 | frame(maxHeight: .infinity, alignment: .bottom)
40 | }
41 | }
42 | }
43 | }
44 |
45 |
46 | struct AlignDemoView: View {
47 |
48 | var alignment: ViewAlignment
49 |
50 | var body: some View {
51 | Text("Hello, World!").align(alignment)
52 | }
53 | }
54 |
55 |
56 | struct AlignDemoView_Previews: PreviewProvider {
57 |
58 | private static var alignments: [(name: String, alignment: ViewAlignment)] = [
59 | (name: "Leading", alignment: .leading),
60 | (name: "CenterX", alignment: .centerX),
61 | (name: "Trailing", alignment: .trailing),
62 | (name: "Top", alignment: .top),
63 | (name: "CenterY", alignment: .centerY),
64 | (name: "Bottom", alignment: .bottom),
65 | ]
66 |
67 | static var previews: some View {
68 | ForEach(alignments, id: \.name) {
69 | AlignDemoView(alignment: $0.alignment)
70 | .previewDisplayName($0.name)
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Tests/AlignTests/AlignedTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import SwiftUI
3 | @testable import Align
4 |
5 | final class AlignTests: XCTestCase {
6 |
7 | func testLeft() {
8 | XCTAssertNotNil(text.align(.leading))
9 | }
10 |
11 | func testCenterX() {
12 | XCTAssertNotNil(text.align(.centerX))
13 | }
14 |
15 | func testRight() {
16 | XCTAssertNotNil(text.align(.trailing))
17 | }
18 |
19 | func testTop() {
20 | XCTAssertNotNil(text.align(.top))
21 | }
22 |
23 | func testCenterY() {
24 | XCTAssertNotNil(text.align(.centerY))
25 | }
26 |
27 | func testBottom() {
28 | XCTAssertNotNil(text.align(.bottom))
29 | }
30 |
31 | private var text: some View {
32 | Text("Hello, world!")
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Tests/AlignTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(AlignTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import AlignTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += AlignTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------