Skip to content

Commit 581cc2e

Browse files
authored
Merge pull request #35 from 3sidedcube/release/v2.2.0
Release/v2.2.0
2 parents 07d8d56 + f2a0c56 commit 581cc2e

21 files changed

+473
-96
lines changed

Example/ViewControllers/MessageViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class MessageViewController: UIViewController {
1313

1414
private lazy var messageStackView: MessageStackView = {
1515
let messageStackView: MessageStackView = view.createMessageStackView()
16-
messageStackView.messageConfiguation = MessageConfiguration(
16+
messageStackView.messageConfiguration = MessageConfiguration(
1717
backgroundColor: .systemGroupedBackground,
1818
tintColor: .gray,
1919
shadow: true,

Example/ViewControllers/RootTableViewController.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class RootTableViewController: UITableViewController {
2424
("Badge Message", BadgeMessageViewController.self, false),
2525
("Message", MessageViewController.self, false),
2626
("No Internet", NoInternetTabBarController.self, true),
27-
("Shadow", ShadowViewController.self, false)
27+
("Shadow", ShadowViewController.self, false),
28+
("Toast", ToastViewController.self, false)
2829
]
2930

3031
// MARK: - ViewController lifecycle
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//
2+
// ToastViewController.swift
3+
// Example
4+
//
5+
// Created by Ben Shutt on 02/06/2021.
6+
// Copyright © 2021 3 SIDED CUBE APP PRODUCTIONS LTD. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import UIKit
11+
import MessageStackView
12+
13+
/// `UIViewController` to test `Toast`
14+
class ToastViewController: UIViewController {
15+
16+
/// `Toast` to post at the bottom of the screen
17+
private lazy var toast = Toast()
18+
19+
/// `UIButton` to add to bottom to make sure it can be clicked when the toast is slowing
20+
private lazy var button: UIButton = {
21+
let button = UIButton()
22+
button.setTitle(.buttonTitleClick, for: .normal)
23+
button.setTitleColor(.systemBlue, for: .normal)
24+
button.addTarget(
25+
self,
26+
action: #selector(buttonTouchUpInside),
27+
for: .touchUpInside
28+
)
29+
return button
30+
}()
31+
32+
// MARK: - ViewController lifecycle
33+
34+
override func viewDidLoad() {
35+
super.viewDidLoad()
36+
37+
addButtonToBottomLeading()
38+
addAndConstrainToast(toast)
39+
}
40+
41+
override func viewDidAppear(_ animated: Bool) {
42+
super.viewDidAppear(animated)
43+
44+
toast.post(message: .shortMessage)
45+
toast.postIfNotShowing(message: .shortMessage) // Shouldn't show
46+
toast.post(message: .longMessage)
47+
}
48+
49+
// MARK: - Subviews
50+
51+
private func addButtonToBottomLeading() {
52+
view.addSubview(button)
53+
button.translatesAutoresizingMaskIntoConstraints = false
54+
NSLayoutConstraint.activate([
55+
button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 25),
56+
button.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -15)
57+
])
58+
}
59+
60+
// MARK: - Actions
61+
62+
/// `sender` received `.touchUpInside` `UIControl.Event`
63+
///
64+
/// - Parameter sender: `UIButton` that invoked the action
65+
@objc
66+
private func buttonTouchUpInside(_ sender: UIButton) {
67+
UIView.animate(
68+
withDuration: 0.5,
69+
delay: 0,
70+
options: [.autoreverse],
71+
animations: {
72+
sender.setTitle(.buttonTitleClicked, for: .normal)
73+
sender.transform = CGAffineTransform(scaleX: 2, y: 2)
74+
}, completion: { _ in
75+
sender.transform = .identity
76+
sender.setTitle(.buttonTitleClick, for: .normal)
77+
}
78+
)
79+
}
80+
}
81+
82+
// MARK: - String + Text
83+
84+
private extension String {
85+
86+
static let buttonTitleClick = """
87+
Click Me
88+
"""
89+
90+
static let buttonTitleClicked = """
91+
Clicked!
92+
"""
93+
94+
static let shortMessage = """
95+
This is a toast!
96+
"""
97+
98+
static let longMessage = """
99+
This is a long toast to test how the text wraps when the width \
100+
of the text is greater than the width of the screen
101+
"""
102+
}

MessageStackView.xcodeproj/project.pbxproj

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
B81AEE5024FFF27A0068CE23 /* ShadowLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B81AEE4F24FFF27A0068CE23 /* ShadowLayer.swift */; };
3030
B81AEE5224FFFB2E0068CE23 /* ParentShadowLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B81AEE5124FFFB2E0068CE23 /* ParentShadowLayer.swift */; };
3131
B81AEE5425003F270068CE23 /* ShadowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B81AEE5325003F270068CE23 /* ShadowViewController.swift */; };
32+
B82405672668F6A200E4178B /* EdgeLayoutGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82405662668F6A200E4178B /* EdgeLayoutGuide.swift */; };
33+
B83CACB12667D5CE008FB755 /* Order.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83CACB02667D5CE008FB755 /* Order.swift */; };
34+
B83CACB32667D97E008FB755 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83CACB22667D97E008FB755 /* Toast.swift */; };
35+
B83CACB52667DA8A008FB755 /* ToastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83CACB42667DA8A008FB755 /* ToastViewController.swift */; };
3236
B872BE8725A3874C0031D619 /* UIImageView+Hidden.swift in Sources */ = {isa = PBXBuildFile; fileRef = B872BE8625A3874C0031D619 /* UIImageView+Hidden.swift */; };
3337
B872BE9125A387570031D619 /* UILabel+Hidden.swift in Sources */ = {isa = PBXBuildFile; fileRef = B872BE9025A387570031D619 /* UILabel+Hidden.swift */; };
3438
B875C98925126EB200FA05B5 /* UIViewController+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = B875C98825126EB200FA05B5 /* UIViewController+System.swift */; };
@@ -172,6 +176,10 @@
172176
B81AEE4F24FFF27A0068CE23 /* ShadowLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowLayer.swift; sourceTree = "<group>"; };
173177
B81AEE5124FFFB2E0068CE23 /* ParentShadowLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentShadowLayer.swift; sourceTree = "<group>"; };
174178
B81AEE5325003F270068CE23 /* ShadowViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowViewController.swift; sourceTree = "<group>"; };
179+
B82405662668F6A200E4178B /* EdgeLayoutGuide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EdgeLayoutGuide.swift; sourceTree = "<group>"; };
180+
B83CACB02667D5CE008FB755 /* Order.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Order.swift; sourceTree = "<group>"; };
181+
B83CACB22667D97E008FB755 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
182+
B83CACB42667DA8A008FB755 /* ToastViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastViewController.swift; sourceTree = "<group>"; };
175183
B872BE8625A3874C0031D619 /* UIImageView+Hidden.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+Hidden.swift"; sourceTree = "<group>"; };
176184
B872BE9025A387570031D619 /* UILabel+Hidden.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Hidden.swift"; sourceTree = "<group>"; };
177185
B875C98825126EB200FA05B5 /* UIViewController+System.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+System.swift"; sourceTree = "<group>"; };
@@ -313,6 +321,18 @@
313321
path = Shadow;
314322
sourceTree = "<group>";
315323
};
324+
B82405682668F8EB00E4178B /* UIView */ = {
325+
isa = PBXGroup;
326+
children = (
327+
OBJ_25 /* UIView+Animation.swift */,
328+
OBJ_26 /* UIView+Extensions.swift */,
329+
OBJ_28 /* UIView+SafeArea.swift */,
330+
OBJ_29 /* UIView+Shadow.swift */,
331+
OBJ_30 /* UIView+ShadowComponents.swift */,
332+
);
333+
path = UIView;
334+
sourceTree = "<group>";
335+
};
316336
B872BE8525A3873F0031D619 /* Hidden */ = {
317337
isa = PBXGroup;
318338
children = (
@@ -369,6 +389,7 @@
369389
B8BB087924C4BC46000E2E87 /* MessageViewController.swift */,
370390
B87CC99C24CC263E002B697C /* NoInternetTabBarController.swift */,
371391
B81AEE5325003F270068CE23 /* ShadowViewController.swift */,
392+
B83CACB42667DA8A008FB755 /* ToastViewController.swift */,
372393
);
373394
path = ViewControllers;
374395
sourceTree = "<group>";
@@ -414,6 +435,7 @@
414435
OBJ_13 /* CenterConstraints.swift */,
415436
OBJ_14 /* Constrainable.swift */,
416437
OBJ_15 /* EdgeConstraints.swift */,
438+
B82405662668F6A200E4178B /* EdgeLayoutGuide.swift */,
417439
OBJ_16 /* MessageLayout.swift */,
418440
OBJ_17 /* SizeConstraints.swift */,
419441
);
@@ -423,18 +445,14 @@
423445
OBJ_18 /* Extensions */ = {
424446
isa = PBXGroup;
425447
children = (
448+
B82405682668F8EB00E4178B /* UIView */,
426449
B872BE8525A3873F0031D619 /* Hidden */,
427450
OBJ_19 /* CALayer+Animation.swift */,
428451
OBJ_20 /* CGRect+Extensions.swift */,
429452
OBJ_21 /* DispatchQueue+Extensions.swift */,
430453
OBJ_22 /* String+Extensions.swift */,
431454
OBJ_23 /* UIApplication+StatusBar.swift */,
432455
OBJ_24 /* UIEdgeInsets+Extensions.swift */,
433-
OBJ_25 /* UIView+Animation.swift */,
434-
OBJ_26 /* UIView+Extensions.swift */,
435-
OBJ_28 /* UIView+SafeArea.swift */,
436-
OBJ_29 /* UIView+Shadow.swift */,
437-
OBJ_30 /* UIView+ShadowComponents.swift */,
438456
B87CC94B24C9F5A3002B697C /* Array+Extensions.swift */,
439457
B8BCDA8424CD8EB10067F26C /* UIApplication+KeyWindow.swift */,
440458
B81AEE4B24FFEE520068CE23 /* FloatingPoint+Equals.swift */,
@@ -519,6 +537,7 @@
519537
OBJ_54 /* PostAnimation.swift */,
520538
OBJ_55 /* Queue.swift */,
521539
B80B92AA2527324400F97364 /* Vector3.swift */,
540+
B83CACB02667D5CE008FB755 /* Order.swift */,
522541
);
523542
path = Models;
524543
sourceTree = "<group>";
@@ -595,6 +614,7 @@
595614
OBJ_74 /* MessageStackView.swift */,
596615
OBJ_75 /* PostView.swift */,
597616
B8F1C76224D8198E007C2712 /* ApplicationPostView.swift */,
617+
B83CACB22667D97E008FB755 /* Toast.swift */,
598618
);
599619
path = PostView;
600620
sourceTree = "<group>";
@@ -812,6 +832,7 @@
812832
B8BB088424C4BC46000E2E87 /* WindowViewController.swift in Sources */,
813833
B8BB088724C4BC46000E2E87 /* MessageViewController.swift in Sources */,
814834
B8BB088224C4BC46000E2E87 /* RootTableViewController.swift in Sources */,
835+
B83CACB52667DA8A008FB755 /* ToastViewController.swift in Sources */,
815836
B87CC99D24CC263E002B697C /* NoInternetTabBarController.swift in Sources */,
816837
);
817838
runOnlyForDeploymentPostprocessing = 0;
@@ -854,6 +875,7 @@
854875
OBJ_99 /* DispatchQueue+Extensions.swift in Sources */,
855876
OBJ_100 /* String+Extensions.swift in Sources */,
856877
OBJ_101 /* UIApplication+StatusBar.swift in Sources */,
878+
B83CACB32667D97E008FB755 /* Toast.swift in Sources */,
857879
OBJ_102 /* UIEdgeInsets+Extensions.swift in Sources */,
858880
OBJ_103 /* UIView+Animation.swift in Sources */,
859881
B8BCDA8C24CDB55B0067F26C /* UIViewController+Lifecycle.m in Sources */,
@@ -874,8 +896,10 @@
874896
B8F1C76324D8198E007C2712 /* ApplicationPostView.swift in Sources */,
875897
B81727F024D6CC9F0062282B /* PostViewController.swift in Sources */,
876898
B8E1CEEF2500F88C002BFE77 /* NeuomorphicShadow.swift in Sources */,
899+
B83CACB12667D5CE008FB755 /* Order.swift in Sources */,
877900
OBJ_115 /* BadgeMessageView.swift in Sources */,
878901
OBJ_116 /* BadgeMessageViewable.swift in Sources */,
902+
B82405672668F6A200E4178B /* EdgeLayoutGuide.swift in Sources */,
879903
OBJ_117 /* Poster+BadgeMessage.swift in Sources */,
880904
OBJ_118 /* Message.swift in Sources */,
881905
B81AEE4E24FFF2650068CE23 /* ShadowView.swift in Sources */,

