Skip to content

Commit 10363a9

Browse files
authored
Merge pull request #6 from devpolant/feature/optional-action-buttons
Optional action buttons
2 parents 716cf7f + 3740eb7 commit 10363a9

File tree

5 files changed

+102
-48
lines changed

5 files changed

+102
-48
lines changed

NativeUI.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "NativeUI"
3-
s.version = "1.1.0"
3+
s.version = "1.2.0"
44
s.summary = "Library that includes customizable replacements for native UIKit components"
55

66
s.description = <<-DESC

NativeUI/Sources/Alert/AlertActionSequenceView.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ final class AlertActionSequenceView: UIControl {
2525

2626
private let selectionFeedbackGenerator = SelectionFeedbackGenerator()
2727

28+
override var intrinsicContentSize: CGSize {
29+
return CGSize(
30+
width: UIView.noIntrinsicMetric,
31+
height: 44
32+
)
33+
}
34+
2835
// MARK: - Subviews
2936

3037
private final class ActionView: UIView {
@@ -97,6 +104,9 @@ final class AlertActionSequenceView: UIControl {
97104
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
98105
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
99106
])
107+
108+
setContentHuggingPriority(.required, for: .vertical)
109+
setContentCompressionResistancePriority(.required, for: .vertical)
100110
}
101111

102112
// MARK: - Setup

