├── .gitignore ├── LICENSE ├── Package.swift ├── README.md ├── Source └── SwiftAlertView.swift ├── SwiftAlertView.podspec ├── SwiftAlertView.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── SwiftAlertView ├── AppDelegate.swift ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json └── alert-box.imageset │ ├── Contents.json │ └── alert-box@2x.png ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── CustomView.xib ├── Images └── demo.png ├── Info.plist ├── Marker Felt.ttf └── ViewController.swift /.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/ -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | ![](https://raw.githubusercontent.com/dinhquan/SwiftAlertView/master/SwiftAlertView/Images/demo.png) 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /SwiftAlertView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftAlertView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /SwiftAlertView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /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/Assets.xcassets/alert-box.imageset/alert-box@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinhquan/SwiftAlertView/501f3adf5e9663763b7eb8726740a74116cd9dfd/SwiftAlertView/Assets.xcassets/alert-box.imageset/alert-box@2x.png -------------------------------------------------------------------------------- /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/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/Images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinhquan/SwiftAlertView/501f3adf5e9663763b7eb8726740a74116cd9dfd/SwiftAlertView/Images/demo.png -------------------------------------------------------------------------------- /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/Marker Felt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinhquan/SwiftAlertView/501f3adf5e9663763b7eb8726740a74116cd9dfd/SwiftAlertView/Marker Felt.ttf -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------