Sources/Constraints/EdgeConstraints.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,26 +64,32 @@ struct EdgeConstraints: Constrainable {
6464

6565
extension UIView {
6666

67-
/// Construct `EdgeConstraints` `NSLayoutConstraint`s from
68-
/// `self` to `view`
67+
/// Construct `EdgeConstraints` `NSLayoutConstraint`s from `self` to `view`
6968
///
7069
/// - Parameters:
7170
/// - view: `UIView` to constrain to
71+
/// - insets: `UIEdgeInsets` to inset
72+
/// - safeAreaLayoutGuide: `Bool` constrain to `view`'s `safeAreaLayoutGuide`
7273
/// - activate: Activate the `NSLayoutConstraint`s
7374
@discardableResult
7475
func edgeConstraints(
7576
to view: UIView,
7677
insets: UIEdgeInsets = .zero,
78+
safeAreaLayoutGuide: Bool = false,
7779
activate: Bool = true
7880
) -> EdgeConstraints {
7981
translatesAutoresizingMaskIntoConstraints = false
8082

83+
// `EdgeLayoutGuide` of `view` to constrain `self` to
84+
let viewLayoutGuide: EdgeLayoutGuide =
85+
safeAreaLayoutGuide ? view.safeAreaLayoutGuide : view
86+
8187
// Create `NSLayoutConstraint`s to the edge anchors
8288
var edgeConstraints = EdgeConstraints(
83-
leading: leadingAnchor.constraint(equalTo: view.leadingAnchor),
84-
top: topAnchor.constraint(equalTo: view.topAnchor),
85-
trailing: trailingAnchor.constraint(equalTo: view.trailingAnchor),
86-
bottom: bottomAnchor.constraint(equalTo: view.bottomAnchor)
89+
leading: leadingAnchor.constraint(equalTo: viewLayoutGuide.leadingAnchor),
90+
top: topAnchor.constraint(equalTo: viewLayoutGuide.topAnchor),
91+
trailing: trailingAnchor.constraint(equalTo: viewLayoutGuide.trailingAnchor),
92+
bottom: bottomAnchor.constraint(equalTo: viewLayoutGuide.bottomAnchor)
8793
)
8894

8995
// Set `UIEdgeInsets` as provided
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// LayoutGuide.swift
3+
// MessageStackView
4+
//
5+
// Created by Ben Shutt on 03/06/2021.
6+
// Copyright © 2021 3 SIDED CUBE APP PRODUCTIONS LTD. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// Edge layout guide
12+
protocol EdgeLayoutGuide {
13+
14+
/// Leading anchor in X
15+
var leadingAnchor: NSLayoutXAxisAnchor { get }
16+
17+
/// Top anchor in Y
18+
var topAnchor: NSLayoutYAxisAnchor { get }
19+
20+
/// Trailing anchor in X
21+
var trailingAnchor: NSLayoutXAxisAnchor { get }
22+
23+
/// Bottom anchor in Y
24+
var bottomAnchor: NSLayoutYAxisAnchor { get }
25+
}
26+
27+
// MARK: - UIView + EdgeLayoutGuide
28+
29+
extension UIView: EdgeLayoutGuide {}
30+
31+
// MARK: - UILayoutGuide + EdgeLayoutGuide
32+
33+
extension UILayoutGuide: EdgeLayoutGuide {}

Sources/Constraints/MessageLayout.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,27 @@ public enum MessageLayout: Int {
2121
case bottom
2222
}
2323

24+
// MARK: - Order
25+
26+
public extension MessageLayout {
27+
28+
/// Map to `Order`
29+
func toOrder() -> Order {
30+
switch self {
31+
case .top: return .topToBottom
32+
case .bottom: return .bottomToTop
33+
}
34+
}
35+
}
36+
2437
// MARK: - NSLayoutConstraint
2538

2639
public extension MessageLayout {
2740

2841
/// Constrain `subview` to `superview` based on `self` (`MessageLayout`).
2942
/// - Parameters:
3043
/// - subview: `UIView` to add as a subview to `superview`
31-
/// - superview: `UIView` superivew of `subview`
44+
/// - superview: `UIView` superview of `subview`
3245
/// - safeAnchors: Constrain to safe anchors
3346
func constrain(
3447
subview: UIView,
@@ -100,7 +113,9 @@ public extension UIView {
100113

101114
// Constrain `self`
102115
layout.constrain(
103-
subview: self, to: view, safeAnchors: constrainToSafeArea
116+
subview: self,
117+
to: view,
118+
safeAnchors: constrainToSafeArea
104119
)
105120

106121
// Trigger a layout cycle
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)