NativeUI/Sources/Alert/AlertView.swift

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ final class AlertView: UIView {
2222

2323
// MARK: - Subviews
2424

25+
// MARK: Blur
26+
2527
private lazy var blurView: UIVisualEffectView = {
2628
let blurEffect = UIBlurEffect(style: .extraLight)
2729

@@ -32,14 +34,16 @@ final class AlertView: UIView {
3234
return effectView
3335
}()
3436

37+
// MARK: Content
38+
3539
private lazy var contentContainerView: UIView = {
3640
let containerView = UIView()
3741
containerView.translatesAutoresizingMaskIntoConstraints = false
3842
blurView.contentView.addSubview(containerView)
3943
return containerView
4044
}()
4145

42-
private lazy var verticalStackView: UIStackView = {
46+
private lazy var contentStackView: UIStackView = {
4347
let stackView = UIStackView()
4448
stackView.translatesAutoresizingMaskIntoConstraints = false
4549
contentContainerView.addSubview(stackView)
@@ -66,19 +70,26 @@ final class AlertView: UIView {
6670
return contentView
6771
}()
6872

73+
// MARK: Actions
74+
75+
private lazy var actionsStackView: UIStackView = {
76+
let stackView = UIStackView()
77+
stackView.translatesAutoresizingMaskIntoConstraints = false
78+
blurView.contentView.addSubview(stackView)
79+
return stackView
80+
}()
81+
6982
private lazy var contentSeparatorView: UIView = {
7083
let separatorView = UIView()
7184
separatorView.backgroundColor = separatorColor
7285
separatorView.translatesAutoresizingMaskIntoConstraints = false
73-
blurView.contentView.addSubview(separatorView)
7486
return separatorView
7587
}()
7688

77-
private lazy var actionsContainerView: AlertActionSequenceView = {
78-
let containerView = AlertActionSequenceView()
79-
containerView.translatesAutoresizingMaskIntoConstraints = false
80-
blurView.contentView.addSubview(containerView)
81-
return containerView
89+
private lazy var actionSequenceView: AlertActionSequenceView = {
90+
let sequenceView = AlertActionSequenceView()
91+
sequenceView.translatesAutoresizingMaskIntoConstraints = false
92+
return sequenceView
8293
}()
8394

8495
// MARK: - Init
@@ -111,35 +122,38 @@ final class AlertView: UIView {
111122
contentContainerView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
112123
contentContainerView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
113124

114-
verticalStackView.topAnchor.constraint(equalTo: contentContainerView.topAnchor, constant: Layout.Content.top),
115-
verticalStackView.leadingAnchor.constraint(equalTo: contentContainerView.leadingAnchor, constant: Layout.Content.horizontal),
116-
verticalStackView.trailingAnchor.constraint(equalTo: contentContainerView.trailingAnchor, constant: -Layout.Content.horizontal),
117-
verticalStackView.bottomAnchor.constraint(equalTo: contentContainerView.bottomAnchor, constant: -Layout.Content.bottom),
118-
119-
contentSeparatorView.topAnchor.constraint(equalTo: contentContainerView.bottomAnchor),
120-
contentSeparatorView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
121-
contentSeparatorView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
122-
contentSeparatorView.heightAnchor.constraint(equalToConstant: Layout.separatorThickness),
125+
contentStackView.topAnchor.constraint(equalTo: contentContainerView.topAnchor, constant: Layout.Content.top),
126+
contentStackView.leadingAnchor.constraint(equalTo: contentContainerView.leadingAnchor, constant: Layout.Content.horizontal),
127+
contentStackView.trailingAnchor.constraint(equalTo: contentContainerView.trailingAnchor, constant: -Layout.Content.horizontal),
128+
contentStackView.bottomAnchor.constraint(equalTo: contentContainerView.bottomAnchor, constant: -Layout.Content.bottom),
123129

124-
actionsContainerView.topAnchor.constraint(equalTo: contentSeparatorView.bottomAnchor),
125-
actionsContainerView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
126-
actionsContainerView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
127-
actionsContainerView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor),
128-
actionsContainerView.heightAnchor.constraint(equalToConstant: Layout.Button.height)
130+
actionsStackView.topAnchor.constraint(equalTo: contentContainerView.bottomAnchor),
131+
actionsStackView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
132+
actionsStackView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
133+
actionsStackView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor)
129134
])
130135

131-
verticalStackView.axis = .vertical
132-
verticalStackView.spacing = Layout.Content.verticalSpacing
133-
verticalStackView.addArrangedSubview(titleLabel)
134-
verticalStackView.addArrangedSubview(messageLabel)
135-
verticalStackView.addArrangedSubview(customContentView)
136+
contentStackView.axis = .vertical
137+
contentStackView.spacing = Layout.Content.verticalSpacing
138+
contentStackView.addArrangedSubview(titleLabel)
139+
contentStackView.addArrangedSubview(messageLabel)
140+
contentStackView.addArrangedSubview(customContentView)
141+
142+
actionsStackView.axis = .vertical
143+
actionsStackView.spacing = 0
144+
actionsStackView.addArrangedSubview(contentSeparatorView)
145+
actionsStackView.addArrangedSubview(actionSequenceView)
146+
147+
NSLayoutConstraint.activate([
148+
contentSeparatorView.heightAnchor.constraint(equalToConstant: Layout.separatorThickness)
149+
])
136150

137-
titleLabel.setContentHuggingPriority(.required, for: .vertical)
138-
titleLabel.setContentCompressionResistancePriority(.required, for: .vertical)
139-
messageLabel.setContentHuggingPriority(.required, for: .vertical)
140-
messageLabel.setContentCompressionResistancePriority(.required, for: .vertical)
151+
[titleLabel, messageLabel].forEach {
152+
$0.setContentHuggingPriority(.required, for: .vertical)
153+
$0.setContentCompressionResistancePriority(.required, for: .vertical)
154+
}
141155

142-
actionsContainerView.delegate = self
156+
actionSequenceView.delegate = self
143157
}
144158

145159
private func setupAppearance() {
@@ -191,13 +205,17 @@ final class AlertView: UIView {
191205
}
192206
customContentView.isHidden = viewModel.contentView == nil
193207

194-
let actionsViewModel = AlertActionSequenceViewModel(
195-
actions: viewModel.actions,
196-
disabledTintColor: viewModel.disabledTintColor,
197-
separatorColor: separatorColor,
198-
separatorWidth: Layout.separatorThickness
199-
)
200-
actionsContainerView.setup(viewModel: actionsViewModel)
208+
if !viewModel.actions.isEmpty {
209+
let actionsViewModel = AlertActionSequenceViewModel(
210+
actions: viewModel.actions,
211+
disabledTintColor: viewModel.disabledTintColor,
212+
separatorColor: separatorColor,
213+
separatorWidth: Layout.separatorThickness
214+
)
215+
actionSequenceView.setup(viewModel: actionsViewModel)
216+
}
217+
contentSeparatorView.isHidden = viewModel.actions.isEmpty
218+
actionSequenceView.isHidden = viewModel.actions.isEmpty
201219
}
202220

203221
// MARK: - Layout
@@ -214,10 +232,6 @@ final class AlertView: UIView {
214232
static let horizontal: CGFloat = 16
215233
static let verticalSpacing: CGFloat = 4
216234
}
217-
218-
enum Button {
219-
static let height: CGFloat = 44
220-
}
221235
}
222236
}
223237

