├── SwiftAlertView
├── Images
│ └── demo.png
├── Marker Felt.ttf
├── Assets.xcassets
│ ├── Contents.json
│ ├── alert-box.imageset
│ │ ├── alert-box@2x.png
│ │ └── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── Info.plist
├── CustomView.xib
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
└── ViewController.swift
├── SwiftAlertView.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── SwiftAlertView.podspec
├── LICENSE
├── Package.swift
├── .gitignore
├── README.md
└── Source
└── SwiftAlertView.swift
/SwiftAlertView/Images/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinhquan/SwiftAlertView/HEAD/SwiftAlertView/Images/demo.png
--------------------------------------------------------------------------------
/SwiftAlertView/Marker Felt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinhquan/SwiftAlertView/HEAD/SwiftAlertView/Marker Felt.ttf
--------------------------------------------------------------------------------
/SwiftAlertView/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SwiftAlertView/Assets.xcassets/alert-box.imageset/alert-box@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinhquan/SwiftAlertView/HEAD/SwiftAlertView/Assets.xcassets/alert-box.imageset/alert-box@2x.png
--------------------------------------------------------------------------------
/SwiftAlertView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftAlertView/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SwiftAlertView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwiftAlertView/Assets.xcassets/alert-box.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "alert-box@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwiftAlertView/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftAlertView
4 | //
5 | // Created by Quan on 10/27/21.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 |
19 | return true
20 | }
21 |
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/SwiftAlertView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "SwiftAlertView"
4 | s.version = "2.2.1"
5 | s.summary = "A powerful customizable Alert View written in Swift."
6 | s.description = <<-DESC
7 | SwiftAlertView is a powerful customizable Alert View written in Swift. With SwiftAlertView, you can easily make your desired Alert View in some lines of code.
8 | DESC
9 |
10 | s.homepage = "https://github.com/dinhquan/SwiftAlertView"
11 | s.license = { :type => 'MIT', :file => 'LICENSE' }
12 | s.author = { 'Dinh Quan' => 'dinhquan191@gmail.com' }
13 | s.platform = :ios
14 | s.source = { :git => "https://github.com/dinhquan/SwiftAlertView.git", :tag => s.version }
15 | s.source_files = 'Source/*.swift'
16 | s.ios.deployment_target = "10.0"
17 | s.swift_version = "5.0"
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 dinhquan
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 |
23 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | //
3 | // Package.swift
4 | //
5 | // Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/)
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in
15 | // all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | // THE SOFTWARE.
24 | //
25 | import PackageDescription
26 |
27 | let package = Package(name: "SwiftAlertView",
28 | platforms: [.macOS(.v10_12), .iOS(.v10), .tvOS(.v10), .watchOS(.v3)],
29 | products: [
30 | .library(name: "SwiftAlertView", targets: ["SwiftAlertView"])
31 | ],
32 | targets: [
33 | .target(name: "SwiftAlertView", path: "Source")
34 | ],
35 | swiftLanguageVersions: [.v5]
36 | )
37 |
--------------------------------------------------------------------------------
/SwiftAlertView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIAppFonts
24 |
25 | Marker Felt.ttf
26 |
27 | UIApplicationSupportsIndirectInputEvents
28 |
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIMainStoryboardFile
32 | Main
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationLandscapeLeft
41 | UIInterfaceOrientationLandscapeRight
42 |
43 | UISupportedInterfaceOrientations~ipad
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/SwiftAlertView/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
--------------------------------------------------------------------------------
/SwiftAlertView/CustomView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SwiftAlertView/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/SwiftAlertView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/SwiftAlertView/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SwiftAlertViewDemo
4 | //
5 | // Created by Dinh Quan on 8/28/15.
6 | // Copyright (c) 2015 Dinh Quan. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ViewController: UITableViewController {
12 |
13 | let demoTitles: [String] = ["Dark Mode",
14 | "Alert with Text Field",
15 | "More Text Fields & Validation Label",
16 | "Customize Font & Color",
17 | "Custom Content View",
18 | "Init From Nib File",
19 | "Custom Background Image",
20 | "Customize Transition Type"]
21 |
22 | override func viewDidLoad() {
23 | super.viewDidLoad()
24 | }
25 |
26 | // MARK: TableView Delegate & Datasource
27 |
28 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
29 | tableView.deselectRow(at: indexPath as IndexPath, animated: false)
30 |
31 | switch indexPath.row {
32 | case 0:
33 | SwiftAlertView.show(title: "Lorem ipsum",
34 | message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
35 | buttonTitles: "Cancel", "Ok") {
36 | $0.style = .dark
37 | }
38 | .onButtonClicked { _, buttonIndex in
39 | print("Button Clicked At Index \(buttonIndex)")
40 | }
41 |
42 | case 1:
43 | SwiftAlertView.show(title: "Title",
44 | message: "Message",
45 | buttonTitles: "Button 1", "Button 2", "Button 3", "Cancel") { alertView in
46 | alertView.cancelButtonIndex = 3
47 | alertView.buttonTitleColor = UIColor(red: 0.8764, green: 0.5, blue: 0.3352, alpha: 1)
48 | alertView.addTextField { textField in
49 | textField.placeholder = "Placeholder"
50 | }
51 | }
52 | .onActionButtonClicked { alert, buttonIndex in
53 | let text = alert.textField(at: 0)?.text ?? ""
54 | print("Text: ", text)
55 | }
56 |
57 | case 2:
58 | SwiftAlertView.show(title: "Sign in", buttonTitles: "Cancel", "Sign In") { alertView in
59 | alertView.addTextField { textField in
60 | textField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [.foregroundColor: UIColor.gray])
61 | }
62 | alertView.addTextField { textField in
63 | textField.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [.foregroundColor: UIColor.gray])
64 | }
65 | alertView.isEnabledValidationLabel = true
66 | alertView.isDismissOnActionButtonClicked = false
67 | alertView.style = .dark
68 | }
69 | .onActionButtonClicked { alert, buttonIndex in
70 | let username = alert.textField(at: 0)?.text ?? ""
71 | if username.isEmpty {
72 | alert.validationLabel.text = "Username is incorrect"
73 | } else {
74 | alert.dismiss()
75 | }
76 | }
77 | .onTextChanged { _, text, index in
78 | if index == 0 {
79 | print("Username text changed: ", text ?? "")
80 | }
81 | }
82 |
83 | case 3:
84 | let alertView = SwiftAlertView(title: "Lorem ipsum",
85 | message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
86 | buttonTitles: ["Cancel", "OK"])
87 |
88 | alertView.backgroundColor = UIColor(red: 0.9852, green: 0.9827, blue: 0.92, alpha: 1)
89 | alertView.titleLabel.textColor = UIColor(red: 0.0, green: 0.7253, blue: 0.6017, alpha: 1)
90 | alertView.messageLabel.textColor = UIColor.orange
91 | alertView.titleLabel.font = UIFont(name: "Marker Felt", size: 30)
92 | alertView.messageLabel.font = UIFont(name: "Marker Felt", size: 20)
93 | alertView.button(at: 0)?.setTitleColor(.purple, for: .normal)
94 | alertView.button(at: 1)?.setTitleColor(.purple, for: .normal)
95 | alertView.button(at: 0)?.titleLabel?.font = UIFont(name: "Marker Felt", size: 20)
96 | alertView.button(at: 1)?.titleLabel?.font = UIFont(name: "Marker Felt", size: 20)
97 | alertView.delegate = self
98 | alertView.show()
99 |
100 | case 4:
101 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
102 | let label = UILabel(frame: CGRect(x: 20, y: 0, width: 160, height: 200))
103 | label.text = "This is the custom content view"
104 | label.numberOfLines = 0
105 | label.lineBreakMode = .byWordWrapping
106 | label.textAlignment = .center
107 | view.addSubview(label)
108 | view.backgroundColor = .yellow
109 |
110 | let alertView = SwiftAlertView(contentView: view, buttonTitles: ["Cancel", "OK"])
111 | alertView.show()
112 |
113 | case 5:
114 | let alertView = SwiftAlertView(nibName: "CustomView", buttonTitles: ["I love this feature"])
115 | alertView.show()
116 |
117 | case 6:
118 | let alertView = SwiftAlertView(title: "Custom Background Image",
119 | message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
120 | buttonTitles: ["Cancel", "Button 1", "Button 2", "Button 3"])
121 | alertView.backgroundImage = #imageLiteral(resourceName: "alert-box")
122 | alertView.show()
123 |
124 | case 7:
125 | let alertView = SwiftAlertView(title: "Lorem ipsum",
126 | message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
127 | buttonTitles: ["Cancel", "Button 1", "Button 2", "Button 3"])
128 | alertView.transitionType = .vertical
129 | alertView.appearTime = 0.2
130 | alertView.disappearTime = 0.2
131 | alertView.show()
132 | default:
133 | ()
134 | }
135 | }
136 |
137 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
138 | let cell = tableView.dequeueReusableCell(withIdentifier: "DemoCell", for: indexPath as IndexPath) as UITableViewCell
139 | cell.textLabel?.text = demoTitles[indexPath.row]
140 | return cell
141 | }
142 |
143 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
144 | return demoTitles.count
145 | }
146 | }
147 |
148 | // MARK: SwiftAlertViewDelegate
149 |
150 | extension ViewController: SwiftAlertViewDelegate {
151 | func alertView(_ alertView: SwiftAlertView, clickedButtonAtIndex buttonIndex: Int) {
152 | print("Button Clicked At Index \(buttonIndex)")
153 | }
154 |
155 | func didPresentAlertView(alertView: SwiftAlertView) {
156 | print("Did Present Alert View\n")
157 | }
158 |
159 | func didDismissAlertView(alertView: SwiftAlertView) {
160 | print("Did Dismiss Alert View\n")
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SwiftAlertView
2 | ===========
3 |
4 | A powerful customizable Alert View library written in Swift.
5 |
6 | `SwiftAlertView` is the best alternative for `UIAlertController` and `SwiftUI alert`.
7 | With `SwiftAlertView`, you can easily make your desired Alert View in some lines of code.
8 |
9 | 
10 |
11 | ## Highlight Features
12 |
13 | | Features | SwiftAlertView | UIAlertController |
14 | | - | - | - |
15 | | Change button color | :white_check_mark: | :white_check_mark: |
16 | | Change button font | :white_check_mark: | :x: |
17 | | Change title, message color/font | :white_check_mark: | :x: |
18 | | Change title, message margin | :white_check_mark: | :x: |
19 | | Change background color/image | :white_check_mark: | :x: |
20 | | Change dim background color | :white_check_mark: | :x: |
21 | | Change border radius, separator color | :white_check_mark: | :x: |
22 | | Dark mode | :white_check_mark: | :white_check_mark: |
23 | | Add text fields | :white_check_mark: | :white_check_mark: |
24 | | Callback for handling text changed | :white_check_mark: | :x: |
25 | | Init alert with custom view/xib file | :white_check_mark: | :x: |
26 | | TextField Validation Label | :white_check_mark: | :x: |
27 | | Customize transtion type | :white_check_mark: | :x: |
28 | | Easy-to-use APIs | Super easy | Not so easy |
29 |
30 | ## Installation
31 |
32 | #### CocoaPods
33 |
34 | ```ruby
35 | pod 'SwiftAlertView', '~> 2.2.1'
36 | ```
37 |
38 | #### Carthage
39 |
40 | ```ogdl
41 | github "https://github.com/dinhquan/SwiftAlertView" ~> 2.2.1
42 | ```
43 |
44 | #### Swift Package Manager
45 |
46 | ```swift
47 | dependencies: [
48 | .package(url: "https://github.com/dinhquan/SwiftAlertView", .upToNextMajor(from: "2.2.1"))
49 | ]
50 | ```
51 |
52 | #### Manually
53 | Drag and drop the file named ```SwiftAlertView``` inside `Source` in your project and you are done.
54 |
55 | ## Usage
56 |
57 | ### Showing alert
58 |
59 | ```swift
60 | SwiftAlertView.show(title: "Title", message: "Message", buttonTitles: "Cancel", "OK")
61 | ```
62 |
63 | Customization
64 |
65 | ```swift
66 | SwiftAlertView.show(title: "Title",
67 | message: "Message",
68 | buttonTitles: "OK", "Cancel") { alert in
69 | alert.backgroundColor = .yellow
70 | alert.cancelButtonIndex = 1
71 | alert.buttonTitleColor = .blue
72 | }
73 | ```
74 |
75 | Handle button clicked events
76 |
77 | ```swift
78 | SwiftAlertView.show(title: "Title",
79 | message: "Message",
80 | buttonTitles: "Cancel", "OK") {
81 | $0.style = .dark
82 | }
83 | .onButtonClicked { _, buttonIndex in
84 | print("Button Clicked At Index \(buttonIndex)")
85 | }
86 | ```
87 |
88 | Add text fields
89 |
90 | ```swift
91 | SwiftAlertView.show(title: "Sign in", buttonTitles: "Cancel", "Sign In") { alertView in
92 | alertView.addTextField { textField in
93 | textField.placeholder = "Username"
94 | }
95 | alertView.addTextField { textField in
96 | textField.placeholder = "Password"
97 | }
98 | alertView.isEnabledValidationLabel = true
99 | alertView.isDismissOnActionButtonClicked = false
100 | }
101 | .onActionButtonClicked { alertView, buttonIndex in
102 | let username = alert.textField(at: 0)?.text ?? ""
103 | if username.isEmpty {
104 | alertView.validationLabel.text = "Username is incorrect"
105 | } else {
106 | alertView.dismiss()
107 | }
108 | }
109 | .onTextChanged { _, text, textFieldIndex in
110 | if textFieldIndex == 0 {
111 | print("Username text changed: ", text ?? "")
112 | }
113 | }
114 | ```
115 |
116 | You can show alert with custom content view
117 |
118 | ```swift
119 | // with xib file
120 | SwiftAlertView.show(nibName: "CustomView", buttonTitles: "OK")
121 |
122 | // with custom UIView
123 | SwiftAlertView.show(contentView: customView, buttonTitles: "OK")
124 | ```
125 |
126 | ### Programmatically creating an alert
127 |
128 | Initialize an alert
129 |
130 | ```swift
131 | let alertView = SwiftAlertView(title: "Title", message: "Message", buttonTitles: "Cancel", "Button 1", "Button 2", "Button 3")
132 |
133 | let alertView = SwiftAlertView(contentView: customView, buttonTitles: "OK")
134 |
135 | let alertView = SwiftAlertView(nibName: "CustomView", buttonTitles: "OK")
136 | ```
137 |
138 | Show or dismiss
139 |
140 | ```swift
141 | // Show at center of screen
142 | alertView.show()
143 |
144 | // Show at center of a view
145 | alertView.show(in: view)
146 |
147 | // Programmatically dismiss the alert view
148 | alertView.dismiss()
149 | ```
150 |
151 | Handle button clicked event
152 |
153 | ```swift
154 |
155 | alertView.onButtonClicked { _, buttonIndex in
156 | print("Button Clicked At Index \(buttonIndex)")
157 | }
158 | alertView.onActionButtonClicked { _, buttonIndex in
159 | print("Action Button Clicked At Index \(buttonIndex)")
160 | }
161 | ```
162 |
163 | If you don't want to use closures, make your view controller conform ```SwiftAlertViewDelegate``` and use delegate methods:
164 |
165 | ```swift
166 | alertView.delegate = self
167 |
168 | func alertView(_ alertView: SwiftAlertView, clickedButtonAtIndex buttonIndex: Int) {
169 | println("Button Clicked At Index \(buttonIndex)")
170 | }
171 |
172 | func didPresentAlertView(_ alertView: SwiftAlertView) {
173 | println("Did Present Alert View")
174 | }
175 |
176 | func didDismissAlertView(_ alertView: SwiftAlertView) {
177 | println("Did Dismiss Alert View")
178 | }
179 | ```
180 | ### Customization
181 |
182 | SwiftAlertView can be customized with the following properties:
183 |
184 | ```swift
185 | public var style: Style = .auto // default is based on system color
186 |
187 | public var titleLabel: UILabel! // access titleLabel to customize the title font, color
188 | public var messageLabel: UILabel! // access messageLabel to customize the message font, color
189 |
190 | public var backgroundImage: UIImage?
191 | // public var backgroundColor: UIColor? // inherits from UIView
192 |
193 | public var cancelButtonIndex = 0 // default is 0, set this property if you want to change the position of cancel button
194 | public var buttonTitleColor = UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1) // to change the title color of all buttons
195 | public var buttonHeight: CGFloat = 44.0
196 |
197 | public var separatorColor = UIColor(red: 196.0/255, green: 196.0/255, blue: 201.0/255, alpha: 1.0) // to change the separator color
198 | public var isHideSeparator = false
199 | public var cornerRadius: CGFloat = 12.0
200 |
201 | public var isDismissOnActionButtonClicked = true // default is true, if you want the alert view will not be dismissed when clicking on action buttons, set this property to false
202 | public var isHighlightOnButtonClicked = true
203 | public var isDimBackgroundWhenShowing = true
204 | public var isDismissOnOutsideTapped = false
205 | public var dimAlpha: CGFloat = 0.4
206 | public var dimBackgroundColor: UIColor? = .init(white: 0, alpha: 0.4)
207 |
208 | public var appearTime = 0.2
209 | public var disappearTime = 0.1
210 |
211 | public var transitionType: TransitionType = .default
212 |
213 | // customize the margin & spacing of title & message
214 | public var titleSideMargin: CGFloat = 20.0
215 | public var messageSideMargin: CGFloat = 20.0
216 | public var titleTopMargin: CGFloat = 20.0
217 | public var messageBottomMargin: CGFloat = 20.0
218 | public var titleToMessageSpacing: CGFloat = 20.0
219 |
220 | // customize text fields
221 | public var textFieldHeight: CGFloat = 34.0
222 | public var textFieldSideMargin: CGFloat = 15.0
223 | public var textFieldBottomMargin: CGFloat = 15.0
224 | public var textFieldSpacing: CGFloat = 10.0
225 | public var isFocusTextFieldWhenShowing = true
226 | public var isEnabledValidationLabel = false
227 | public var validationLabel: UILabel! // access to validation label to customize font, color
228 | public var validationLabelTopMargin: CGFloat = 8.0
229 | public var validationLabelSideMargin: CGFloat = 15.0
230 | ```
231 |
232 | ## Contributing
233 | Contributions for bug fixing or improvements are welcomed. Feel free to submit a pull request.
234 | If you have any questions, feature suggestions or bug reports, please send me an email to dinhquan191@gmail.com.
235 |
236 |
--------------------------------------------------------------------------------
/SwiftAlertView.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 146BEE62272930E90004D971 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 146BEE61272930E90004D971 /* AppDelegate.swift */; };
11 | 146BEE66272930E90004D971 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 146BEE65272930E90004D971 /* ViewController.swift */; };
12 | 146BEE69272930E90004D971 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 146BEE67272930E90004D971 /* Main.storyboard */; };
13 | 146BEE6B272930EB0004D971 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 146BEE6A272930EB0004D971 /* Assets.xcassets */; };
14 | 146BEE6E272930EB0004D971 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 146BEE6C272930EB0004D971 /* LaunchScreen.storyboard */; };
15 | 146BEE76272931A80004D971 /* CustomView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 146BEE75272931A80004D971 /* CustomView.xib */; };
16 | 146BEE792729328C0004D971 /* SwiftAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 146BEE782729328C0004D971 /* SwiftAlertView.swift */; };
17 | 14B4714B279106A800634E54 /* SwiftAlertView.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 14B47147279106A700634E54 /* SwiftAlertView.podspec */; };
18 | 14B4714D279106A800634E54 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 14B47149279106A800634E54 /* LICENSE */; };
19 | 14B4714E279106A800634E54 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 14B4714A279106A800634E54 /* README.md */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 146BEE5E272930E90004D971 /* SwiftAlertView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftAlertView.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 146BEE61272930E90004D971 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | 146BEE65272930E90004D971 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
26 | 146BEE68272930E90004D971 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
27 | 146BEE6A272930EB0004D971 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
28 | 146BEE6D272930EB0004D971 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | 146BEE6F272930EB0004D971 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | 146BEE75272931A80004D971 /* CustomView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomView.xib; sourceTree = ""; };
31 | 146BEE782729328C0004D971 /* SwiftAlertView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftAlertView.swift; sourceTree = ""; };
32 | 146BEE7A272932F20004D971 /* Marker Felt.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Marker Felt.ttf"; sourceTree = ""; };
33 | 14B47147279106A700634E54 /* SwiftAlertView.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SwiftAlertView.podspec; sourceTree = ""; };
34 | 14B47149279106A800634E54 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
35 | 14B4714A279106A800634E54 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
36 | /* End PBXFileReference section */
37 |
38 | /* Begin PBXFrameworksBuildPhase section */
39 | 146BEE5B272930E90004D971 /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | );
44 | runOnlyForDeploymentPostprocessing = 0;
45 | };
46 | /* End PBXFrameworksBuildPhase section */
47 |
48 | /* Begin PBXGroup section */
49 | 146BEE55272930E90004D971 = {
50 | isa = PBXGroup;
51 | children = (
52 | 14B47149279106A800634E54 /* LICENSE */,
53 | 14B4714A279106A800634E54 /* README.md */,
54 | 14B47147279106A700634E54 /* SwiftAlertView.podspec */,
55 | 146BEE772729328C0004D971 /* Source */,
56 | 146BEE60272930E90004D971 /* SwiftAlertView */,
57 | 146BEE5F272930E90004D971 /* Products */,
58 | );
59 | sourceTree = "";
60 | };
61 | 146BEE5F272930E90004D971 /* Products */ = {
62 | isa = PBXGroup;
63 | children = (
64 | 146BEE5E272930E90004D971 /* SwiftAlertView.app */,
65 | );
66 | name = Products;
67 | sourceTree = "";
68 | };
69 | 146BEE60272930E90004D971 /* SwiftAlertView */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 146BEE61272930E90004D971 /* AppDelegate.swift */,
73 | 146BEE65272930E90004D971 /* ViewController.swift */,
74 | 146BEE67272930E90004D971 /* Main.storyboard */,
75 | 146BEE75272931A80004D971 /* CustomView.xib */,
76 | 146BEE6A272930EB0004D971 /* Assets.xcassets */,
77 | 146BEE7A272932F20004D971 /* Marker Felt.ttf */,
78 | 146BEE6C272930EB0004D971 /* LaunchScreen.storyboard */,
79 | 146BEE6F272930EB0004D971 /* Info.plist */,
80 | );
81 | path = SwiftAlertView;
82 | sourceTree = "";
83 | };
84 | 146BEE772729328C0004D971 /* Source */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 146BEE782729328C0004D971 /* SwiftAlertView.swift */,
88 | );
89 | path = Source;
90 | sourceTree = "";
91 | };
92 | /* End PBXGroup section */
93 |
94 | /* Begin PBXNativeTarget section */
95 | 146BEE5D272930E90004D971 /* SwiftAlertView */ = {
96 | isa = PBXNativeTarget;
97 | buildConfigurationList = 146BEE72272930EB0004D971 /* Build configuration list for PBXNativeTarget "SwiftAlertView" */;
98 | buildPhases = (
99 | 146BEE5A272930E90004D971 /* Sources */,
100 | 146BEE5B272930E90004D971 /* Frameworks */,
101 | 146BEE5C272930E90004D971 /* Resources */,
102 | );
103 | buildRules = (
104 | );
105 | dependencies = (
106 | );
107 | name = SwiftAlertView;
108 | productName = SwiftAlertView;
109 | productReference = 146BEE5E272930E90004D971 /* SwiftAlertView.app */;
110 | productType = "com.apple.product-type.application";
111 | };
112 | /* End PBXNativeTarget section */
113 |
114 | /* Begin PBXProject section */
115 | 146BEE56272930E90004D971 /* Project object */ = {
116 | isa = PBXProject;
117 | attributes = {
118 | LastSwiftUpdateCheck = 1250;
119 | LastUpgradeCheck = 1310;
120 | TargetAttributes = {
121 | 146BEE5D272930E90004D971 = {
122 | CreatedOnToolsVersion = 12.5.1;
123 | };
124 | };
125 | };
126 | buildConfigurationList = 146BEE59272930E90004D971 /* Build configuration list for PBXProject "SwiftAlertView" */;
127 | compatibilityVersion = "Xcode 9.3";
128 | developmentRegion = en;
129 | hasScannedForEncodings = 0;
130 | knownRegions = (
131 | en,
132 | Base,
133 | );
134 | mainGroup = 146BEE55272930E90004D971;
135 | productRefGroup = 146BEE5F272930E90004D971 /* Products */;
136 | projectDirPath = "";
137 | projectRoot = "";
138 | targets = (
139 | 146BEE5D272930E90004D971 /* SwiftAlertView */,
140 | );
141 | };
142 | /* End PBXProject section */
143 |
144 | /* Begin PBXResourcesBuildPhase section */
145 | 146BEE5C272930E90004D971 /* Resources */ = {
146 | isa = PBXResourcesBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | 14B4714D279106A800634E54 /* LICENSE in Resources */,
150 | 146BEE6E272930EB0004D971 /* LaunchScreen.storyboard in Resources */,
151 | 146BEE76272931A80004D971 /* CustomView.xib in Resources */,
152 | 14B4714E279106A800634E54 /* README.md in Resources */,
153 | 14B4714B279106A800634E54 /* SwiftAlertView.podspec in Resources */,
154 | 146BEE6B272930EB0004D971 /* Assets.xcassets in Resources */,
155 | 146BEE69272930E90004D971 /* Main.storyboard in Resources */,
156 | );
157 | runOnlyForDeploymentPostprocessing = 0;
158 | };
159 | /* End PBXResourcesBuildPhase section */
160 |
161 | /* Begin PBXSourcesBuildPhase section */
162 | 146BEE5A272930E90004D971 /* Sources */ = {
163 | isa = PBXSourcesBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | 146BEE792729328C0004D971 /* SwiftAlertView.swift in Sources */,
167 | 146BEE66272930E90004D971 /* ViewController.swift in Sources */,
168 | 146BEE62272930E90004D971 /* AppDelegate.swift in Sources */,
169 | );
170 | runOnlyForDeploymentPostprocessing = 0;
171 | };
172 | /* End PBXSourcesBuildPhase section */
173 |
174 | /* Begin PBXVariantGroup section */
175 | 146BEE67272930E90004D971 /* Main.storyboard */ = {
176 | isa = PBXVariantGroup;
177 | children = (
178 | 146BEE68272930E90004D971 /* Base */,
179 | );
180 | name = Main.storyboard;
181 | sourceTree = "";
182 | };
183 | 146BEE6C272930EB0004D971 /* LaunchScreen.storyboard */ = {
184 | isa = PBXVariantGroup;
185 | children = (
186 | 146BEE6D272930EB0004D971 /* Base */,
187 | );
188 | name = LaunchScreen.storyboard;
189 | sourceTree = "";
190 | };
191 | /* End PBXVariantGroup section */
192 |
193 | /* Begin XCBuildConfiguration section */
194 | 146BEE70272930EB0004D971 /* Debug */ = {
195 | isa = XCBuildConfiguration;
196 | buildSettings = {
197 | ALWAYS_SEARCH_USER_PATHS = NO;
198 | CLANG_ANALYZER_NONNULL = YES;
199 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
200 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
201 | CLANG_CXX_LIBRARY = "libc++";
202 | CLANG_ENABLE_MODULES = YES;
203 | CLANG_ENABLE_OBJC_ARC = YES;
204 | CLANG_ENABLE_OBJC_WEAK = YES;
205 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
206 | CLANG_WARN_BOOL_CONVERSION = YES;
207 | CLANG_WARN_COMMA = YES;
208 | CLANG_WARN_CONSTANT_CONVERSION = YES;
209 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
212 | CLANG_WARN_EMPTY_BODY = YES;
213 | CLANG_WARN_ENUM_CONVERSION = YES;
214 | CLANG_WARN_INFINITE_RECURSION = YES;
215 | CLANG_WARN_INT_CONVERSION = YES;
216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
217 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
220 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
222 | CLANG_WARN_STRICT_PROTOTYPES = YES;
223 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
224 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
225 | CLANG_WARN_UNREACHABLE_CODE = YES;
226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
227 | COPY_PHASE_STRIP = NO;
228 | DEBUG_INFORMATION_FORMAT = dwarf;
229 | ENABLE_STRICT_OBJC_MSGSEND = YES;
230 | ENABLE_TESTABILITY = YES;
231 | GCC_C_LANGUAGE_STANDARD = gnu11;
232 | GCC_DYNAMIC_NO_PIC = NO;
233 | GCC_NO_COMMON_BLOCKS = YES;
234 | GCC_OPTIMIZATION_LEVEL = 0;
235 | GCC_PREPROCESSOR_DEFINITIONS = (
236 | "DEBUG=1",
237 | "$(inherited)",
238 | );
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
246 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
247 | MTL_FAST_MATH = YES;
248 | ONLY_ACTIVE_ARCH = YES;
249 | SDKROOT = iphoneos;
250 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
251 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
252 | };
253 | name = Debug;
254 | };
255 | 146BEE71272930EB0004D971 /* Release */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_ANALYZER_NONNULL = YES;
260 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
262 | CLANG_CXX_LIBRARY = "libc++";
263 | CLANG_ENABLE_MODULES = YES;
264 | CLANG_ENABLE_OBJC_ARC = YES;
265 | CLANG_ENABLE_OBJC_WEAK = YES;
266 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
267 | CLANG_WARN_BOOL_CONVERSION = YES;
268 | CLANG_WARN_COMMA = YES;
269 | CLANG_WARN_CONSTANT_CONVERSION = YES;
270 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
272 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
273 | CLANG_WARN_EMPTY_BODY = YES;
274 | CLANG_WARN_ENUM_CONVERSION = YES;
275 | CLANG_WARN_INFINITE_RECURSION = YES;
276 | CLANG_WARN_INT_CONVERSION = YES;
277 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
278 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
279 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
281 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
283 | CLANG_WARN_STRICT_PROTOTYPES = YES;
284 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
285 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
286 | CLANG_WARN_UNREACHABLE_CODE = YES;
287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
288 | COPY_PHASE_STRIP = NO;
289 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
290 | ENABLE_NS_ASSERTIONS = NO;
291 | ENABLE_STRICT_OBJC_MSGSEND = YES;
292 | GCC_C_LANGUAGE_STANDARD = gnu11;
293 | GCC_NO_COMMON_BLOCKS = YES;
294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
296 | GCC_WARN_UNDECLARED_SELECTOR = YES;
297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
298 | GCC_WARN_UNUSED_FUNCTION = YES;
299 | GCC_WARN_UNUSED_VARIABLE = YES;
300 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
301 | MTL_ENABLE_DEBUG_INFO = NO;
302 | MTL_FAST_MATH = YES;
303 | SDKROOT = iphoneos;
304 | SWIFT_COMPILATION_MODE = wholemodule;
305 | SWIFT_OPTIMIZATION_LEVEL = "-O";
306 | VALIDATE_PRODUCT = YES;
307 | };
308 | name = Release;
309 | };
310 | 146BEE73272930EB0004D971 /* Debug */ = {
311 | isa = XCBuildConfiguration;
312 | buildSettings = {
313 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
314 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
315 | CODE_SIGN_STYLE = Automatic;
316 | INFOPLIST_FILE = SwiftAlertView/Info.plist;
317 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
318 | LD_RUNPATH_SEARCH_PATHS = (
319 | "$(inherited)",
320 | "@executable_path/Frameworks",
321 | );
322 | PRODUCT_BUNDLE_IDENTIFIER = com.dinhquan.SwiftAlertView;
323 | PRODUCT_NAME = "$(TARGET_NAME)";
324 | SWIFT_VERSION = 5.0;
325 | TARGETED_DEVICE_FAMILY = "1,2";
326 | };
327 | name = Debug;
328 | };
329 | 146BEE74272930EB0004D971 /* Release */ = {
330 | isa = XCBuildConfiguration;
331 | buildSettings = {
332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
333 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
334 | CODE_SIGN_STYLE = Automatic;
335 | INFOPLIST_FILE = SwiftAlertView/Info.plist;
336 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
337 | LD_RUNPATH_SEARCH_PATHS = (
338 | "$(inherited)",
339 | "@executable_path/Frameworks",
340 | );
341 | PRODUCT_BUNDLE_IDENTIFIER = com.dinhquan.SwiftAlertView;
342 | PRODUCT_NAME = "$(TARGET_NAME)";
343 | SWIFT_VERSION = 5.0;
344 | TARGETED_DEVICE_FAMILY = "1,2";
345 | };
346 | name = Release;
347 | };
348 | /* End XCBuildConfiguration section */
349 |
350 | /* Begin XCConfigurationList section */
351 | 146BEE59272930E90004D971 /* Build configuration list for PBXProject "SwiftAlertView" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | 146BEE70272930EB0004D971 /* Debug */,
355 | 146BEE71272930EB0004D971 /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | 146BEE72272930EB0004D971 /* Build configuration list for PBXNativeTarget "SwiftAlertView" */ = {
361 | isa = XCConfigurationList;
362 | buildConfigurations = (
363 | 146BEE73272930EB0004D971 /* Debug */,
364 | 146BEE74272930EB0004D971 /* Release */,
365 | );
366 | defaultConfigurationIsVisible = 0;
367 | defaultConfigurationName = Release;
368 | };
369 | /* End XCConfigurationList section */
370 | };
371 | rootObject = 146BEE56272930E90004D971 /* Project object */;
372 | }
373 |
--------------------------------------------------------------------------------
/Source/SwiftAlertView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftAlertView.swift
3 | // SwiftAlertView
4 | //
5 | // Created by Dinh Quan on 8/26/15.
6 | // Copyright (c) 2015 Dinh Quan. All rights reserved.
7 | //
8 | // This code is distributed under the terms and conditions of the MIT license.
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 |
28 |
29 | import UIKit
30 |
31 | public class SwiftAlertView: UIView {
32 |
33 | public enum Style {
34 | case auto
35 | case light
36 | case dark
37 | }
38 |
39 | public enum TransitionType {
40 | case `default`
41 | case fade
42 | case vertical
43 | }
44 |
45 |
46 | // MARK: Public Properties
47 |
48 | public weak var delegate: SwiftAlertViewDelegate?
49 |
50 | public var style: Style = .auto { // default is based on system color
51 | didSet {
52 | updateAlertStyle()
53 | }
54 | }
55 |
56 | public var titleLabel: UILabel! // access titleLabel to customize the title font, color
57 | public var messageLabel: UILabel! // access messageLabel to customize the message font, color
58 |
59 | public var backgroundImage: UIImage?
60 | // public var backgroundColor: UIColor? // inherits from UIView
61 |
62 | public var cancelButtonIndex = 0 { // default is 0, set this property if you want to change the position of cancel button
63 | didSet {
64 | updateCancelButtonIndex()
65 | }
66 | }
67 | public var buttonTitleColor = UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1) // to change the title color of all buttons
68 | public var buttonHeight: CGFloat = 44.0
69 |
70 | public var separatorColor = UIColor(red: 196.0/255, green: 196.0/255, blue: 201.0/255, alpha: 1.0) // to change the separator color
71 | public var isHideSeparator = false
72 | public var cornerRadius: CGFloat = 12.0
73 |
74 | public var isDismissOnActionButtonClicked = true // default is true, if you want the alert view will not be dismissed when clicking on action buttons, set this property to false
75 | public var isHighlightOnButtonClicked = true
76 | public var isDimBackgroundWhenShowing = true
77 | public var isDismissOnOutsideTapped = false
78 | public var dimAlpha: CGFloat = 0.4
79 | public var dimBackgroundColor: UIColor? = .init(white: 0, alpha: 0.4)
80 |
81 | public var appearTime = 0.2
82 | public var disappearTime = 0.1
83 |
84 | public var transitionType: TransitionType = .default
85 |
86 | // customize the margin & spacing of title & message
87 | public var titleSideMargin: CGFloat = 20.0
88 | public var messageSideMargin: CGFloat = 20.0
89 | public var titleTopMargin: CGFloat = 20.0
90 | public var messageBottomMargin: CGFloat = 20.0
91 | public var titleToMessageSpacing: CGFloat = 20.0
92 |
93 | // customize text fields
94 | public var textFieldHeight: CGFloat = 34.0
95 | public var textFieldSideMargin: CGFloat = 15.0
96 | public var textFieldBottomMargin: CGFloat = 15.0
97 | public var textFieldSpacing: CGFloat = 10.0
98 | public var isFocusTextFieldWhenShowing = true
99 | public var isEnabledValidationLabel = false
100 | public var validationLabel: UILabel! // access to validation label to customize font, color
101 | public var validationLabelTopMargin: CGFloat = 8.0
102 | public var validationLabelSideMargin: CGFloat = 15.0
103 |
104 |
105 | // MARK: Constants
106 |
107 | private let kSeparatorWidth: CGFloat = 0.5
108 | private let kDefaultWidth: CGFloat = 270.0
109 | private let kDefaultHeight: CGFloat = 144.0
110 | private let kDefaultTitleSizeMargin: CGFloat = 20.0
111 | private let kDefaultMessageSizeMargin: CGFloat = 20.0
112 | private let kDefaultButtonHeight: CGFloat = 44.0
113 | private let kDefaultCornerRadius: CGFloat = 12.0
114 | private let kDefaultTitleTopMargin: CGFloat = 20.0
115 | private let kDefaultTitleToMessageSpacing: CGFloat = 10.0
116 | private let kDefaultMessageBottomMargin: CGFloat = 20.0
117 | private let kDefaultDimAlpha: CGFloat = 0.2
118 | private let kDefaultAppearTime = 0.2
119 | private let kDefaultDisappearTime = 0.1
120 | private var kMoveUpWithKeyboardDistance: CGFloat = 150.0
121 |
122 | // MARK: Private Properties
123 |
124 | private var contentView: UIView?
125 | private var buttons: [UIButton] = []
126 | private var textFields: [UITextField] = []
127 | private var backgroundImageView: UIImageView?
128 | private var dimView: UIView?
129 | private var title: String?
130 | private var message: String?
131 | private var buttonTitles: [String] = []
132 | private var viewWidth: CGFloat = 0
133 | private var viewHeight: CGFloat = 0
134 | private var isMoveUpWithKeyboard = false
135 |
136 | private var onButtonClicked: ((_ buttonIndex: Int) -> Void)?
137 | private var onCancelClicked: (() -> Void)?
138 | private var onActionButtonClicked: ((_ buttonIndex: Int) -> (Void))?
139 | private var onTextChanged: ((_ text: String?, _ textFieldIndex: Int) -> Void)?
140 |
141 | // MARK: Initialization
142 |
143 | public init(title: String? = nil, message: String? = nil, buttonTitles: [String]) {
144 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
145 | setUp(title: title, message: message, buttonTitles: buttonTitles)
146 | }
147 |
148 | public init(title: String? = nil, message: String? = nil, buttonTitles: String...) {
149 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
150 | setUp(title: title, message: message, buttonTitles: buttonTitles)
151 | }
152 |
153 | public init(contentView: UIView, buttonTitles: [String]) {
154 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
155 | setUp(contentView: contentView, buttonTitles: buttonTitles)
156 | }
157 |
158 | public init(contentView: UIView, buttonTitles: String...) {
159 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
160 | setUp(contentView: contentView, buttonTitles: buttonTitles)
161 | }
162 |
163 | public init(nibName: String, buttonTitles: [String]) {
164 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
165 | guard let contentView = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)?.first as? UIView else {
166 | fatalError("Could not load nib file")
167 | }
168 | setUp(contentView: contentView, buttonTitles: buttonTitles)
169 | }
170 |
171 | public init(nibName: String,
172 | buttonTitles: String...) {
173 | super.init(frame: CGRect(x: 0, y: 0, width: kDefaultWidth, height: kDefaultHeight))
174 | guard let contentView = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)?.first as? UIView else {
175 | fatalError("Could not load nib file")
176 | }
177 | setUp(contentView: contentView, buttonTitles: buttonTitles)
178 | }
179 |
180 | required public init(coder aDecoder: NSCoder) {
181 | fatalError("init(coder:) has not been implemented")
182 | }
183 |
184 | // MARK: Public Methods
185 |
186 | // access the buttons to customize their font & color
187 | public func button(at index: Int) -> UIButton? {
188 | if index >= 0 && index < buttons.count {
189 | return buttons[index]
190 | }
191 |
192 | return nil
193 | }
194 |
195 | // access the text fields to customize their font & color
196 | public func textField(at index: Int) -> UITextField? {
197 | if index >= 0 && index < textFields.count {
198 | return textFields[index]
199 | }
200 |
201 | return nil
202 | }
203 |
204 | public func addTextField(configurationHandler: ((UITextField) -> Void)? = nil) {
205 | let textField = UITextField(frame: CGRect(x: textFieldSideMargin, y: 0, width: viewWidth - textFieldSideMargin * 2, height: textFieldHeight))
206 | textField.font = .systemFont(ofSize: 14)
207 | textField.borderStyle = .roundedRect
208 | textField.delegate = self
209 | textField.tag = textFields.count
210 | textField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
211 | configurationHandler?(textField)
212 | textFields.append(textField)
213 | addSubview(textField)
214 | }
215 |
216 | // show the alert view at center of screen
217 | public func show() {
218 | if let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {
219 | show(in: window)
220 | }
221 | }
222 |
223 | // show the alert view at center of a view
224 | public func show(in view: UIView) {
225 | layoutElementBeforeShowing()
226 |
227 | let isFocusTextField = isFocusTextFieldWhenShowing && !textFields.isEmpty
228 | var showY = (view.frame.size.height - viewHeight)/2
229 | if isFocusTextField {
230 | showY -= kMoveUpWithKeyboardDistance
231 | isMoveUpWithKeyboard = true
232 | }
233 |
234 | frame = CGRect(x: (view.frame.size.width - viewWidth)/2, y: showY, width: viewWidth, height: viewHeight)
235 |
236 | if isDimBackgroundWhenShowing {
237 | dimView = UIView(frame: view.bounds)
238 | if let color = dimBackgroundColor {
239 | dimView!.backgroundColor = color
240 | } else {
241 | dimView!.backgroundColor = UIColor(white: 0, alpha: CGFloat(dimAlpha))
242 | }
243 | view.addSubview(dimView!)
244 | let recognizer = UITapGestureRecognizer(target: self, action: #selector(outsideTapped(_:)))
245 | dimView!.addGestureRecognizer(recognizer)
246 | }
247 |
248 | if isFocusTextField {
249 | textFields[0].becomeFirstResponder()
250 | }
251 |
252 | delegate?.willPresentAlertView?(self)
253 |
254 | view.addSubview(self)
255 | view.bringSubviewToFront(self)
256 |
257 | switch transitionType {
258 | case .default:
259 | if isFocusTextField {
260 | alpha = 0
261 | transform = CGAffineTransform(translationX: 0, y: 60)
262 | .concatenating(CGAffineTransform(scaleX: 1.1, y: 1.1))
263 | UIView.animate(withDuration: appearTime, delay: 0, options: .curveEaseInOut) {
264 | self.transform = CGAffineTransform.identity
265 | self.alpha = 1
266 | } completion: { _ in
267 | self.delegate?.didPresentAlertView?(self)
268 | }
269 | } else {
270 | transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
271 | alpha = 0.6
272 |
273 | UIView.animate(withDuration: appearTime) {
274 | self.transform = CGAffineTransform.identity
275 | self.alpha = 1
276 | } completion: { _ in
277 | self.delegate?.didPresentAlertView?(self)
278 | }
279 | }
280 | case .fade:
281 | alpha = 0
282 |
283 | UIView.animate(withDuration: appearTime, delay: 0, options: .curveEaseInOut) {
284 | self.alpha = 1
285 | } completion: { _ in
286 | self.delegate?.didPresentAlertView?(self)
287 | }
288 | case .vertical:
289 | let tempFrame = frame
290 | frame = CGRect(x: frame.origin.x, y: superview!.frame.size.height + 10, width: frame.size.width, height: frame.size.height)
291 |
292 | UIView.animate(withDuration: appearTime, delay: 0, options: .curveEaseInOut) {
293 | self.frame = tempFrame
294 | } completion: { _ in
295 | self.delegate?.didPresentAlertView?(self)
296 | }
297 | }
298 | }
299 |
300 | // dismiss the alert view programmatically
301 | public func dismiss() {
302 | self.delegate?.willDismissAlertView?(self)
303 |
304 | for textField in textFields {
305 | textField.resignFirstResponder()
306 | }
307 |
308 | if dimView != nil {
309 | UIView.animate(withDuration: disappearTime) {
310 | self.dimView?.alpha = 0
311 | } completion: { _ in
312 | self.dimView?.removeFromSuperview()
313 | self.dimView = nil
314 | }
315 | }
316 |
317 | switch transitionType {
318 | case .default:
319 | transform = CGAffineTransform.identity
320 |
321 | UIView.animate(withDuration: disappearTime, delay: 0.02, options: .curveEaseOut) {
322 | self.alpha = 0
323 | } completion: { _ in
324 | self.removeFromSuperview()
325 | self.delegate?.didDismissAlertView?(self)
326 | }
327 | case .fade:
328 | self.alpha = 1
329 |
330 | UIView.animate(withDuration: disappearTime, delay: 0.02, options: .curveEaseOut) {
331 | self.alpha = 0
332 | } completion: { _ in
333 | self.removeFromSuperview()
334 | self.delegate?.didDismissAlertView?(self)
335 | }
336 | case .vertical:
337 | UIView.animate(withDuration: disappearTime, delay: 0.02, options: .curveEaseOut) {
338 | self.frame = CGRect(x: self.frame.origin.x, y: self.superview!.frame.size.height + 10, width: self.frame.size.width, height: self.frame.size.height)
339 | } completion: { _ in
340 | self.removeFromSuperview()
341 | self.delegate?.didDismissAlertView?(self)
342 | }
343 | }
344 | }
345 |
346 | // handle events
347 | @discardableResult
348 | public func onButtonClicked(_ handler: @escaping (_ alertView: SwiftAlertView, _ buttonIndex: Int) -> Void) -> SwiftAlertView {
349 | self.onButtonClicked = { index in
350 | handler(self, index)
351 | }
352 | return self
353 | }
354 |
355 | @discardableResult
356 | public func onActionButtonClicked(_ handler: @escaping (_ alertView: SwiftAlertView, _ buttonIndex: Int) -> Void) -> SwiftAlertView {
357 | self.onActionButtonClicked = { index in
358 | handler(self, index)
359 | }
360 | return self
361 | }
362 |
363 | @discardableResult
364 | public func onTextChanged(_ handler: @escaping (_ alertView: SwiftAlertView, _ text: String?, _ textFieldIndex: Int) -> Void) -> SwiftAlertView {
365 | self.onTextChanged = { text, index in
366 | handler(self, text, index)
367 | }
368 | return self
369 | }
370 | }
371 |
372 |
373 | // MARK: Private Functions
374 |
375 | extension SwiftAlertView {
376 |
377 | private func setUp(title: String? = nil,
378 | message: String? = nil,
379 | contentView: UIView? = nil,
380 | buttonTitles: [String]) {
381 | self.title = title
382 | self.message = message
383 | self.buttonTitles = buttonTitles
384 |
385 | if let contentView = contentView {
386 | self.contentView = contentView
387 | }
388 |
389 | setUpDefaultValue()
390 | setUpElements()
391 | setUpDefaultAppearance()
392 |
393 | if let contentView = contentView {
394 | viewWidth = contentView.frame.size.width
395 | }
396 |
397 | if title == nil || message == nil {
398 | titleToMessageSpacing = 0
399 | }
400 | }
401 |
402 | private func setUpDefaultValue() {
403 | clipsToBounds = true
404 | viewWidth = kDefaultWidth
405 | viewHeight = kDefaultHeight
406 | titleSideMargin = kDefaultTitleSizeMargin
407 | messageSideMargin = kDefaultMessageSizeMargin
408 | buttonHeight = kDefaultButtonHeight
409 | titleTopMargin = kDefaultTitleTopMargin
410 | titleToMessageSpacing = kDefaultTitleToMessageSpacing
411 | messageBottomMargin = kDefaultMessageBottomMargin
412 | dimAlpha = kDefaultDimAlpha
413 | isDimBackgroundWhenShowing = true
414 | isDismissOnActionButtonClicked = true
415 | isHighlightOnButtonClicked = true
416 | isDismissOnOutsideTapped = false
417 | isHideSeparator = false
418 | cornerRadius = kDefaultCornerRadius
419 | appearTime = kDefaultAppearTime
420 | disappearTime = kDefaultDisappearTime
421 | transitionType = .default
422 | buttonTitleColor = UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1)
423 | layer.cornerRadius = CGFloat(cornerRadius)
424 | }
425 |
426 | private func setUpElements() {
427 | titleLabel = UILabel(frame: .zero)
428 | messageLabel = UILabel(frame: .zero)
429 | validationLabel = UILabel(frame: .zero)
430 |
431 | if title != nil {
432 | titleLabel.text = title
433 | addSubview(titleLabel)
434 | }
435 | if message != nil {
436 | messageLabel.text = message
437 | addSubview(messageLabel)
438 | }
439 |
440 | if let contentView = contentView {
441 | contentView.frame = CGRect(x: 0, y: 0, width: contentView.frame.size.width, height: contentView.frame.size.height)
442 | addSubview(contentView)
443 | }
444 |
445 | for buttonTitle in buttonTitles {
446 | let button = _HighlightButton(type: .custom)
447 | button.setTitle(buttonTitle, for: .normal)
448 | buttons.append(button)
449 | addSubview(button)
450 | }
451 | }
452 |
453 | private func setUpDefaultAppearance() {
454 | self.backgroundColor = UIColor(red: 245.0/255, green: 245.0/255, blue: 245.0/255, alpha: 1)
455 |
456 | if title != nil {
457 | titleLabel.numberOfLines = 0
458 | titleLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
459 | titleLabel.textColor = UIColor.black
460 | titleLabel.font = UIFont.boldSystemFont(ofSize: 17)
461 | titleLabel.textAlignment = NSTextAlignment.center
462 | titleLabel.backgroundColor = .clear
463 | }
464 |
465 | if message != nil {
466 | messageLabel.numberOfLines = 0
467 | messageLabel.lineBreakMode = .byWordWrapping
468 | messageLabel.textColor = .black
469 | messageLabel.font = UIFont.systemFont(ofSize: 13)
470 | if title == nil {
471 | messageLabel.font = UIFont.boldSystemFont(ofSize: 17)
472 | }
473 | messageLabel.textAlignment = .center
474 | messageLabel.backgroundColor = .clear
475 | }
476 |
477 | validationLabel.text = " "
478 | validationLabel.numberOfLines = 0
479 | validationLabel.lineBreakMode = .byWordWrapping
480 | validationLabel.textColor = .red
481 | validationLabel.font = .systemFont(ofSize: 13)
482 | validationLabel.textAlignment = .left
483 |
484 | var i = 0
485 | for button in buttons {
486 | button.tag = i
487 | i += 1
488 | button.backgroundColor = .clear
489 | button.setTitleColor(buttonTitleColor, for: .normal)
490 | if button.tag == cancelButtonIndex {
491 | button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
492 | } else {
493 | button.titleLabel?.font = UIFont.systemFont(ofSize: 17)
494 | }
495 | }
496 | }
497 |
498 | private func layoutElementBeforeShowing() {
499 | if let backgroundImage = backgroundImage {
500 | backgroundImageView = UIImageView(frame: self.bounds)
501 | backgroundImageView?.image = backgroundImage
502 | addSubview(backgroundImageView!)
503 | sendSubviewToBack(backgroundImageView!)
504 | }
505 |
506 | var i = 0
507 | for button in buttons {
508 | button.tag = i
509 | i += 1
510 |
511 | if !buttonTitleColor.isEqual(UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1)) {
512 | button.setTitleColor(buttonTitleColor, for: .normal)
513 | }
514 |
515 | button.addTarget(self, action: #selector(buttonClicked(_:)), for: .touchUpInside)
516 | }
517 |
518 | if title != nil {
519 | titleLabel.frame = CGRect(x: 0, y: 0, width: viewWidth - titleSideMargin*2, height: 0)
520 | labelHeightToFit(titleLabel)
521 | }
522 | if message != nil {
523 | messageLabel.frame = CGRect(x: 0, y: 0, width: viewWidth - messageSideMargin*2, height: 0)
524 | labelHeightToFit(messageLabel)
525 | }
526 | if title != nil {
527 | titleLabel.center = CGPoint(x: viewWidth/2, y: titleTopMargin + titleLabel.frame.size.height/2)
528 | }
529 | if message != nil {
530 | messageLabel.center = CGPoint(x: viewWidth/2, y: titleTopMargin + titleLabel.frame.size.height + titleToMessageSpacing + messageLabel.frame.size.height/2)
531 | }
532 |
533 | let titleMessageHeight = titleTopMargin + titleLabel.frame.size.height + titleToMessageSpacing + messageLabel.frame.size.height + messageBottomMargin
534 | for i in 0.. Void)? = nil) -> SwiftAlertView {
672 | let alertView = SwiftAlertView(title: title, message: message, buttonTitles: buttonTitles)
673 | configure?(alertView)
674 | alertView.show()
675 | return alertView
676 | }
677 |
678 | @discardableResult
679 | public static func show(title: String? = nil,
680 | message: String? = nil,
681 | buttonTitles: String...,
682 | configure: ((_ alertView: SwiftAlertView) -> Void)? = nil) -> SwiftAlertView {
683 | return show(title: title, message: message, buttonTitles: buttonTitles, configure: configure)
684 | }
685 |
686 | @discardableResult
687 | public static func show(contentView: UIView,
688 | buttonTitles: [String],
689 | configure: ((_ alertView: SwiftAlertView) -> Void)? = nil) -> SwiftAlertView {
690 | let alertView = SwiftAlertView(contentView: contentView, buttonTitles: buttonTitles)
691 | configure?(alertView)
692 | alertView.show()
693 | return alertView
694 | }
695 |
696 | @discardableResult
697 | public static func show(contentView: UIView,
698 | buttonTitles: String...,
699 | configure: ((_ alertView: SwiftAlertView) -> Void)? = nil) -> SwiftAlertView {
700 | return show(contentView: contentView, buttonTitles: buttonTitles, configure: configure)
701 | }
702 |
703 | @discardableResult
704 | public static func show(nibName: String,
705 | buttonTitles: [String],
706 | configure: ((_ alertView: SwiftAlertView) -> Void)? = nil) -> SwiftAlertView {
707 | let alertView = SwiftAlertView(nibName: nibName, buttonTitles: buttonTitles)
708 | configure?(alertView)
709 | alertView.show()
710 | return alertView
711 | }
712 |
713 | @discardableResult
714 | public static func show(nibName: String,
715 | buttonTitles: String...,
716 | configure: ((_ alertView: SwiftAlertView) -> Void)? = nil) -> SwiftAlertView {
717 | return show(nibName: nibName, buttonTitles: buttonTitles, configure: configure)
718 | }
719 | }
720 |
721 |
722 | @objc public protocol SwiftAlertViewDelegate : NSObjectProtocol {
723 |
724 | @objc optional func alertView(_ alertView: SwiftAlertView, clickedButtonAtIndex buttonIndex: Int)
725 |
726 | @objc optional func willPresentAlertView(_ alertView: SwiftAlertView) // before animation and showing view
727 | @objc optional func didPresentAlertView(_ alertView: SwiftAlertView) // after animation
728 |
729 | @objc optional func willDismissAlertView(_ alertView: SwiftAlertView) // before animation and showing view
730 | @objc optional func didDismissAlertView(_ alertView: SwiftAlertView) // after animation
731 | }
732 |
733 | extension SwiftAlertView: UITextFieldDelegate {
734 | public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
735 | textField.resignFirstResponder()
736 | return true
737 | }
738 |
739 | public func textFieldDidBeginEditing(_ textField: UITextField) {
740 | if isMoveUpWithKeyboard { return }
741 | self.isMoveUpWithKeyboard = true
742 | UIView.animate(withDuration: 0.2) {
743 | self.frame = self.frame.offsetBy(dx: 0, dy: -self.kMoveUpWithKeyboardDistance)
744 | }
745 | }
746 |
747 | public func textFieldDidEndEditing(_ textField: UITextField) {
748 | if !isMoveUpWithKeyboard { return }
749 | self.isMoveUpWithKeyboard = false
750 | UIView.animate(withDuration: 0.2) {
751 | self.frame = self.frame.offsetBy(dx: 0, dy: self.kMoveUpWithKeyboardDistance)
752 | }
753 | }
754 | }
755 |
756 | final class _HighlightButton: UIButton {
757 | var highlightColor = UIColor(white: 0.2, alpha: 0.1)
758 | private var bgColor: UIColor = .clear
759 |
760 | override func awakeFromNib() {
761 | super.awakeFromNib()
762 | bgColor = backgroundColor ?? .clear
763 | }
764 |
765 | override public var isHighlighted: Bool {
766 | didSet {
767 | let highlightedColor = bgColor == .clear ? highlightColor : bgColor.withAlphaComponent(0.66)
768 | backgroundColor = isHighlighted ? highlightedColor : bgColor
769 | }
770 | }
771 | }
772 |
773 | extension SwiftAlertView {
774 | func color(light: UIColor, dark: UIColor) -> UIColor {
775 | if #available(iOS 13, *), style == .auto {
776 | return UIColor { $0.userInterfaceStyle == .dark ? dark : light }
777 | } else if style == .dark {
778 | return dark
779 | } else {
780 | return light
781 | }
782 | }
783 | }
784 |
785 |
786 |
--------------------------------------------------------------------------------