Skip to content

Commit 0477a58

Browse files
authored
Merge pull request #48 from WeTransfer/feature/action
Add Support for Button
2 parents 43fc7d9 + c2081cc commit 0477a58

File tree

7 files changed

+161
-34
lines changed

7 files changed

+161
-34
lines changed

Assets/button_notification.png

36.5 KB
Loading

Example/UINotifications-Example/Base.lproj/Main.storyboard

Lines changed: 61 additions & 29 deletions
Large diffs are not rendered by default.

Example/UINotifications-Example/ViewController.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ final class ViewController: UIViewController {
8181

8282
@IBOutlet private weak var automaticallyDismissSwitch: UISwitch!
8383
@IBOutlet private weak var addActionSwitch: UISwitch!
84+
@IBOutlet private weak var addButtonSwitch: UISwitch!
8485
@IBOutlet private weak var showsImageSwitch: UISwitch!
8586
@IBOutlet private weak var successStyleSwitch: UISwitch!
8687

@@ -110,6 +111,17 @@ final class ViewController: UIViewController {
110111

111112
let notification = UINotification(content: UINotificationContent(title: title, subtitle: subtitle, image: image), style: style, action: action)
112113

114+
if addButtonSwitch.isOn {
115+
let button = UIButton(type: .system)
116+
button.setTitle("Button", for: .normal)
117+
button.addTarget(self, action: #selector(handleTapNotificationButton), for: .touchUpInside)
118+
notification.button = button
119+
}
120+
113121
UINotificationCenter.current.show(notification: notification, dismissTrigger: dismissTrigger)
114122
}
123+
124+
@objc func handleTapNotificationButton() {
125+
print("Tapped the button!")
126+
}
115127
}

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ manualDismissTrigger.trigger() // Dismiss
148148
UINotificationCenter.current.notificationViewType = MyCustomNotificationView.self
149149
```
150150

151+
### Use a custom UIButton
152+
By setting the `button` property on `UINotification`, you can simply add a button to the notification.
153+
154+
```swift
155+
notification.button = UIButton(type: .system)
156+
```
157+
158+
![Button](Assets/button_notification.png?)
159+
151160
### Create a custom presenter
152161
Create a custom presenter to manage presentation and dismiss animations.
153162

Sources/UINotification.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ public protocol UINotificationStyle {
3737

3838
/// Handles changes in UINotification
3939
protocol UINotificationDelegate: class {
40-
// Called when Notification is updated
40+
// Called when Notification is updated.
4141
func didUpdateContent(in notificaiton: UINotification)
42+
43+
/// Called when the button is set.
44+
func didUpdateButton(in notificaiton: UINotification)
4245
}
4346

4447
/// An UINotification which can be showed on top of the `UINavigationBar` and `UIStatusBar`
@@ -68,6 +71,14 @@ public final class UINotification: Equatable {
6871
/// The style of the notification which applies on the notification view.
6972
public let style: UINotificationStyle
7073

74+
/// The button to display on the right side of the notification, if any.
75+
/// Setting this property will add the button, even if the notification is already visible.
76+
public var button: UIButton? {
77+
didSet {
78+
delegate?.didUpdateButton(in: self)
79+
}
80+
}
81+
7182
/// The action which will be triggered on tap.
7283
public let action: UINotificationAction?
7384

Sources/UINotificationView.swift

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ open class UINotificationView: UIView {
2727
private let containerStackViewDefaultSpacing: CGFloat = 14
2828

2929
private lazy var containerStackView: UIStackView = {
30-
let stackView = UIStackView(arrangedSubviews: [self.imageView, self.titlesStackView, self.chevronImageView])
30+
let stackView = UIStackView()
3131
stackView.axis = .horizontal
3232
stackView.spacing = self.containerStackViewDefaultSpacing
3333
stackView.translatesAutoresizingMaskIntoConstraints = false
3434
stackView.alignment = .center
35+
3536
return stackView
3637
}()
3738

@@ -71,6 +72,13 @@ open class UINotificationView: UIView {
7172
return imageView
7273
}()
7374

75+
var button: UIButton? {
76+
let button = self.notification.button
77+
button?.translatesAutoresizingMaskIntoConstraints = false
78+
79+
return button
80+
}
81+
7482
// MARK: Gestures
7583
internal fileprivate(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
7684
let gesture = UIPanGestureRecognizer()
@@ -104,6 +112,7 @@ open class UINotificationView: UIView {
104112

105113
layoutMargins = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)
106114

115+
addArrangedSubviewsForContainerStackView()
107116
addSubview(containerStackView)
108117

109118
setupConstraints()
@@ -124,9 +133,6 @@ open class UINotificationView: UIView {
124133
imageView.image = notification.content.image
125134
imageView.isHidden = notification.content.image == nil
126135

127-
let chevronImageWidth = chevronImageView.image?.size.width ?? 0
128-
containerStackView.spacing = imageView.isHidden ? -chevronImageWidth : containerStackViewDefaultSpacing
129-
130136
backgroundColor = notification.style.backgroundColor
131137

132138
chevronImageView.tintColor = notification.style.titleTextColor
@@ -136,6 +142,15 @@ open class UINotificationView: UIView {
136142
tapGestureRecognizer.isEnabled = notification.style.interactive
137143
}
138144

145+
open func updateForButton() {
146+
guard !subviews.isEmpty else { return }
147+
subviews.forEach { subview in
148+
subview.removeFromSuperview()
149+
}
150+
151+
setupView()
152+
}
153+
139154
/// Called when all constraints should be setup for the notification. Can be overwritten to set your own constraints.
140155
/// When setting your own constraints, you should not be calling super.
141156
open func setupConstraints() {
@@ -150,10 +165,28 @@ open class UINotificationView: UIView {
150165
imageView.widthAnchor.constraint(equalToConstant: 31),
151166
imageView.heightAnchor.constraint(equalToConstant: 31)
152167
]
168+
169+
button?.setContentHuggingPriority(.defaultHigh, for: .horizontal)
153170

154171
NSLayoutConstraint.activate(constraints)
155172
}
156173

174+
private func addArrangedSubviewsForContainerStackView() {
175+
var arrangedSubviews = [self.imageView, self.titlesStackView, self.chevronImageView]
176+
177+
if let button = self.button {
178+
arrangedSubviews.insert(button, at: arrangedSubviews.count - 1)
179+
}
180+
181+
containerStackView.arrangedSubviews.forEach { (view) in
182+
containerStackView.removeArrangedSubview(view)
183+
}
184+
185+
arrangedSubviews.forEach { (view) in
186+
containerStackView.addArrangedSubview(view)
187+
}
188+
}
189+
157190
@objc internal func handleTapGestureRecognizer() {
158191
guard let presenter = presenter, presenter.state == UINotificationPresenterState.presented else { return }
159192
notification.action?.execute()
@@ -184,9 +217,15 @@ open class UINotificationView: UIView {
184217
}
185218

186219
extension UINotificationView: UINotificationDelegate {
220+
187221
func didUpdateContent(in notificaiton: UINotification) {
188222
updateForNotificationData()
189223
}
224+
225+
func didUpdateButton(in notificaiton: UINotification) {
226+
updateForButton()
227+
}
228+
190229
}
191230

192231
extension NSLayoutConstraint {

UINotificationsTests/UINotificationDefaultViewTests.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,30 @@ final class UINotificationViewTests: UINotificationTestCase {
7575
XCTAssert(notificationView.subtitleLabel.text == updatedContent.subtitle, "Subtitle of the notification view should update accordingly")
7676
XCTAssert(notificationView.imageView.image == updatedContent.image, "Image of the notification view should update accordingly")
7777
}
78+
79+
/// It should add the button as a subview when set.
80+
func testButton() {
81+
let notificationView = UINotificationView(notification: notification)
82+
83+
XCTAssertNil(notificationView.button)
84+
85+
notification.button = UIButton(type: .system)
86+
XCTAssertNotNil(notificationView.button)
87+
XCTAssertNotNil(notificationView.button?.superview)
88+
}
89+
90+
/// It should add the button as a subview when set, even after the notification is shown.
91+
func testButtonAfterShow() {
92+
let notificationView = UINotificationView(notification: notification)
93+
94+
UINotificationCenter.current.show(notification: notification, dismissTrigger: nil)
95+
96+
XCTAssertNil(notificationView.button)
97+
notification.button = UIButton(type: .system)
98+
XCTAssertNotNil(notificationView.button)
99+
XCTAssertNotNil(notificationView.button?.superview)
100+
}
101+
78102
}
79103

80104
private struct LargeChevronStyle: UINotificationStyle {

0 commit comments

Comments
 (0)