NativeUI/Sources/Alert/AlertViewController.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,19 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
1212

1313
public var shouldDismissAutomatically: Bool = true
1414

15+
public var shouldDismissOnBackgroundTap: Bool = false
16+
1517
private var viewModel: Alert
1618

1719
// MARK: - Subviews
1820

21+
private lazy var backgroundView: UIView = {
22+
let backgroundView = UIView()
23+
backgroundView.translatesAutoresizingMaskIntoConstraints = false
24+
view.addSubview(backgroundView)
25+
return backgroundView
26+
}()
27+
1928
private(set) lazy var alertView: AlertView = {
2029
let alertView = AlertView()
2130
alertView.translatesAutoresizingMaskIntoConstraints = false
@@ -30,6 +39,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
3039
super.init(nibName: nil, bundle: nil)
3140
modalPresentationStyle = .custom
3241
transitioningDelegate = self
42+
shouldDismissOnBackgroundTap = viewModel.actions.isEmpty
3343
}
3444

3545
required init?(coder: NSCoder) {
@@ -42,6 +52,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
4252
super.viewDidLoad()
4353
setupAppearance()
4454
setupLayout()
55+
setupGestures()
4556
setupViewModel()
4657
}
4758

@@ -54,7 +65,7 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
5465
// MARK: - UI Setup
5566

5667
private func setupAppearance() {
57-
view.backgroundColor = UIColor.black.withAlphaComponent(0.2)
68+
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
5869

5970
if let tintColor = viewModel.tintColor {
6071
view.tintColor = tintColor
@@ -77,18 +88,37 @@ public final class AlertViewController: UIViewController, AlertViewDelegate {
7788
}
7889

7990
NSLayoutConstraint.activate([
91+
backgroundView.topAnchor.constraint(equalTo: view.topAnchor),
92+
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
93+
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
94+
backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
95+
8096
alertView.widthAnchor.constraint(equalToConstant: Layout.width),
8197
alertView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
8298
alertView.centerYAnchor.constraint(equalTo: safeAreaLayoutGuide.centerYAnchor),
8399
alertView.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor, constant: Layout.verticalInset)
84100
])
85101
}
86102

103+
private func setupGestures() {
104+
guard shouldDismissOnBackgroundTap else {
105+
return
106+
}
107+
let recognizer = UITapGestureRecognizer(target: self, action: #selector(actionBackgroundViewTapped(sender:)))
108+
backgroundView.addGestureRecognizer(recognizer)
109+
}
110+
87111
private func setupViewModel() {
88112
alertView.delegate = self
89113
alertView.setup(viewModel: viewModel)
90114
}
91115

116+
// MARK: - Actions
117+
118+
@objc private func actionBackgroundViewTapped(sender: UIGestureRecognizer) {
119+
dismiss(animated: true, completion: nil)
120+
}
121+
92122
// MARK: - Layout
93123

94124
private enum Layout {

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
# NativeUI
77

8-
## Requirements:
8+
## Minimum Requirements:
99
- iOS 9.0
10-
- Xcode 11.0
10+
- Xcode 12.0
1111
- Swift 5
1212

1313
## Installation
@@ -16,15 +16,15 @@
1616

1717
```ruby
1818
target 'MyApp' do
19-
pod 'NativeUI', '~> 1.1'
19+
pod 'NativeUI', '~> 1.2'
2020
end
2121
```
2222

2323
If you don't need to connect all UI components you may use subspecs like:
2424

2525
```ruby
2626
target 'MyApp' do
27-
pod 'NativeUI/Alert', '~> 1.1'
27+
pod 'NativeUI/Alert', '~> 1.2'
2828
end
2929
```
3030

0 commit comments

Comments
 (0)