├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── SPAlertController.podspec ├── SPAlertController ├── SPAlertAction.swift ├── SPAlertAnimation.swift ├── SPAlertController+Public.swift ├── SPAlertController+transitionDelegate.swift ├── SPAlertController.swift ├── SPAlertControllerActionView.swift ├── SPAlertControllerDelegate.swift ├── SPAlertPresentationController.swift ├── SPConstant.swift ├── SPInteractiveTransition.swift ├── SPInterfaceActionItemSeparatorView.swift ├── SPInterfaceActionSequenceView.swift ├── SPInterfaceHeaderScrollView.swift └── SPOverlayView.swift └── Swift_SPAlertController ├── Carthage └── Build │ ├── .SPAlertController.version │ └── iOS │ ├── SPAlertController.framework.dSYM │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ └── DWARF │ │ └── SPAlertController │ └── SPAlertController.framework │ ├── Headers │ ├── SPAlertController-Swift.h │ └── SPAlertController.h │ ├── Info.plist │ ├── Modules │ ├── SPAlertController.swiftmodule │ │ ├── arm.swiftdoc │ │ ├── arm.swiftmodule │ │ ├── arm64-apple-ios.swiftdoc │ │ ├── arm64-apple-ios.swiftmodule │ │ ├── arm64.swiftdoc │ │ ├── arm64.swiftmodule │ │ ├── armv7-apple-ios.swiftdoc │ │ ├── armv7-apple-ios.swiftmodule │ │ ├── armv7.swiftdoc │ │ ├── armv7.swiftmodule │ │ ├── i386-apple-ios-simulator.swiftdoc │ │ ├── i386-apple-ios-simulator.swiftmodule │ │ ├── i386.swiftdoc │ │ ├── i386.swiftmodule │ │ ├── x86_64-apple-ios-simulator.swiftdoc │ │ ├── x86_64-apple-ios-simulator.swiftmodule │ │ ├── x86_64.swiftdoc │ │ └── x86_64.swiftmodule │ └── module.modulemap │ └── SPAlertController ├── SPAlertController ├── Info.plist ├── SPAlertAction.swift ├── SPAlertAnimation.swift ├── SPAlertController+Public.swift ├── SPAlertController+transitionDelegate.swift ├── SPAlertController.h ├── SPAlertController.swift ├── SPAlertControllerActionView.swift ├── SPAlertControllerDelegate.swift ├── SPAlertPresentationController.swift ├── SPConstant.swift ├── SPInteractiveTransition.swift ├── SPInterfaceActionItemSeparatorView.swift ├── SPInterfaceActionSequenceView.swift ├── SPInterfaceHeaderScrollView.swift └── SPOverlayView.swift ├── Swift_SPAlertController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── ETrans.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── SPAlertController.xcscheme └── xcuserdata │ └── ETrans.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist └── Swift_SPAlertController ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon-1.appiconset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json ├── publish_0.imageset │ ├── Contents.json │ ├── publish_0@2x.png │ └── publish_0@3x.png ├── publish_1.imageset │ ├── Contents.json │ ├── publish_1@2x.png │ └── publish_1@3x.png ├── publish_10.imageset │ ├── Contents.json │ ├── publish_10@2x.png │ └── publish_10@3x.png ├── publish_11.imageset │ ├── Contents.json │ ├── publish_11@2x.png │ └── publish_11@3x.png ├── publish_2.imageset │ ├── Contents.json │ ├── publish_2@2x.png │ └── publish_2@3x.png ├── publish_3.imageset │ ├── Contents.json │ ├── publish_3@2x.png │ └── publish_3@3x.png ├── publish_4.imageset │ ├── Contents.json │ ├── publish_4@2x.png │ └── publish_4@3x.png ├── publish_5.imageset │ ├── Contents.json │ ├── publish_5@2x.png │ └── publish_5@3x.png ├── publish_6.imageset │ ├── Contents.json │ ├── publish_6@2x.png │ └── publish_6@3x.png ├── publish_7.imageset │ ├── Contents.json │ ├── publish_7@2x.png │ └── publish_7@3x.png ├── publish_8.imageset │ ├── Contents.json │ ├── publish_8@2x.png │ └── publish_8@3x.png ├── publish_9.imageset │ ├── Contents.json │ ├── publish_9@2x.png │ └── publish_9@3x.png ├── success.imageset │ ├── Contents.json │ └── 勾.png ├── telephone.imageset │ ├── Contents.json │ ├── telephone@2x.png │ └── telephone@3x.png ├── video.imageset │ ├── Contents.json │ ├── video@2x.png │ └── video@3x.png ├── wechatLogo.imageset │ ├── Contents.json │ ├── wechatLogo@2x.png │ └── wechatLogo@3x.png ├── zhiwen.imageset │ ├── Contents.json │ ├── zhiwen@2x.png │ └── zhiwen@3x.png ├── 减号.imageset │ ├── Contents.json │ ├── 减号-1.png │ ├── 减号-2.png │ └── 减号.png ├── 加号.imageset │ ├── Contents.json │ ├── 加号-1.png │ ├── 加号-3.png │ └── 加号-4.png ├── 取消.imageset │ ├── Contents.json │ ├── 叉-1.png │ ├── 叉-2.png │ └── 叉-3.png └── 苹果logo.imageset │ ├── Contents.json │ └── 苹果logo.png ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── CustomOverlayView.swift ├── CustomViews ├── CustomView1 │ ├── SendAlertView.swift │ └── SendAlertView.xib ├── CustomView2 │ ├── MyView.swift │ ├── MyView.xib │ ├── PassWordView.h │ ├── PassWordView.m │ └── Swift_SPAlertController-Bridging-Header.h ├── CustomView3 │ ├── ShoppingCartCell.swift │ ├── ShoppingCartCell.xib │ └── ShoppingCartView.swift ├── CustomView4 │ └── CommodityListView.swift ├── CustomView5 │ ├── PickerView.swift │ └── PickerView.xib ├── CustomView6 │ ├── HCSStarRatingView.h │ ├── HCSStarRatingView.m │ └── ScoreView.swift └── CustomView7 │ └── MyCenterView.swift ├── DLog.swift ├── DynamicBlurView ├── BlurLayer.swift ├── CGContext+CGImage.swift ├── CGImage+Accelerate.swift ├── CaptureQuality.swift ├── DynamicBlurView.h ├── DynamicBlurView.swift ├── TrackingMode.swift └── UIImage+Blur.swift ├── Images ├── image0.jpg ├── image1.jpg ├── image2.jpg ├── image3.jpg ├── image4.jpg ├── image5.jpg ├── image6.jpg ├── image7.jpg ├── image8.jpg ├── image9.jpg ├── send0.jpeg ├── send1.jpeg ├── 背景1.jpg └── 背景2.jpg ├── Info.plist ├── Nibloadable.swift ├── ViewController+Alert.swift ├── ViewController+Attributed.swift ├── ViewController+Custom.swift ├── ViewController+Sheet.swift ├── ViewController+Special.swift ├── ViewController+background.swift └── ViewController.swift /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Carthage 26 | 27 | # We recommend against adding the Pods directory to your .gitignore. However 28 | # you should judge for yourself, the pros and cons are mentioned at: 29 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 30 | # 31 | # Note: if you ignore the Pods directory, make sure to uncomment 32 | # `pod install` in .travis.yml 33 | # 34 | # Pods/ 35 | .idea 36 | /Tests/FailureDiffs 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2018-2019 leshengping (lesp163@163.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /SPAlertController.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint SPAlertController.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "SPAlertController" 19 | s.version = "1.0.0" 20 | s.summary = "万能提醒对话框.自定义弹窗" 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | 28 | s.homepage = "https://github.com/dongxiexidu/SPAlertController" 29 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 30 | 31 | 32 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 33 | # 34 | # Licensing your code is important. See http://choosealicense.com for more info. 35 | # CocoaPods will detect a license file if there is a named LICENSE* 36 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 37 | # 38 | 39 | s.license = "MIT" 40 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 41 | 42 | 43 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 44 | # 45 | # Specify the authors of the library, with email addresses. Email addresses 46 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 47 | # accepts just a name if you'd rather not provide an email address. 48 | # 49 | # Specify a social_media_url where others can refer to, for example a twitter 50 | # profile URL. 51 | # 52 | 53 | s.author = { "dongxiexidu" => "863223764@qq.com" } 54 | # Or just: s.author = "dongxiexidu" 55 | # s.authors = { "dongxiexidu" => "" } 56 | # s.social_media_url = "https://www.jianshu.com/u/6f76b136c31e" 57 | 58 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 59 | # 60 | # If this Pod runs only on iOS or OS X, then specify the platform and 61 | # the deployment target. You can optionally include the target after the platform. 62 | # 63 | 64 | s.platform = :ios 65 | s.platform = :ios, "9.0" 66 | s.swift_versions = '5.0' 67 | 68 | # When using multiple platforms 69 | s.ios.deployment_target = "9.0" 70 | # s.osx.deployment_target = "10.7" 71 | # s.watchos.deployment_target = "2.0" 72 | # s.tvos.deployment_target = "9.0" 73 | 74 | 75 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 76 | # 77 | # Specify the location from where the source should be retrieved. 78 | # Supports git, hg, bzr, svn and HTTP. 79 | # 80 | 81 | s.source = { :git => "https://github.com/dongxiexidu/SPAlertController.git", :tag => s.version } 82 | 83 | 84 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 85 | # 86 | # CocoaPods is smart about how it includes source code. For source files 87 | # giving a folder will include any swift, h, m, mm, c & cpp files. 88 | # For header files it will include any header in the folder. 89 | # Not including the public_header_files will make all headers public. 90 | # 91 | 92 | s.source_files = "SPAlertController" 93 | s.exclude_files = "Classes/Exclude" 94 | 95 | end 96 | -------------------------------------------------------------------------------- /SPAlertController/SPAlertAction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertAction.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class SPAlertAction: NSObject { 12 | 13 | /// Whether button should dismiss popup when tapped 14 | open var dismissOnTap = true 15 | 16 | public var title: String? { 17 | didSet{ 18 | self.propertyChangedClosure?(self,true) 19 | } 20 | } 21 | /// action的富文本标题 22 | public var attributedTitle: NSAttributedString? { 23 | didSet { 24 | self.propertyChangedClosure?(self,true) 25 | } 26 | } 27 | /// action的图标,位于title的左边 28 | public var image: UIImage? { 29 | didSet { 30 | self.propertyChangedClosure?(self,true) 31 | } 32 | } 33 | /// title跟image之间的间距 34 | public var imageTitleSpacing: CGFloat = 0 { 35 | didSet{ 36 | self.propertyChangedClosure?(self,true) 37 | } 38 | } 39 | /// 样式 40 | public var style: SPAlertActionStyle = .default 41 | /// 是否能点击,默认为YES 42 | public var isEnabled: Bool = true { 43 | didSet{ // enabled改变不需要更新布局 44 | self.propertyChangedClosure?(self,false) 45 | } 46 | } 47 | /// action的标题颜色,这个颜色只是普通文本的颜色,富文本颜色需要用NSForegroundColorAttributeName 48 | public var titleColor: UIColor = .black { 49 | didSet{// 颜色改变不需要更新布局 50 | self.propertyChangedClosure?(self,false) 51 | } 52 | } 53 | /// action的标题字体,如果文字太长显示不全,会自动改变字体自适应按钮宽度,最多压缩文字为原来的0.5倍封顶 54 | public var titleFont: UIFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) { 55 | didSet{// 字体改变需要更新布局 56 | self.propertyChangedClosure?(self,true) 57 | } 58 | } 59 | /// action的标题的内边距,如果在不改变字体的情况下想增大action的高度,可以设置该属性的top和bottom值,默认UIEdgeInsetsMake(0, 15, 0, 15) 60 | public var titleEdgeInsets: UIEdgeInsets = .init(top: 0, left: 15, bottom: 0, right: 15) 61 | 62 | public var handler: ((SPAlertAction) ->Void)? 63 | //当在addAction之后设置action属性时,会回调这个block,设置相应控件的字体、颜色等 64 | /// 如果没有这个block,那使用时,只有在addAction之前设置action的属性才有效 65 | internal var propertyChangedClosure: ((SPAlertAction, Bool) ->Void)? 66 | 67 | public class func action(withTitle title: String?, 68 | style: SPAlertActionStyle, 69 | handler: @escaping (SPAlertAction)->Void) -> SPAlertAction { 70 | let action = SPAlertAction.init(title: title, style: style, handler: handler) 71 | return action 72 | } 73 | 74 | convenience init(title: String?, style: SPAlertActionStyle, handler: @escaping ((SPAlertAction) ->Void)) { 75 | 76 | self.init() 77 | self.title = title 78 | self.style = style 79 | self.handler = handler 80 | 81 | if style == .destructive { 82 | self.titleColor = .red 83 | self.titleFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 84 | } else if style == .cancel { 85 | self.titleColor = .black 86 | self.titleFont = UIFont.boldSystemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 87 | } else { 88 | self.titleFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 89 | self.titleColor = .black 90 | } 91 | } 92 | 93 | } 94 | 95 | extension SPAlertAction: NSCopying{ 96 | // 由于要对装载action的数组进行拷贝,所以SPAlertAction也需要支持拷贝 97 | public func copy(with zone: NSZone? = nil) -> Any { 98 | let action = SPAlertAction() 99 | action.title = self.title 100 | action.attributedTitle = self.attributedTitle 101 | action.image = self.image 102 | action.imageTitleSpacing = self.imageTitleSpacing 103 | action.style = self.style 104 | action.isEnabled = self.isEnabled 105 | action.titleColor = self.titleColor 106 | action.titleFont = self.titleFont 107 | action.titleEdgeInsets = self.titleEdgeInsets 108 | action.handler = self.handler 109 | action.propertyChangedClosure = self.propertyChangedClosure 110 | 111 | return action 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /SPAlertController/SPAlertController+transitionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertController+transitionDelegate.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/7. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //FIXME: 文件名修改为`SPAlertController+transitioningDelegate` 12 | 13 | //SPAlertController自定义转场动画,需要遵守`UIViewControllerTransitioningDelegate`,实现必要的协议 14 | //MARK: UIViewControllerTransitioningDelegate 15 | extension SPAlertController: UIViewControllerTransitioningDelegate { 16 | 17 | // 2.如何弹出的动画 18 | public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 19 | 20 | return SPAlertAnimation.animationIsPresenting(isPresenting: true, interactor: self.interactor) 21 | } 22 | // 3.如何dismissed的动画 23 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 24 | 25 | self.view.endEditing(true) 26 | return SPAlertAnimation.animationIsPresenting(isPresenting: false, interactor: self.interactor) 27 | } 28 | // 1.返回一个自定义的UIPresentationController 29 | // 控制控制器跳转的类,是iOS8新增的一个API,用来控制controller之间的跳转特效, 30 | public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 31 | 32 | return SPAlertPresentationController.init(presentedViewController: presented, presenting: presenting) 33 | } 34 | 35 | public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 36 | return interactor.hasStarted ? interactor : nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SPAlertController/SPAlertControllerActionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertControllerActionView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPAlertControllerActionView: UIView { 12 | 13 | 14 | public var afterSpacing: CGFloat = SP_LINE_WIDTH 15 | 16 | private var actionButtonConstraints = [NSLayoutConstraint]() 17 | private var methodAction: Selector! 18 | private var target: AnyObject! 19 | 20 | 21 | func addTarget(target: AnyObject, action: Selector) { 22 | self.target = target 23 | self.methodAction = action 24 | } 25 | //手指按下然后在按钮有效事件范围内抬起 26 | @objc func touchUpInside() { 27 | _ = target.perform(self.methodAction, with: self) 28 | } 29 | //手指按下或者手指按下后往外拽再往内拽 30 | @objc func touchDown(button: UIButton) { 31 | guard let alert = self.findAlertController() else{ return } 32 | 33 | if alert.needDialogBlur { 34 | // 需要毛玻璃时,只有白色带透明,毛玻璃效果才更加清澈 35 | button.backgroundColor = SP_SELECTED_COLOR 36 | } else { 37 | // 该颜色比'取消action'上的分割线的颜色浅一些 38 | button.backgroundColor = UIColor.gray.withAlphaComponent(0.1) 39 | } 40 | } 41 | // 手指被迫停止、手指按下后往外拽或者取消,取消的可能性:比如点击的那一刻突然来电话 42 | @objc func touchDragExit(button: UIButton) { 43 | button.backgroundColor = SP_NORMAL_COLOR 44 | } 45 | 46 | func findAlertController() -> SPAlertController? { 47 | var next = self.next 48 | while next != nil { 49 | if next is SPAlertController { 50 | return next as? SPAlertController 51 | } else { 52 | next = next?.next 53 | } 54 | } 55 | return nil 56 | } 57 | 58 | // 安全区域发生了改变,在这个方法里自动适配iPhoneX 59 | override func safeAreaInsetsDidChange() { 60 | if #available(iOS 11.0, *) { 61 | super.safeAreaInsetsDidChange() 62 | self.actionButton.contentEdgeInsets = self.edgeInsetsAddEdgeInsets(i1: self.safeAreaInsets, i2: action.titleEdgeInsets) 63 | } else { 64 | // Fallback on earlier versions 65 | } 66 | 67 | self.setNeedsUpdateConstraints() 68 | } 69 | 70 | override func updateConstraints() { 71 | super.updateConstraints() 72 | 73 | if self.actionButtonConstraints.count > 0 { 74 | NSLayoutConstraint.deactivate(self.actionButtonConstraints) 75 | self.actionButtonConstraints.removeAll() 76 | } 77 | 78 | actionButtonConstraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[actionButton]-0-|", options: [], metrics: nil, views: ["actionButton": actionButton])) 79 | actionButtonConstraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[actionButton]-0-|", options: [], metrics: nil, views: ["actionButton": actionButton])) 80 | // 按钮必须确认高度,因为其父视图及父视图的父视图乃至根视图都没有设置高度,而且必须用NSLayoutRelationEqual,如果用NSLayoutRelationGreaterThanOrEqual,虽然也能撑起父视图,但是当某个按钮的高度有所变化以后,stackView会将其余按钮按的高度同比增减 81 | 82 | // titleLabel的内容自适应的高度 55 83 | let labelH: CGFloat = actionButton.titleLabel?.intrinsicContentSize.height ?? 0.0 84 | // 按钮的上下内边距之和 0 85 | let topBottom_insetsSum: CGFloat = actionButton.contentEdgeInsets.top+actionButton.contentEdgeInsets.bottom 86 | // 文字的上下间距之和,等于SP_ACTION_HEIGHT-默认字体大小,这是为了保证文字上下有一个固定间距值,不至于使文字靠按钮太紧,,由于按钮内容默认垂直居中,所以最终的顶部或底部间距为topBottom_marginSum/2.0,这个间距,几乎等于18号字体时,最小高度为49时的上下间距 33.5 87 | let topBottom_marginSum: CGFloat = SP_ACTION_HEIGHT-UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE).lineHeight 88 | 89 | // 按钮高度 90 | let buttonH = labelH+topBottom_insetsSum+topBottom_marginSum 91 | 92 | var relation = NSLayoutConstraint.Relation.equal 93 | if let stackView = self.superview as? UIStackView, stackView.axis == .horizontal { 94 | relation = .greaterThanOrEqual 95 | } 96 | // 如果字体保持默认18号,只有一行文字时最终结果约等于SP_ACTION_HEIGHT 97 | let buttonHonstraint = NSLayoutConstraint.init(item: actionButton, attribute: .height, relatedBy: relation, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: buttonH) 98 | buttonHonstraint.priority = UILayoutPriority(rawValue: 999) 99 | actionButtonConstraints.append(buttonHonstraint) 100 | 101 | // 给一个最小高度,当按钮字体很小时,如果还按照上面的高度计算,高度会比较小 102 | let minHConstraint = NSLayoutConstraint.init(item: actionButton, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: SP_ACTION_HEIGHT+topBottom_insetsSum) 103 | minHConstraint.priority = UILayoutPriority.required 104 | self.addConstraints(actionButtonConstraints) 105 | } 106 | 107 | private func edgeInsetsAddEdgeInsets(i1: UIEdgeInsets, i2: UIEdgeInsets) -> UIEdgeInsets { 108 | var bottom: CGFloat = i1.bottom 109 | if bottom > 21 {// 34的高度太大,这里转为21 110 | bottom = 21 111 | } 112 | return .init(top: i1.top+i2.top, left: i1.left+i2.left, bottom: bottom+i2.bottom, right: i1.right+i2.right) 113 | } 114 | 115 | lazy var actionButton: UIButton = { 116 | let btn = UIButton.init(type: .custom) 117 | btn.backgroundColor = SP_NORMAL_COLOR 118 | btn.translatesAutoresizingMaskIntoConstraints = false 119 | btn.titleLabel?.textAlignment = .center 120 | btn.titleLabel?.adjustsFontSizeToFitWidth = true 121 | btn.titleLabel?.baselineAdjustment = .alignCenters 122 | btn.titleLabel?.minimumScaleFactor = 0.5 123 | btn.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside) 124 | btn.addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragInside]) 125 | btn.addTarget(self, action: #selector(touchDragExit), for: [.touchDragExit, .touchUpOutside, .touchCancel]) 126 | self.addSubview(btn) 127 | return btn 128 | }() 129 | 130 | public var action: SPAlertAction! { 131 | didSet { 132 | self.actionButton.titleLabel?.font = action.titleFont 133 | if action.isEnabled == true { 134 | self.actionButton.setTitleColor(action.titleColor, for: .normal) 135 | } else { 136 | self.actionButton.setTitleColor(.lightGray, for: .normal) 137 | } 138 | 139 | // 注意不能赋值给按钮的titleEdgeInsets,当只有文字时,按钮的titleEdgeInsets设置top和bottom值无效 140 | self.actionButton.contentEdgeInsets = action.titleEdgeInsets 141 | self.actionButton.isEnabled = action.isEnabled 142 | if action.attributedTitle != nil { 143 | // 这里之所以要设置按钮颜色为黑色,是因为如果外界在addAction:之后设置按钮的富文本,那么富文本的颜色在没有采用NSForegroundColorAttributeName的情况下会自动读取按钮上普通文本的颜色,在addAction:之前设置会保持默认色(黑色),为了在addAction:前后设置富文本保持统一,这里先将按钮置为黑色,富文本就会是黑色 144 | self.actionButton.setTitleColor(.black, for: .normal) 145 | if action.attributedTitle!.string.contains("\n") || action.attributedTitle!.string.contains("\r") { 146 | self.actionButton.titleLabel?.lineBreakMode = .byWordWrapping 147 | } 148 | self.actionButton.setAttributedTitle(action.attributedTitle!, for: .normal) 149 | // 设置完富文本之后,还原按钮普通文本的颜色,其实这行代码加不加都不影响,只是为了让按钮普通文本的颜色保持跟action.titleColor一致 150 | self.actionButton.setTitleColor(action.titleColor, for: .normal) 151 | } else { 152 | 153 | if let title = action.title { 154 | if title.contains("\n") || title.contains("\r") { 155 | self.actionButton.titleLabel?.lineBreakMode = .byWordWrapping 156 | } 157 | self.actionButton.setTitle(title, for: .normal) 158 | } 159 | 160 | } 161 | self.actionButton.setImage(action.image, for: .normal) 162 | self.actionButton.titleEdgeInsets = .init(top: 0, left: action.imageTitleSpacing, bottom: 0, right: -action.imageTitleSpacing) 163 | self.actionButton.imageEdgeInsets = .init(top: 0, left: -action.imageTitleSpacing, bottom: 0, right: action.imageTitleSpacing) 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /SPAlertController/SPAlertControllerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertControllerDelegate.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //: NSObject 12 | protocol SPAlertControllerDelegate{ 13 | 14 | } 15 | 16 | extension SPAlertControllerDelegate { 17 | 18 | /// 将要present 19 | func willPresentAlertController(alertController: SPAlertController) { 20 | 21 | } 22 | /// 已经present 23 | func didPresentAlertController(alertController: SPAlertController) { 24 | 25 | } 26 | /// 将要dismiss 27 | func willDismissAlertController(alertController: SPAlertController) { 28 | 29 | } 30 | /// 已经dismiss 31 | func didDismissAlertController(alertController: SPAlertController) { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SPAlertController/SPAlertPresentationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertPresentationController.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // UIPresentationController控制控制器跳转的类,是iOS8新增的一个API,用来控制 controller之间的跳转特效, 12 | // 例如:显示一个模态窗口,大小和位置是自定义的,遮罩在原来的页面 13 | class SPAlertPresentationController: UIPresentationController { 14 | 15 | 16 | override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { 17 | super.init(presentedViewController: presentedViewController, presenting: presentingViewController) 18 | } 19 | 20 | override func containerViewWillLayoutSubviews() { 21 | super.containerViewWillLayoutSubviews() 22 | if let containerV = self.containerView { 23 | self.overlayView.frame = containerV.bounds 24 | } 25 | } 26 | 27 | override func containerViewDidLayoutSubviews() { 28 | super.containerViewDidLayoutSubviews() 29 | } 30 | 31 | // MARK: - 1.将要开始弹出 32 | override func presentationTransitionWillBegin() { 33 | super.presentationTransitionWillBegin() 34 | 35 | let alertController = self.presentedViewController as! SPAlertController 36 | self.overlayView.setAppearanceStyle(appearanceStyle: alertController.backgroundViewAppearanceStyle, alpha: alertController.backgroundViewAlpha) 37 | // 遮罩的alpha值从0~1变化,UIViewControllerTransitionCoordinator协是一个过渡协调器,当执行模态过渡或push过渡时,可以对视图中的其他部分做动画 38 | let coordinator = self.presentedViewController.transitionCoordinator 39 | if let coordinatorT = coordinator { 40 | coordinatorT.animate(alongsideTransition: { (context) in 41 | self.overlayView.alpha = 1.0 42 | }, completion: nil) 43 | } else { 44 | self.overlayView.alpha = 1.0 45 | } 46 | alertController.delegate?.willPresentAlertController(alertController: alertController) 47 | 48 | } 49 | // MARK: - 2.已经弹出 50 | override func presentationTransitionDidEnd(_ completed: Bool) { 51 | super.presentationTransitionDidEnd(completed) 52 | 53 | let alertController = self.presentedViewController as! SPAlertController 54 | alertController.delegate?.didPresentAlertController(alertController: alertController) 55 | } 56 | 57 | // MARK: - 3.即将dismiss 58 | override func dismissalTransitionWillBegin() { 59 | super.dismissalTransitionWillBegin() 60 | 61 | let alertController = self.presentedViewController as! SPAlertController 62 | // 遮罩的alpha值从1~0变化,UIViewControllerTransitionCoordinator协议执行动画可以保证和转场动画同步 63 | let coordinator = self.presentedViewController.transitionCoordinator 64 | if let coordinatorT = coordinator { 65 | coordinatorT.animate(alongsideTransition: { (context) in 66 | self.overlayView.alpha = 0.0 67 | }, completion: nil) 68 | } else { 69 | self.overlayView.alpha = 0.0 70 | } 71 | alertController.delegate?.willDismissAlertController(alertController: alertController) 72 | } 73 | // MARK: - 4.已经dismissed 74 | override func dismissalTransitionDidEnd(_ completed: Bool) { 75 | super.dismissalTransitionDidEnd(completed) 76 | 77 | if completed { 78 | self.overlayView.removeFromSuperview() 79 | } 80 | let alertController = self.presentedViewController as! SPAlertController 81 | alertController.delegate?.didDismissAlertController(alertController: alertController) 82 | } 83 | 84 | 85 | override var frameOfPresentedViewInContainerView: CGRect{ 86 | return self.presentedView!.frame 87 | } 88 | 89 | 90 | lazy var overlayView: SPOverlayView = { 91 | let overlay = SPOverlayView.init() 92 | overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] 93 | let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapOverlayView)) 94 | overlay.addGestureRecognizer(tap) 95 | self.containerView?.addSubview(overlay) 96 | return overlay 97 | }() 98 | 99 | @objc func tapOverlayView() { 100 | let alertController = self.presentedViewController as! SPAlertController 101 | // DLog(alertController.backgroundViewAlpha) 102 | if alertController.tapBackgroundViewDismiss { 103 | alertController.dismiss(animated: true, completion: nil) 104 | } 105 | } 106 | // TODO: 没必要吧? 107 | // deinit { 108 | // NotificationCenter.default.removeObserver(self) 109 | // } 110 | } 111 | -------------------------------------------------------------------------------- /SPAlertController/SPConstant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPConstant.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/11/27. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let SP_SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width 12 | let SP_SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height 13 | let SP_LINE_COLOR: UIColor = UIColor.gray.withAlphaComponent(0.3) 14 | let SP_NORMAL_COLOR: UIColor = UIColor.white.withAlphaComponent(0.7) 15 | let SP_SELECTED_COLOR: UIColor = UIColor.init(white: 1.0, alpha: 0.4) 16 | let SP_LINE_WIDTH: CGFloat = 1.0/UIScreen.main.scale 17 | let Is_iPhoneX: Bool = SP_SCREEN_HEIGHT >= 812.0 18 | let SP_STATUS_BAR_HEIGHT: CGFloat = Is_iPhoneX ? 44.0 : 20.0 19 | let SP_ACTION_TITLE_FONTSIZE: CGFloat = 18.0 20 | let SP_ACTION_HEIGHT: CGFloat = 55.0 21 | 22 | public enum SPAlertControllerStyle { 23 | case actionSheet 24 | case alert 25 | } 26 | 27 | public enum SPAlertAnimationType: Int { 28 | case `default` 29 | case fromBottom 30 | case fromTop 31 | case fromRight 32 | case fromLeft 33 | 34 | case shrink 35 | case expand 36 | case fade 37 | case none 38 | } 39 | 40 | public enum SPAlertActionStyle { 41 | case `default` 42 | case cancel 43 | case destructive 44 | } 45 | 46 | public enum SPBackgroundViewAppearanceStyle { 47 | case translucent 48 | case blurDark 49 | case blurExtraLight 50 | case blurLight 51 | } 52 | 53 | -------------------------------------------------------------------------------- /SPAlertController/SPInteractiveTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPInteractiveTransition.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/16. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | // Handles interactive transition triggered via pan gesture recognizer on dialog 11 | class SPInteractiveTransition: UIPercentDrivenInteractiveTransition { 12 | // If the interactive transition was started 13 | var hasStarted = false 14 | 15 | // If the interactive transition 16 | var shouldFinish = false 17 | 18 | // The view controller containing the views 19 | // with attached gesture recognizers weak 20 | var viewController: SPAlertController? 21 | 22 | @objc func handlePan(_ sender: UIPanGestureRecognizer) { 23 | 24 | guard let vc = viewController else { return } 25 | 26 | guard let progress = calculateProgress(sender: sender) else { return } 27 | switch sender.state { 28 | case .began: 29 | hasStarted = true 30 | vc.dismiss(animated: true, completion: nil) 31 | case .changed: 32 | shouldFinish = progress > 0.3 33 | update(progress) 34 | case .cancelled: 35 | hasStarted = false 36 | cancel() 37 | case .ended: 38 | hasStarted = false 39 | completionSpeed = 0.55 40 | shouldFinish ? finish() : cancel() 41 | default: 42 | break 43 | } 44 | } 45 | } 46 | 47 | extension SPInteractiveTransition { 48 | 49 | /*! 50 | Translates the pan gesture recognizer position to the progress percentage 51 | - parameter sender: A UIPanGestureRecognizer 52 | - returns: Progress 53 | */ 54 | func calculateProgress(sender: UIPanGestureRecognizer) -> CGFloat? { 55 | guard let vc = viewController else { return nil } 56 | 57 | // http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/ 58 | let translation = sender.translation(in: vc.view) 59 | let verticalMovement: CGFloat = translation.y / vc.view.bounds.height 60 | 61 | var downwardMovement: Float = 0.0 62 | if viewController?.animationType == .fromTop && viewController?.preferredStyle == .actionSheet { 63 | downwardMovement = fmaxf(Float(-verticalMovement), 0.0) 64 | } else { 65 | downwardMovement = fmaxf(Float(verticalMovement), 0.0) 66 | } 67 | let downwardMovementPercent = fminf(downwardMovement, 1.0) 68 | 69 | let progress = CGFloat(downwardMovementPercent) 70 | 71 | return progress 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /SPAlertController/SPInterfaceActionItemSeparatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPInterfaceActionItemSeparatorView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/11/27. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPInterfaceActionItemSeparatorView: UIView { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | 16 | self.backgroundColor = SP_LINE_COLOR 17 | } 18 | 19 | required init?(coder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | 23 | override func layoutSubviews() { 24 | super.layoutSubviews() 25 | 26 | self.backgroundColor = self.frame.size.height > SP_LINE_WIDTH ? UIColor.gray.withAlphaComponent(0.15) : SP_LINE_COLOR 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /SPAlertController/SPOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPOverlayView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPOverlayView: UIView { 12 | 13 | private var presentedView: UIView? 14 | private var effectView: UIVisualEffectView? 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | 19 | self.isUserInteractionEnabled = true 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | func setAppearanceStyle(appearanceStyle: SPBackgroundViewAppearanceStyle, alpha: CGFloat) { 27 | switch appearanceStyle { 28 | case .translucent: 29 | self.effectView?.removeFromSuperview() 30 | self.effectView = nil 31 | var tempAlpha: CGFloat = alpha 32 | if alpha < 0 { 33 | tempAlpha = 0.5 34 | } 35 | self.backgroundColor = .init(white: 0, alpha: tempAlpha) 36 | self.alpha = 0 37 | case .blurExtraLight: 38 | let blur = UIBlurEffect.init(style: .extraLight) 39 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 40 | 41 | case .blurLight: 42 | let blur = UIBlurEffect.init(style: .light) 43 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 44 | case .blurDark: 45 | let blur = UIBlurEffect.init(style: .dark) 46 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 47 | } 48 | } 49 | 50 | func creatVisualEffectView(withBlu blur: UIBlurEffect, alpha: CGFloat) { 51 | self.backgroundColor = .clear 52 | let effectV = UIVisualEffectView.init(frame: self.bounds) 53 | effectV.effect = blur 54 | effectV.autoresizingMask = [.flexibleWidth, .flexibleHeight] 55 | effectV.isUserInteractionEnabled = false 56 | effectV.alpha = alpha 57 | self.addSubview(effectV) 58 | effectView = effectV 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/.SPAlertController.version: -------------------------------------------------------------------------------- 1 | { 2 | "Mac" : [ 3 | 4 | ], 5 | "watchOS" : [ 6 | 7 | ], 8 | "tvOS" : [ 9 | 10 | ], 11 | "commitish" : "2d4ff34ead472ebe420af58fa40275b4f6017469", 12 | "iOS" : [ 13 | { 14 | "name" : "SPAlertController", 15 | "hash" : "fcd82b990521cde8f90c15f8c7393569b73c033a3988844ab55a878ce0ff328f", 16 | "swiftToolchainVersion" : "5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.ETrans.SPAlertController 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework.dSYM/Contents/Resources/DWARF/SPAlertController: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework.dSYM/Contents/Resources/DWARF/SPAlertController -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Headers/SPAlertController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertController.h 3 | // SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/15. 6 | // Copyright © 2020 HeFahu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SPAlertController. 12 | FOUNDATION_EXPORT double SPAlertControllerVersionNumber; 13 | 14 | //! Project version string for SPAlertController. 15 | FOUNDATION_EXPORT const unsigned char SPAlertControllerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Info.plist -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64-apple-ios.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64-apple-ios.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64-apple-ios.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64-apple-ios.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/arm64.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7-apple-ios.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7-apple-ios.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7-apple-ios.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7-apple-ios.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/armv7.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386-apple-ios-simulator.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386-apple-ios-simulator.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386-apple-ios-simulator.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386-apple-ios-simulator.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/i386.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64-apple-ios-simulator.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64-apple-ios-simulator.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64-apple-ios-simulator.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64-apple-ios-simulator.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/SPAlertController.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module SPAlertController { 2 | umbrella header "SPAlertController.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module SPAlertController.Swift { 9 | header "SPAlertController-Swift.h" 10 | requires objc 11 | } 12 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/SPAlertController: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Carthage/Build/iOS/SPAlertController.framework/SPAlertController -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/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 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertAction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertAction.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class SPAlertAction: NSObject { 12 | 13 | /// Whether button should dismiss popup when tapped 14 | open var dismissOnTap = true 15 | 16 | public var title: String? { 17 | didSet{ 18 | self.propertyChangedClosure?(self,true) 19 | } 20 | } 21 | /// action的富文本标题 22 | public var attributedTitle: NSAttributedString? { 23 | didSet { 24 | self.propertyChangedClosure?(self,true) 25 | } 26 | } 27 | /// action的图标,位于title的左边 28 | public var image: UIImage? { 29 | didSet { 30 | self.propertyChangedClosure?(self,true) 31 | } 32 | } 33 | /// title跟image之间的间距 34 | public var imageTitleSpacing: CGFloat = 0 { 35 | didSet{ 36 | self.propertyChangedClosure?(self,true) 37 | } 38 | } 39 | /// 样式 40 | public var style: SPAlertActionStyle = .default 41 | /// 是否能点击,默认为YES 42 | public var isEnabled: Bool = true { 43 | didSet{ // enabled改变不需要更新布局 44 | self.propertyChangedClosure?(self,false) 45 | } 46 | } 47 | /// action的标题颜色,这个颜色只是普通文本的颜色,富文本颜色需要用NSForegroundColorAttributeName 48 | public var titleColor: UIColor = .black { 49 | didSet{// 颜色改变不需要更新布局 50 | self.propertyChangedClosure?(self,false) 51 | } 52 | } 53 | /// action的标题字体,如果文字太长显示不全,会自动改变字体自适应按钮宽度,最多压缩文字为原来的0.5倍封顶 54 | public var titleFont: UIFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) { 55 | didSet{// 字体改变需要更新布局 56 | self.propertyChangedClosure?(self,true) 57 | } 58 | } 59 | /// action的标题的内边距,如果在不改变字体的情况下想增大action的高度,可以设置该属性的top和bottom值,默认UIEdgeInsetsMake(0, 15, 0, 15) 60 | public var titleEdgeInsets: UIEdgeInsets = .init(top: 0, left: 15, bottom: 0, right: 15) 61 | 62 | public var handler: ((SPAlertAction) ->Void)? 63 | //当在addAction之后设置action属性时,会回调这个block,设置相应控件的字体、颜色等 64 | /// 如果没有这个block,那使用时,只有在addAction之前设置action的属性才有效 65 | internal var propertyChangedClosure: ((SPAlertAction, Bool) ->Void)? 66 | 67 | public class func action(withTitle title: String?, 68 | style: SPAlertActionStyle, 69 | handler: @escaping (SPAlertAction)->Void) -> SPAlertAction { 70 | let action = SPAlertAction.init(title: title, style: style, handler: handler) 71 | return action 72 | } 73 | 74 | convenience init(title: String?, style: SPAlertActionStyle, handler: @escaping ((SPAlertAction) ->Void)) { 75 | 76 | self.init() 77 | self.title = title 78 | self.style = style 79 | self.handler = handler 80 | 81 | if style == .destructive { 82 | self.titleColor = .red 83 | self.titleFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 84 | } else if style == .cancel { 85 | self.titleColor = .black 86 | self.titleFont = UIFont.boldSystemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 87 | } else { 88 | self.titleFont = UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE) 89 | self.titleColor = .black 90 | } 91 | } 92 | 93 | } 94 | 95 | extension SPAlertAction: NSCopying{ 96 | // 由于要对装载action的数组进行拷贝,所以SPAlertAction也需要支持拷贝 97 | public func copy(with zone: NSZone? = nil) -> Any { 98 | let action = SPAlertAction() 99 | action.title = self.title 100 | action.attributedTitle = self.attributedTitle 101 | action.image = self.image 102 | action.imageTitleSpacing = self.imageTitleSpacing 103 | action.style = self.style 104 | action.isEnabled = self.isEnabled 105 | action.titleColor = self.titleColor 106 | action.titleFont = self.titleFont 107 | action.titleEdgeInsets = self.titleEdgeInsets 108 | action.handler = self.handler 109 | action.propertyChangedClosure = self.propertyChangedClosure 110 | 111 | return action 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertController+transitionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertController+transitionDelegate.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/7. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //FIXME: 文件名修改为`SPAlertController+transitioningDelegate` 12 | 13 | //SPAlertController自定义转场动画,需要遵守`UIViewControllerTransitioningDelegate`,实现必要的协议 14 | //MARK: UIViewControllerTransitioningDelegate 15 | extension SPAlertController: UIViewControllerTransitioningDelegate { 16 | 17 | // 2.如何弹出的动画 18 | public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 19 | 20 | return SPAlertAnimation.animationIsPresenting(isPresenting: true, interactor: self.interactor) 21 | } 22 | // 3.如何dismissed的动画 23 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 24 | 25 | self.view.endEditing(true) 26 | return SPAlertAnimation.animationIsPresenting(isPresenting: false, interactor: self.interactor) 27 | } 28 | // 1.返回一个自定义的UIPresentationController 29 | // 控制控制器跳转的类,是iOS8新增的一个API,用来控制controller之间的跳转特效, 30 | public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 31 | return SPAlertPresentationController.init(customOverlay: customOverlayView, presentedViewController: presented, presenting: presenting) 32 | //return SPAlertPresentationController.init(presentedViewController: presented, presenting: presenting) 33 | } 34 | 35 | public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 36 | return interactor.hasStarted ? interactor : nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertController.h 3 | // SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/15. 6 | // Copyright © 2020 HeFahu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SPAlertController. 12 | FOUNDATION_EXPORT double SPAlertControllerVersionNumber; 13 | 14 | //! Project version string for SPAlertController. 15 | FOUNDATION_EXPORT const unsigned char SPAlertControllerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertControllerActionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertControllerActionView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPAlertControllerActionView: UIView { 12 | 13 | 14 | public var afterSpacing: CGFloat = SP_LINE_WIDTH 15 | 16 | private var actionButtonConstraints = [NSLayoutConstraint]() 17 | private var methodAction: Selector! 18 | private var target: AnyObject! 19 | 20 | 21 | func addTarget(target: AnyObject, action: Selector) { 22 | self.target = target 23 | self.methodAction = action 24 | } 25 | //手指按下然后在按钮有效事件范围内抬起 26 | @objc func touchUpInside() { 27 | _ = target.perform(self.methodAction, with: self) 28 | } 29 | //手指按下或者手指按下后往外拽再往内拽 30 | @objc func touchDown(button: UIButton) { 31 | guard let alert = self.findAlertController() else{ return } 32 | 33 | if alert.needDialogBlur { 34 | // 需要毛玻璃时,只有白色带透明,毛玻璃效果才更加清澈 35 | button.backgroundColor = SP_SELECTED_COLOR 36 | } else { 37 | // 该颜色比'取消action'上的分割线的颜色浅一些 38 | button.backgroundColor = UIColor.gray.withAlphaComponent(0.1) 39 | } 40 | } 41 | // 手指被迫停止、手指按下后往外拽或者取消,取消的可能性:比如点击的那一刻突然来电话 42 | @objc func touchDragExit(button: UIButton) { 43 | button.backgroundColor = SP_NORMAL_COLOR 44 | } 45 | 46 | func findAlertController() -> SPAlertController? { 47 | var next = self.next 48 | while next != nil { 49 | if next is SPAlertController { 50 | return next as? SPAlertController 51 | } else { 52 | next = next?.next 53 | } 54 | } 55 | return nil 56 | } 57 | 58 | // 安全区域发生了改变,在这个方法里自动适配iPhoneX 59 | override func safeAreaInsetsDidChange() { 60 | if #available(iOS 11.0, *) { 61 | super.safeAreaInsetsDidChange() 62 | self.actionButton.contentEdgeInsets = self.edgeInsetsAddEdgeInsets(i1: self.safeAreaInsets, i2: action.titleEdgeInsets) 63 | } else { 64 | // Fallback on earlier versions 65 | } 66 | 67 | self.setNeedsUpdateConstraints() 68 | } 69 | 70 | override func updateConstraints() { 71 | super.updateConstraints() 72 | 73 | if self.actionButtonConstraints.count > 0 { 74 | NSLayoutConstraint.deactivate(self.actionButtonConstraints) 75 | self.actionButtonConstraints.removeAll() 76 | } 77 | 78 | actionButtonConstraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[actionButton]-0-|", options: [], metrics: nil, views: ["actionButton": actionButton])) 79 | actionButtonConstraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[actionButton]-0-|", options: [], metrics: nil, views: ["actionButton": actionButton])) 80 | // 按钮必须确认高度,因为其父视图及父视图的父视图乃至根视图都没有设置高度,而且必须用NSLayoutRelationEqual,如果用NSLayoutRelationGreaterThanOrEqual,虽然也能撑起父视图,但是当某个按钮的高度有所变化以后,stackView会将其余按钮按的高度同比增减 81 | 82 | // titleLabel的内容自适应的高度 55 83 | let labelH: CGFloat = actionButton.titleLabel?.intrinsicContentSize.height ?? 0.0 84 | // 按钮的上下内边距之和 0 85 | let topBottom_insetsSum: CGFloat = actionButton.contentEdgeInsets.top+actionButton.contentEdgeInsets.bottom 86 | // 文字的上下间距之和,等于SP_ACTION_HEIGHT-默认字体大小,这是为了保证文字上下有一个固定间距值,不至于使文字靠按钮太紧,,由于按钮内容默认垂直居中,所以最终的顶部或底部间距为topBottom_marginSum/2.0,这个间距,几乎等于18号字体时,最小高度为49时的上下间距 33.5 87 | let topBottom_marginSum: CGFloat = SP_ACTION_HEIGHT-UIFont.systemFont(ofSize: SP_ACTION_TITLE_FONTSIZE).lineHeight 88 | 89 | // 按钮高度 90 | let buttonH = labelH+topBottom_insetsSum+topBottom_marginSum 91 | 92 | var relation = NSLayoutConstraint.Relation.equal 93 | if let stackView = self.superview as? UIStackView, stackView.axis == .horizontal { 94 | relation = .greaterThanOrEqual 95 | } 96 | // 如果字体保持默认18号,只有一行文字时最终结果约等于SP_ACTION_HEIGHT 97 | let buttonHonstraint = NSLayoutConstraint.init(item: actionButton, attribute: .height, relatedBy: relation, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: buttonH) 98 | buttonHonstraint.priority = UILayoutPriority(rawValue: 999) 99 | actionButtonConstraints.append(buttonHonstraint) 100 | 101 | // 给一个最小高度,当按钮字体很小时,如果还按照上面的高度计算,高度会比较小 102 | let minHConstraint = NSLayoutConstraint.init(item: actionButton, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: SP_ACTION_HEIGHT+topBottom_insetsSum) 103 | minHConstraint.priority = UILayoutPriority.required 104 | self.addConstraints(actionButtonConstraints) 105 | } 106 | 107 | private func edgeInsetsAddEdgeInsets(i1: UIEdgeInsets, i2: UIEdgeInsets) -> UIEdgeInsets { 108 | var bottom: CGFloat = i1.bottom 109 | if bottom > 21 {// 34的高度太大,这里转为21 110 | bottom = 21 111 | } 112 | return .init(top: i1.top+i2.top, left: i1.left+i2.left, bottom: bottom+i2.bottom, right: i1.right+i2.right) 113 | } 114 | 115 | 116 | lazy var actionButton: UIButton = { 117 | let btn = UIButton.init(type: .custom) 118 | if #available(iOS 13, *) { 119 | btn.backgroundColor = .tertiarySystemBackground 120 | } else { 121 | btn.backgroundColor = SP_NORMAL_COLOR 122 | } 123 | 124 | btn.translatesAutoresizingMaskIntoConstraints = false 125 | btn.titleLabel?.textAlignment = .center 126 | btn.titleLabel?.adjustsFontSizeToFitWidth = true 127 | btn.titleLabel?.baselineAdjustment = .alignCenters 128 | btn.titleLabel?.minimumScaleFactor = 0.5 129 | btn.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside) 130 | btn.addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragInside]) 131 | btn.addTarget(self, action: #selector(touchDragExit), for: [.touchDragExit, .touchUpOutside, .touchCancel]) 132 | self.addSubview(btn) 133 | return btn 134 | }() 135 | 136 | public var action: SPAlertAction! { 137 | didSet { 138 | self.actionButton.titleLabel?.font = action.titleFont 139 | if action.isEnabled == true { 140 | self.actionButton.setTitleColor(action.titleColor, for: .normal) 141 | } else { 142 | self.actionButton.setTitleColor(.lightGray, for: .normal) 143 | } 144 | 145 | // 注意不能赋值给按钮的titleEdgeInsets,当只有文字时,按钮的titleEdgeInsets设置top和bottom值无效 146 | self.actionButton.contentEdgeInsets = action.titleEdgeInsets 147 | self.actionButton.isEnabled = action.isEnabled 148 | if action.attributedTitle != nil { 149 | // 这里之所以要设置按钮颜色为黑色,是因为如果外界在addAction:之后设置按钮的富文本,那么富文本的颜色在没有采用NSForegroundColorAttributeName的情况下会自动读取按钮上普通文本的颜色,在addAction:之前设置会保持默认色(黑色),为了在addAction:前后设置富文本保持统一,这里先将按钮置为黑色,富文本就会是黑色 150 | self.actionButton.setTitleColor(.black, for: .normal) 151 | if action.attributedTitle!.string.contains("\n") || action.attributedTitle!.string.contains("\r") { 152 | self.actionButton.titleLabel?.lineBreakMode = .byWordWrapping 153 | } 154 | self.actionButton.setAttributedTitle(action.attributedTitle!, for: .normal) 155 | // 设置完富文本之后,还原按钮普通文本的颜色,其实这行代码加不加都不影响,只是为了让按钮普通文本的颜色保持跟action.titleColor一致 156 | self.actionButton.setTitleColor(action.titleColor, for: .normal) 157 | } else { 158 | 159 | if let title = action.title { 160 | if title.contains("\n") || title.contains("\r") { 161 | self.actionButton.titleLabel?.lineBreakMode = .byWordWrapping 162 | } 163 | self.actionButton.setTitle(title, for: .normal) 164 | } 165 | 166 | } 167 | self.actionButton.setImage(action.image, for: .normal) 168 | self.actionButton.titleEdgeInsets = .init(top: 0, left: action.imageTitleSpacing, bottom: 0, right: -action.imageTitleSpacing) 169 | self.actionButton.imageEdgeInsets = .init(top: 0, left: -action.imageTitleSpacing, bottom: 0, right: action.imageTitleSpacing) 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertControllerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertControllerDelegate.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //: NSObject 12 | protocol SPAlertControllerDelegate{ 13 | 14 | } 15 | 16 | extension SPAlertControllerDelegate { 17 | 18 | /// 将要present 19 | func willPresentAlertController(alertController: SPAlertController) { 20 | 21 | } 22 | /// 已经present 23 | func didPresentAlertController(alertController: SPAlertController) { 24 | 25 | } 26 | /// 将要dismiss 27 | func willDismissAlertController(alertController: SPAlertController) { 28 | 29 | } 30 | /// 已经dismiss 31 | func didDismissAlertController(alertController: SPAlertController) { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPAlertPresentationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPAlertPresentationController.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // UIPresentationController控制控制器跳转的类,是iOS8新增的一个API,用来控制 controller之间的跳转特效, 12 | // 例如:显示一个模态窗口,大小和位置是自定义的,遮罩在原来的页面 13 | class SPAlertPresentationController: UIPresentationController { 14 | 15 | /// 自定义背景蒙版 16 | var customOverlayView: UIView? 17 | convenience init(customOverlay: UIView?, presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { 18 | self.init(presentedViewController: presentedViewController, presenting: presentingViewController) 19 | self.customOverlayView = customOverlay 20 | } 21 | 22 | 23 | override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { 24 | super.init(presentedViewController: presentedViewController, presenting: presentingViewController) 25 | } 26 | 27 | override func containerViewWillLayoutSubviews() { 28 | super.containerViewWillLayoutSubviews() 29 | if let containerV = self.containerView { 30 | self.overlayView.frame = containerV.bounds 31 | //self.customOverlayView?.frame = containerV.bounds 32 | } 33 | } 34 | 35 | override func containerViewDidLayoutSubviews() { 36 | super.containerViewDidLayoutSubviews() 37 | } 38 | 39 | // MARK: - 1.将要开始弹出 40 | override func presentationTransitionWillBegin() { 41 | super.presentationTransitionWillBegin() 42 | 43 | let alertController = self.presentedViewController as! SPAlertController 44 | if customOverlayView == nil { 45 | (overlayView as! SPOverlayView).setAppearanceStyle(appearanceStyle: alertController.backgroundViewAppearanceStyle, alpha: alertController.backgroundViewAlpha) 46 | } 47 | 48 | // 遮罩的alpha值从0~1变化,UIViewControllerTransitionCoordinator协是一个过渡协调器,当执行模态过渡或push过渡时,可以对视图中的其他部分做动画 49 | let coordinator = self.presentedViewController.transitionCoordinator 50 | if let coordinatorT = coordinator { 51 | coordinatorT.animate(alongsideTransition: { (context) in 52 | self.overlayView.alpha = 1.0 53 | }, completion: nil) 54 | } else { 55 | self.overlayView.alpha = 1.0 56 | } 57 | alertController.delegate?.willPresentAlertController(alertController: alertController) 58 | 59 | } 60 | // MARK: - 2.已经弹出 61 | override func presentationTransitionDidEnd(_ completed: Bool) { 62 | super.presentationTransitionDidEnd(completed) 63 | 64 | let alertController = self.presentedViewController as! SPAlertController 65 | alertController.delegate?.didPresentAlertController(alertController: alertController) 66 | } 67 | 68 | // MARK: - 3.即将dismiss 69 | override func dismissalTransitionWillBegin() { 70 | super.dismissalTransitionWillBegin() 71 | 72 | let alertController = self.presentedViewController as! SPAlertController 73 | // 遮罩的alpha值从1~0变化,UIViewControllerTransitionCoordinator协议执行动画可以保证和转场动画同步 74 | let coordinator = self.presentedViewController.transitionCoordinator 75 | if let coordinatorT = coordinator { 76 | coordinatorT.animate(alongsideTransition: { (context) in 77 | self.overlayView.alpha = 0.0 78 | }, completion: nil) 79 | } else { 80 | self.overlayView.alpha = 0.0 81 | } 82 | alertController.delegate?.willDismissAlertController(alertController: alertController) 83 | } 84 | // MARK: - 4.已经dismissed 85 | override func dismissalTransitionDidEnd(_ completed: Bool) { 86 | super.dismissalTransitionDidEnd(completed) 87 | 88 | if completed { 89 | self.overlayView.removeFromSuperview() 90 | } 91 | let alertController = self.presentedViewController as! SPAlertController 92 | alertController.delegate?.didDismissAlertController(alertController: alertController) 93 | } 94 | 95 | 96 | override var frameOfPresentedViewInContainerView: CGRect{ 97 | return self.presentedView!.frame 98 | } 99 | 100 | // private lazy var overlayView: CustomOverlayView = { 101 | // let overlay = CustomOverlayView.init() 102 | // overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] 103 | // let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapOverlayView)) 104 | // overlay.addGestureRecognizer(tap) 105 | // self.containerView?.insertSubview(overlay, at: 0) 106 | // // self.containerView?.addSubview(overlay) 107 | // return overlay 108 | // }() 109 | var _overlayView: UIView? 110 | private var overlayView: UIView { 111 | if _overlayView == nil { 112 | if let customView = customOverlayView { 113 | _overlayView = customView 114 | } else { 115 | _overlayView = SPOverlayView.init() 116 | } 117 | _overlayView!.autoresizingMask = [.flexibleWidth, .flexibleHeight] 118 | let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapOverlayView)) 119 | _overlayView!.addGestureRecognizer(tap) 120 | self.containerView?.insertSubview(_overlayView!, at: 0) 121 | } 122 | return _overlayView! 123 | } 124 | 125 | // lazy var overlayView: SPOverlayView = { 126 | // let overlay = SPOverlayView.init() 127 | // overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] 128 | // let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapOverlayView)) 129 | // overlay.addGestureRecognizer(tap) 130 | // self.containerView?.addSubview(overlay) 131 | // return overlay 132 | // }() 133 | 134 | 135 | @objc func tapOverlayView() { 136 | let alertController = self.presentedViewController as! SPAlertController 137 | if alertController.tapBackgroundViewDismiss { 138 | alertController.dismiss(animated: true, completion: nil) 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPConstant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPConstant.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/11/27. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let SP_SCREEN_WIDTH: CGFloat = UIScreen.main.bounds.size.width 12 | let SP_SCREEN_HEIGHT: CGFloat = UIScreen.main.bounds.size.height 13 | let SP_LINE_COLOR: UIColor = UIColor.gray.withAlphaComponent(0.3) 14 | let SP_NORMAL_COLOR: UIColor = UIColor.white.withAlphaComponent(0.7) 15 | 16 | let SP_SELECTED_COLOR: UIColor = UIColor.init(white: 1.0, alpha: 0.4) 17 | let SP_LINE_WIDTH: CGFloat = 1.0/UIScreen.main.scale 18 | let Is_iPhoneX: Bool = SP_SCREEN_HEIGHT >= 812.0 19 | let SP_STATUS_BAR_HEIGHT: CGFloat = Is_iPhoneX ? 44.0 : 20.0 20 | let SP_ACTION_TITLE_FONTSIZE: CGFloat = 18.0 21 | let SP_ACTION_HEIGHT: CGFloat = 55.0 22 | 23 | public enum SPAlertControllerStyle { 24 | case actionSheet 25 | case alert 26 | } 27 | 28 | public enum SPAlertAnimationType: Int { 29 | case `default` 30 | case fromBottom 31 | case fromTop 32 | case fromRight 33 | case fromLeft 34 | 35 | case shrink 36 | case expand 37 | case fade 38 | case none 39 | } 40 | 41 | public enum SPAlertActionStyle { 42 | case `default` 43 | case cancel 44 | case destructive 45 | } 46 | 47 | public enum SPBackgroundViewAppearanceStyle { 48 | case translucent 49 | case blurDark 50 | case blurExtraLight 51 | case blurLight 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPInteractiveTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPInteractiveTransition.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/16. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | // Handles interactive transition triggered via pan gesture recognizer on dialog 11 | class SPInteractiveTransition: UIPercentDrivenInteractiveTransition { 12 | // If the interactive transition was started 13 | var hasStarted = false 14 | 15 | // If the interactive transition 16 | var shouldFinish = false 17 | 18 | // The view controller containing the views 19 | // with attached gesture recognizers weak 20 | var viewController: SPAlertController? 21 | 22 | @objc func handlePan(_ sender: UIPanGestureRecognizer) { 23 | 24 | guard let vc = viewController else { return } 25 | 26 | guard let progress = calculateProgress(sender: sender) else { return } 27 | switch sender.state { 28 | case .began: 29 | hasStarted = true 30 | vc.dismiss(animated: true, completion: nil) 31 | case .changed: 32 | shouldFinish = progress > 0.3 33 | update(progress) 34 | case .cancelled: 35 | hasStarted = false 36 | cancel() 37 | case .ended: 38 | hasStarted = false 39 | completionSpeed = 0.55 40 | shouldFinish ? finish() : cancel() 41 | default: 42 | break 43 | } 44 | } 45 | } 46 | 47 | extension SPInteractiveTransition { 48 | 49 | /*! 50 | Translates the pan gesture recognizer position to the progress percentage 51 | - parameter sender: A UIPanGestureRecognizer 52 | - returns: Progress 53 | */ 54 | func calculateProgress(sender: UIPanGestureRecognizer) -> CGFloat? { 55 | guard let vc = viewController else { return nil } 56 | 57 | // http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/ 58 | let translation = sender.translation(in: vc.view) 59 | let verticalMovement: CGFloat = translation.y / vc.view.bounds.height 60 | 61 | var downwardMovement: Float = 0.0 62 | if viewController?.animationType == .fromTop && viewController?.preferredStyle == .actionSheet { 63 | downwardMovement = fmaxf(Float(-verticalMovement), 0.0) 64 | } else { 65 | downwardMovement = fmaxf(Float(verticalMovement), 0.0) 66 | } 67 | let downwardMovementPercent = fminf(downwardMovement, 1.0) 68 | 69 | let progress = CGFloat(downwardMovementPercent) 70 | 71 | return progress 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPInterfaceActionItemSeparatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPInterfaceActionItemSeparatorView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/11/27. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPInterfaceActionItemSeparatorView: UIView { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | 16 | self.backgroundColor = SP_LINE_COLOR 17 | } 18 | 19 | required init?(coder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | 23 | override func layoutSubviews() { 24 | super.layoutSubviews() 25 | 26 | self.backgroundColor = self.frame.size.height > SP_LINE_WIDTH ? UIColor.gray.withAlphaComponent(0.15) : SP_LINE_COLOR 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Swift_SPAlertController/SPAlertController/SPOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SPOverlayView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/12/6. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SPOverlayView: UIView { 12 | 13 | private var presentedView: UIView? 14 | private var effectView: UIVisualEffectView? 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | 19 | self.isUserInteractionEnabled = true 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | func setAppearanceStyle(appearanceStyle: SPBackgroundViewAppearanceStyle, alpha: CGFloat) { 27 | switch appearanceStyle { 28 | case .translucent: 29 | self.effectView?.removeFromSuperview() 30 | self.effectView = nil 31 | var tempAlpha: CGFloat = alpha 32 | if alpha < 0 { 33 | tempAlpha = 0.5 34 | } 35 | self.backgroundColor = .init(white: 0, alpha: tempAlpha) 36 | self.alpha = 0 37 | case .blurExtraLight: 38 | let blur = UIBlurEffect.init(style: .extraLight) 39 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 40 | 41 | case .blurLight: 42 | let blur = UIBlurEffect.init(style: .light) 43 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 44 | case .blurDark: 45 | let blur = UIBlurEffect.init(style: .dark) 46 | self.creatVisualEffectView(withBlu: blur, alpha: alpha) 47 | } 48 | } 49 | 50 | func creatVisualEffectView(withBlu blur: UIBlurEffect, alpha: CGFloat) { 51 | self.backgroundColor = .clear 52 | let effectV = UIVisualEffectView.init(frame: self.bounds) 53 | effectV.effect = blur 54 | effectV.autoresizingMask = [.flexibleWidth, .flexibleHeight] 55 | effectV.isUserInteractionEnabled = false 56 | effectV.alpha = alpha 57 | self.addSubview(effectV) 58 | effectView = effectV 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/ETrans.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/ETrans.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/xcshareddata/xcschemes/SPAlertController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/xcuserdata/ETrans.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController.xcodeproj/xcuserdata/ETrans.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SPAlertController.xcscheme_^#shared#^_ 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | Swift_SPAlertController.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 0 20 | 21 | 22 | SuppressBuildableAutocreation 23 | 24 | D6315172238E4FD30043D403 25 | 26 | primary 27 | 28 | 29 | D6A5A3B727F8009E00967937 30 | 31 | primary 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2019/11/27. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | var window: UIWindow? 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/AppIcon-1.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_0.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_0@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_0@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_0.imageset/publish_0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_0.imageset/publish_0@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_0.imageset/publish_0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_0.imageset/publish_0@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_1@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_1@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_1.imageset/publish_1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_1.imageset/publish_1@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_1.imageset/publish_1@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_1.imageset/publish_1@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_10@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_10@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_11@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_11@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_2@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_2@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_2.imageset/publish_2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_2.imageset/publish_2@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_2.imageset/publish_2@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_2.imageset/publish_2@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_3@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_3@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_3.imageset/publish_3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_3.imageset/publish_3@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_3.imageset/publish_3@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_3.imageset/publish_3@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_4@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_4@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_4.imageset/publish_4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_4.imageset/publish_4@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_4.imageset/publish_4@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_4.imageset/publish_4@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_5@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_5@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_5.imageset/publish_5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_5.imageset/publish_5@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_5.imageset/publish_5@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_5.imageset/publish_5@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_6@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_6@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_7@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_7@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_8@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_8@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "publish_9@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "publish_9@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/success.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "勾.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/success.imageset/勾.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/success.imageset/勾.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/telephone.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "telephone@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "telephone@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/telephone.imageset/telephone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/telephone.imageset/telephone@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/telephone.imageset/telephone@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/telephone.imageset/telephone@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/video.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "video@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "video@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/video.imageset/video@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/video.imageset/video@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/video.imageset/video@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/video.imageset/video@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/wechatLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "wechatLogo@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "wechatLogo@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/zhiwen.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "zhiwen@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "zhiwen@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@2x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@3x.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "减号.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "减号-1.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "减号-2.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号-1.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号-2.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/减号.imageset/减号.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "加号-1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "加号-3.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "加号-4.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-1.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-3.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/加号.imageset/加号-4.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "叉-1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "叉-2.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "叉-3.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-1.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-2.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/取消.imageset/叉-3.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/苹果logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "苹果logo.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/苹果logo.imageset/苹果logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Assets.xcassets/苹果logo.imageset/苹果logo.png -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Base.lproj/LaunchScreen.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 | 26 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/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 | 26 | 27 | 28 | 29 | 30 | 31 | 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 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomOverlayView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/17. 6 | // Copyright © 2020 HeFahu. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomOverlayView: UIView { 12 | 13 | // MARK: - Appearance 14 | 15 | /// Turns the blur of the overlay view on or off 16 | @objc public dynamic var blurEnabled: Bool { 17 | get { return !blurView.isHidden } 18 | set { blurView.isHidden = !newValue } 19 | } 20 | 21 | /// The blur radius of the overlay view 22 | @objc public dynamic var blurRadius: CGFloat { 23 | get { return blurView.blurRadius } 24 | set { blurView.blurRadius = newValue } 25 | } 26 | 27 | /// Whether the blur view should allow for 28 | /// live rendering of the background 29 | @objc public dynamic var liveBlurEnabled: Bool { 30 | get { return blurView.trackingMode == .common } 31 | set { 32 | if newValue { 33 | blurView.trackingMode = .common 34 | } else { 35 | blurView.trackingMode = .none 36 | } 37 | } 38 | } 39 | 40 | /// The background color of the overlay view 41 | @objc public dynamic var color: UIColor? { 42 | get { return overlay.backgroundColor } 43 | set { overlay.backgroundColor = newValue } 44 | } 45 | 46 | /// The opacity of the overlay view 47 | @objc public dynamic var opacity: CGFloat { 48 | get { return overlay.alpha } 49 | set { overlay.alpha = newValue } 50 | } 51 | 52 | // MARK: - Views 53 | 54 | internal lazy var blurView: DynamicBlurView = { 55 | let blurView = DynamicBlurView(frame: .zero) 56 | blurView.blurRadius = 8 57 | blurView.trackingMode = .none 58 | blurView.isDeepRendering = true 59 | blurView.tintColor = .clear 60 | blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth] 61 | return blurView 62 | }() 63 | 64 | internal lazy var overlay: UIView = { 65 | let overlay = UIView(frame: .zero) 66 | overlay.backgroundColor = .black 67 | overlay.alpha = 0.7 68 | overlay.autoresizingMask = [.flexibleHeight, .flexibleWidth] 69 | return overlay 70 | }() 71 | 72 | // MARK: - Inititalizers 73 | 74 | override init(frame: CGRect) { 75 | super.init(frame: frame) 76 | setupView() 77 | } 78 | 79 | required public init?(coder aDecoder: NSCoder) { 80 | fatalError("init(coder:) has not been implemented") 81 | } 82 | 83 | // MARK: - View setup 84 | 85 | fileprivate func setupView() { 86 | 87 | autoresizingMask = [.flexibleHeight, .flexibleWidth] 88 | backgroundColor = .clear 89 | alpha = 0 90 | 91 | addSubview(blurView) 92 | addSubview(overlay) 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView1/SendAlertView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SendAlertView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/11. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SendAlertView: UIView,Nibloadable { 12 | 13 | @IBOutlet weak var userIconView: UIImageView! 14 | @IBOutlet weak var nameLabel: UILabel! 15 | @IBOutlet weak var contentImageView: UIImageView! 16 | @IBOutlet weak var contentHeightConstraint: NSLayoutConstraint! 17 | @IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint! 18 | 19 | @IBOutlet weak var textView: UITextView! 20 | 21 | var contentImage: UIImage? { 22 | didSet{ 23 | contentImageView.image = contentImage 24 | guard let img = contentImage else { return } 25 | var contentH: CGFloat = 0 26 | let imgRatio: CGFloat = img.size.height/img.size.width 27 | let contentW: CGFloat = bounds.size.width-30// 30是contentImageView的左右间距之和 28 | if img.size.height < contentW { 29 | contentH = img.size.height 30 | } else { 31 | contentH = imgRatio * contentW 32 | } 33 | if contentH > UIScreen.main.bounds.size.height-300 { 34 | contentH = UIScreen.main.bounds.size.height-300 35 | } 36 | // 更新图片的高度约束 37 | self.contentHeightConstraint.constant = contentH 38 | } 39 | } 40 | 41 | override func awakeFromNib() { 42 | super.awakeFromNib() 43 | 44 | userIconView.layer.cornerRadius = 4.0 45 | userIconView.layer.masksToBounds = true 46 | textView.delegate = self 47 | textView.layer.borderWidth = 0.5/UIScreen.main.scale 48 | // textView.layer.borderColor = UIColor 49 | // textView.placeholder = "给朋友留言" 50 | // textView.placeholderColor = .l 51 | /* 52 | self.textView.layer.borderColor = [[UIColor grayColor] colorWithAlphaComponent:0.3].CGColor; 53 | self.textView.placeholder = @"给朋友留言"; 54 | self.textView.placeholderColor = [UIColor lightGrayColor]; 55 | */ 56 | } 57 | 58 | 59 | 60 | 61 | 62 | } 63 | 64 | extension SendAlertView: UITextViewDelegate { 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView2/MyView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MyView: UIView, Nibloadable { 12 | 13 | @IBOutlet weak var cancelButton: UIButton! 14 | 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView2/PassWordView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPassWordView.h 3 | // Youqun 4 | // 5 | // Created by 乐升平 on 16/6/1. 6 | // Copyright © 2016年 iDress. All rights reserved. 7 | // 8 | 9 | #import 10 | @class PassWordView; 11 | 12 | @protocol PassWordViewDelegate 13 | 14 | @optional 15 | /** 16 | * 监听输入的改变 17 | */ 18 | - (void)passWordDidChange:(PassWordView *)passWord; 19 | 20 | /** 21 | * 监听输入的完成时 22 | */ 23 | - (void)passWordCompleteInput:(PassWordView *)passWord; 24 | 25 | /** 26 | * 监听开始输入 27 | */ 28 | - (void)passWordBeginInput:(PassWordView *)passWord; 29 | 30 | 31 | @end 32 | 33 | IB_DESIGNABLE 34 | 35 | @interface PassWordView : UIView 36 | 37 | @property (assign, nonatomic) IBInspectable NSUInteger passWordNum;//密码的位数 38 | @property (assign, nonatomic) IBInspectable CGFloat squareWidth;//正方形的大小 39 | @property (assign, nonatomic) IBInspectable CGFloat pointRadius;//黑点的半径 40 | @property (strong, nonatomic) IBInspectable UIColor *pointColor;//黑点的颜色 41 | @property (strong, nonatomic) IBInspectable UIColor *rectColor;//边框的颜色 42 | @property (weak, nonatomic) IBOutlet id delegate; 43 | @property (strong, nonatomic, readonly) NSMutableString *textStore;//保存密码的字符串 44 | 45 | @end 46 | 47 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView2/PassWordView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPassWordView.m 3 | // Youqun 4 | // 5 | // Created by 乐升平 on 16/6/1. 6 | // Copyright © 2016年 iDress. All rights reserved. 7 | // 8 | 9 | #import "PassWordView.h" 10 | 11 | @interface PassWordView () 12 | 13 | @property (strong, nonatomic) NSMutableString *textStore;// 保存密码的字符串 14 | 15 | @end 16 | 17 | @implementation PassWordView 18 | 19 | static NSString * const MONEYNUMBERS = @"0123456789"; 20 | 21 | - (instancetype)initWithCoder:(NSCoder *)coder { 22 | self = [super initWithCoder:coder]; 23 | if (self) { 24 | self.textStore = [NSMutableString string]; 25 | self.squareWidth = 45; 26 | self.passWordNum = 6; 27 | self.pointRadius = 6; 28 | self.rectColor = [UIColor colorWithRed:51.0/255.0 green:51.0/255.0 blue:51.0/255.0 alpha:1.0]; 29 | self.pointColor = [UIColor colorWithRed:223.0/255.0 green:223.0/255.0 blue:223.0/255.0 alpha:1.0]; 30 | [self becomeFirstResponder]; 31 | } 32 | return self; 33 | } 34 | 35 | /** 36 | * 设置正方形的边长 37 | */ 38 | - (void)setSquareWidth:(CGFloat)squareWidth { 39 | _squareWidth = squareWidth; 40 | [self setNeedsDisplay]; 41 | } 42 | 43 | /** 44 | * 设置键盘的类型 45 | */ 46 | - (UIKeyboardType)keyboardType { 47 | return UIKeyboardTypeNumberPad; 48 | } 49 | 50 | /** 51 | * 设置密码的位数 52 | */ 53 | - (void)setPassWordNum:(NSUInteger)passWordNum { 54 | _passWordNum = passWordNum; 55 | [self setNeedsDisplay]; 56 | } 57 | 58 | - (BOOL)becomeFirstResponder { 59 | if ([self.delegate respondsToSelector:@selector(passWordBeginInput:)]) { 60 | [self.delegate passWordBeginInput:self]; 61 | } 62 | return [super becomeFirstResponder]; 63 | } 64 | 65 | /** 66 | * 是否能成为第一响应者 67 | */ 68 | - (BOOL)canBecomeFirstResponder { 69 | return YES; 70 | } 71 | 72 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 73 | if (![self isFirstResponder]) { 74 | [self becomeFirstResponder]; 75 | } 76 | } 77 | 78 | #pragma mark - UIKeyInput 79 | /** 80 | * 用于显示的文本对象是否有任何文本 81 | */ 82 | - (BOOL)hasText { 83 | return self.textStore.length > 0; 84 | } 85 | 86 | /** 87 | * 插入文本 88 | */ 89 | - (void)insertText:(NSString *)text { 90 | if (self.textStore.length < self.passWordNum) { 91 | //判断是否是数字 92 | NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:MONEYNUMBERS] invertedSet]; 93 | NSString*filtered = [[text componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""]; 94 | BOOL basicTest = [text isEqualToString:filtered]; 95 | if(basicTest) { 96 | [self.textStore appendString:text]; 97 | if ([self.delegate respondsToSelector:@selector(passWordDidChange:)]) { 98 | [self.delegate passWordDidChange:self]; 99 | } 100 | if (self.textStore.length == self.passWordNum) { 101 | if ([self.delegate respondsToSelector:@selector(passWordCompleteInput:)]) { 102 | [self.delegate passWordCompleteInput:self]; 103 | } 104 | } 105 | [self setNeedsDisplay]; 106 | } 107 | } 108 | } 109 | 110 | /** 111 | * 删除文本 112 | */ 113 | - (void)deleteBackward { 114 | if (self.textStore.length > 0) { 115 | [self.textStore deleteCharactersInRange:NSMakeRange(self.textStore.length - 1, 1)]; 116 | if ([self.delegate respondsToSelector:@selector(passWordDidChange:)]) { 117 | [self.delegate passWordDidChange:self]; 118 | } 119 | } 120 | [self setNeedsDisplay]; 121 | } 122 | 123 | // Only override drawRect: if you perform custom drawing. 124 | - (void)drawRect:(CGRect)rect { 125 | CGFloat height = rect.size.height; 126 | CGFloat width = rect.size.width; 127 | CGFloat x = (width - self.squareWidth*self.passWordNum)/2.0; 128 | CGFloat y = (height - self.squareWidth)/2.0; 129 | CGContextRef context = UIGraphicsGetCurrentContext(); 130 | //画外框 131 | CGContextAddRect(context, CGRectMake( x, y, self.squareWidth*self.passWordNum, self.squareWidth)); 132 | CGContextSetLineWidth(context, 1); 133 | CGContextSetStrokeColorWithColor(context, self.rectColor.CGColor); 134 | CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); 135 | //画竖条 136 | for (int i = 1; i <= self.passWordNum; i++) { 137 | CGContextMoveToPoint(context, x+i*self.squareWidth, y); 138 | CGContextAddLineToPoint(context, x+i*self.squareWidth, y+self.squareWidth); 139 | CGContextClosePath(context); 140 | } 141 | CGContextDrawPath(context, kCGPathFillStroke); 142 | CGContextSetFillColorWithColor(context, self.pointColor.CGColor); 143 | //画黑点 144 | for (int i = 1; i <= self.textStore.length; i++) { 145 | CGContextAddArc(context, x+i*self.squareWidth - self.squareWidth/2.0, y+self.squareWidth/2, self.pointRadius, 0, M_PI*2, YES); 146 | CGContextDrawPath(context, kCGPathFill); 147 | } 148 | } 149 | 150 | 151 | @end 152 | 153 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView2/Swift_SPAlertController-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "PassWordView.h" 6 | #import "HCSStarRatingView.h" 7 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView3/ShoppingCartCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShoppingCartCell.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShoppingCartCell: UITableViewCell { 12 | 13 | @IBOutlet weak var foodNameLabel: UILabel! 14 | @IBOutlet weak var priceLabel: UILabel! 15 | @IBOutlet weak var countLabel: UILabel! 16 | 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | 20 | } 21 | 22 | override func setSelected(_ selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | 25 | // Configure the view for the selected state 26 | } 27 | 28 | @IBAction func reduceAction(_ sender: Any) { 29 | 30 | 31 | } 32 | 33 | 34 | @IBAction func addAction(_ sender: Any) { 35 | 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView3/ShoppingCartView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShoppingCartView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShoppingCartView: UIView { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | 16 | self.addSubview(topLabel) 17 | self.addSubview(tableView) 18 | } 19 | 20 | required init?(coder: NSCoder) { 21 | fatalError("init(coder:) has not been implemented") 22 | } 23 | 24 | override func layoutSubviews() { 25 | super.layoutSubviews() 26 | 27 | var topLabelY: CGFloat = 0.0 28 | if #available(iOS 11, *) { 29 | topLabelY = self.safeAreaInsets.top 30 | } else { 31 | topLabelY = 20 32 | } 33 | topLabel.frame = CGRect.init(x: 0, y: topLabelY, width: self.bounds.size.width, height: 44) 34 | let tableViewY: CGFloat = topLabel.frame.maxY 35 | tableView.frame = CGRect.init(x: 0, y: tableViewY, width: self.bounds.size.width, height: self.bounds.size.height-tableViewY) 36 | } 37 | 38 | lazy var topLabel: UILabel = { 39 | let label = UILabel() 40 | label.backgroundColor = UIColor.init(red: 244.0/255.0, green: 244.0/255.0, blue: 244.0/255.0, alpha: 1.0) 41 | label.text = "购物车" 42 | label.textAlignment = .center 43 | return label 44 | }() 45 | 46 | lazy var tableView: UITableView = { 47 | let tableV = UITableView.init(frame: .zero, style: .plain) 48 | tableV.delegate = self 49 | tableV.dataSource = self 50 | tableV.showsVerticalScrollIndicator = false 51 | tableV.register(UINib.init(nibName: "ShoppingCartCell", bundle: nil), forCellReuseIdentifier: "ShoppingCartCell") 52 | return tableV 53 | }() 54 | } 55 | 56 | extension ShoppingCartView: UITableViewDelegate, UITableViewDataSource { 57 | 58 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 59 | return 15 60 | } 61 | 62 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 63 | let cell = tableView.dequeueReusableCell(withIdentifier: "ShoppingCartCell")! 64 | return cell 65 | } 66 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 67 | return 50 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView4/CommodityListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommodityListView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CommodityListView: UIView { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | 16 | self.addSubview(scrollView) 17 | } 18 | 19 | override func layoutSubviews() { 20 | super.layoutSubviews() 21 | 22 | scrollView.frame = self.bounds 23 | let imageViewW: CGFloat = bounds.size.width/2-20 24 | let imageViewH: CGFloat = bounds.size.height 25 | var imageViewY: CGFloat = 0 26 | if #available(iOS 11, *) { 27 | imageViewY = self.safeAreaInsets.top 28 | } 29 | var lastImageView: UIImageView! 30 | for (index,imgView) in imageViews.enumerated() { 31 | imgView.frame = CGRect.init(x: (imageViewW + 10.0) * CGFloat(index), y: imageViewY, width: imageViewW, height: imageViewH) 32 | if index == self.imageViews.count-1 { 33 | lastImageView = imgView 34 | } 35 | } 36 | scrollView.contentSize = CGSize.init(width: lastImageView.frame.maxX, height: 0) 37 | } 38 | 39 | required init?(coder: NSCoder) { 40 | fatalError("init(coder:) has not been implemented") 41 | } 42 | 43 | var imageViews = [UIImageView]() 44 | let images = ["image0.jpg", "image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg", "image5.jpg", "image6.jpg", "image7.jpg", "image8.jpg", "image9.jpg"] 45 | 46 | lazy var scrollView: UIScrollView = { 47 | let scrollV = UIScrollView() 48 | scrollV.backgroundColor = UIColor.init(red: 244.0/255.0, green: 244.0/255.0, blue: 244.0/255.0, alpha: 1.0) 49 | scrollV.showsVerticalScrollIndicator = false 50 | 51 | for (index,imgName) in images.enumerated() { 52 | let imageView = UIImageView.init(image: UIImage.init(named: imgName)) 53 | imageView.backgroundColor = .red 54 | scrollV.addSubview(imageView) 55 | imageViews.append(imageView) 56 | } 57 | return scrollV 58 | }() 59 | } 60 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView5/PickerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PickerView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PickerView: UIView, Nibloadable { 12 | 13 | @IBOutlet weak var pickView: UIPickerView! 14 | 15 | var cancelClickedClosure: (()->Void)? 16 | var doneClickedClosure: (()->Void)? 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | 21 | pickView.delegate = self 22 | pickView.dataSource = self 23 | } 24 | 25 | @IBAction func cancelClick(_ sender: Any) { 26 | cancelClickedClosure?() 27 | } 28 | 29 | @IBAction func doneClick(_ sender: Any) { 30 | doneClickedClosure?() 31 | } 32 | } 33 | 34 | extension PickerView: UIPickerViewDelegate, UIPickerViewDataSource { 35 | func numberOfComponents(in pickerView: UIPickerView) -> Int { 36 | return 1 37 | } 38 | func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 39 | return 2 40 | } 41 | 42 | func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 43 | return ["男","女"][row] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView5/PickerView.xib: -------------------------------------------------------------------------------- 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 | 26 | 27 | 28 | 29 | 30 | 31 | 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 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView6/HCSStarRatingView.h: -------------------------------------------------------------------------------- 1 | // HCSStarRatingView.h 2 | // 3 | // Copyright (c) 2015 Hugo Sousa 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | @import UIKit; 24 | 25 | typedef BOOL(^HCSStarRatingViewShouldBeginGestureRecognizerBlock)(UIGestureRecognizer *gestureRecognizer); 26 | 27 | IB_DESIGNABLE 28 | @interface HCSStarRatingView : UIControl 29 | @property (nonatomic) IBInspectable NSUInteger maximumValue; 30 | @property (nonatomic) IBInspectable CGFloat minimumValue; 31 | @property (nonatomic) IBInspectable CGFloat value; 32 | @property (nonatomic) IBInspectable CGFloat spacing; 33 | @property (nonatomic) IBInspectable BOOL allowsHalfStars; 34 | @property (nonatomic) IBInspectable BOOL accurateHalfStars; 35 | @property (nonatomic) IBInspectable BOOL continuous; 36 | 37 | @property (nonatomic) BOOL shouldBecomeFirstResponder; 38 | 39 | // Optional: if `nil` method will return `NO`. 40 | @property (nonatomic, copy) HCSStarRatingViewShouldBeginGestureRecognizerBlock shouldBeginGestureRecognizerBlock; 41 | 42 | @property (nonatomic, strong) IBInspectable UIColor *starBorderColor; 43 | @property (nonatomic) IBInspectable CGFloat starBorderWidth; 44 | 45 | @property (nonatomic, strong) IBInspectable UIColor *emptyStarColor; 46 | 47 | @property (nonatomic, strong) IBInspectable UIImage *emptyStarImage; 48 | @property (nonatomic, strong) IBInspectable UIImage *halfStarImage; 49 | @property (nonatomic, strong) IBInspectable UIImage *filledStarImage; 50 | @end 51 | 52 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView6/ScoreView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScoreView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ScoreView: UIView { 12 | 13 | var finishClickedClosure: (()->Void)? 14 | 15 | override init(frame: CGRect) { 16 | super.init(frame: frame) 17 | 18 | self.addSubview(starRatingView) 19 | self.addSubview(lineView) 20 | self.addSubview(finishButton) 21 | } 22 | 23 | required init?(coder: NSCoder) { 24 | fatalError("init(coder:) has not been implemented") 25 | } 26 | 27 | @objc func finishButtonAction() { 28 | finishClickedClosure?() 29 | } 30 | 31 | override func updateConstraints() { 32 | super.updateConstraints() 33 | 34 | // 星星 35 | starRatingView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 40).isActive = true 36 | starRatingView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -40).isActive = true 37 | starRatingView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true 38 | starRatingView.bottomAnchor.constraint(equalTo: lineView.topAnchor, constant: 0).isActive = true 39 | starRatingView.heightAnchor.constraint(equalToConstant: 50).isActive = true 40 | 41 | // 线 42 | let lineH: CGFloat = 1.0/UIScreen.main.scale 43 | lineView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true 44 | lineView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true 45 | lineView.bottomAnchor.constraint(equalTo: finishButton.topAnchor).isActive = true 46 | lineView.heightAnchor.constraint(equalToConstant: lineH).isActive = true 47 | 48 | // 完成 49 | finishButton.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true 50 | finishButton.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true 51 | finishButton.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true 52 | finishButton.heightAnchor.constraint(equalToConstant: 50).isActive = true 53 | } 54 | 55 | lazy var starRatingView: HCSStarRatingView = { 56 | let starRatingV = HCSStarRatingView() 57 | starRatingV.translatesAutoresizingMaskIntoConstraints = false 58 | starRatingV.maximumValue = 5 59 | starRatingV.minimumValue = 0 60 | starRatingV.value = 2 61 | starRatingV.spacing = 20 62 | starRatingV.tintColor = UIColor.init(red: 0.0, green: 0.48, blue: 1.0, alpha: 1.0) 63 | starRatingV.allowsHalfStars = true 64 | return starRatingV 65 | }() 66 | 67 | lazy var lineView: UIView = { 68 | let line = UIView() 69 | line.translatesAutoresizingMaskIntoConstraints = false 70 | line.backgroundColor = UIColor.lightGray 71 | line.alpha = 0.3 72 | return line 73 | }() 74 | 75 | lazy var finishButton: UIButton = { 76 | let btn = UIButton.init(type: .custom) 77 | btn.translatesAutoresizingMaskIntoConstraints = false 78 | btn.backgroundColor = UIColor.white 79 | let titleColor = UIColor.init(red: 0.0, green: 0.48, blue: 1.0, alpha: 1.0) 80 | btn.setTitleColor(titleColor, for: .normal) 81 | btn.setTitle("完成", for: .normal) 82 | btn.addTarget(self, action: #selector(finishButtonAction), for: .touchUpInside) 83 | return btn 84 | }() 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/CustomViews/CustomView7/MyCenterView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyCenterView.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/13. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MyCenterView: UIView, UITableViewDataSource { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | 16 | self.addSubview(tableView) 17 | } 18 | 19 | required init?(coder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | 23 | override func layoutSubviews() { 24 | super.layoutSubviews() 25 | 26 | tableView.frame = self.bounds 27 | } 28 | 29 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 30 | return 10 31 | } 32 | 33 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 34 | var cell = tableView.dequeueReusableCell(withIdentifier: "myCell") 35 | if cell == nil { 36 | cell = UITableViewCell.init(style: .value1, reuseIdentifier: "myCell") 37 | } 38 | cell!.textLabel!.text = "第\(indexPath.row)行" 39 | cell!.textLabel!.font = UIFont.systemFont(ofSize: 14) 40 | cell!.detailTextLabel!.text = "这是自定义tableView" 41 | cell!.detailTextLabel!.font = UIFont.systemFont(ofSize: 12) 42 | return cell! 43 | } 44 | 45 | lazy var tableView: UITableView = { 46 | let tableV = UITableView.init(frame: .zero, style: .plain) 47 | tableV.dataSource = self 48 | tableV.showsVerticalScrollIndicator = false 49 | return tableV 50 | }() 51 | } 52 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DLog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DLog.swift 3 | // IsuzuAuto 4 | // 5 | // Created by lidongxi on 2019/8/17. 6 | // Copyright © 2019 lidongxi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol LogLevel { 12 | func myDescription(level: Int) -> String 13 | } 14 | 15 | //封装的日志输出功能(T表示不指定日志信息参数类型) 16 | public func DLog(_ message:T, file:String = #file, function:String = #function, 17 | line:Int = #line) { 18 | #if DEBUG 19 | let fileName = (file as NSString).lastPathComponent 20 | if message is Dictionary { 21 | print("[\(fileName):line:\(line)]- \((message as! Dictionary).myDescription(level: 0))") 22 | }else if message is Array { 23 | print("[\(fileName):line:\(line)]- \((message as! Array ).myDescription(level: 0))") 24 | }else if message is CustomStringConvertible { 25 | print("[\(fileName):line:\(line)]- \((message as! CustomStringConvertible).description)") 26 | }else { 27 | print("[\(fileName):line:\(line)]- \(message)") 28 | } 29 | #endif 30 | } 31 | 32 | 33 | // MARK: - 重写可选型description 34 | extension Optional: CustomStringConvertible { 35 | public var description: String { 36 | switch self { 37 | case .none: 38 | return "Optional(null)" 39 | case .some(let obj): 40 | if let obj = obj as? CustomStringConvertible, obj is Dictionary { 41 | return "Optional:" + "\((obj as! Dictionary).myDescription(level: 0))" 42 | } 43 | if let obj = obj as? CustomStringConvertible, obj is Array { 44 | return "Optional:" + "\((obj as! Array).myDescription(level: 0))" 45 | } 46 | return "Optional" + "(\(obj))" 47 | } 48 | } 49 | } 50 | 51 | // MARK: - 重写字典型description 52 | extension Dictionary: LogLevel { 53 | public var description: String { 54 | var str = "" 55 | str.append(contentsOf: "{\n") 56 | for (key, value) in self { 57 | if value is String { 58 | let s = value as! String 59 | str.append(contentsOf: String.init(format: "\t%@ = \"%@\",\n", key as! CVarArg, s.unicodeStr)) 60 | }else if value is Dictionary { 61 | str.append(contentsOf: String.init(format: "\t%@ = \"%@\",\n", key as! CVarArg, (value as! Dictionary).description)) 62 | }else if value is Array { 63 | str.append(contentsOf: String.init(format: "\t%@ = \"%@\",\n", key as! CVarArg, (value as! Array).description)) 64 | }else { 65 | str.append(contentsOf: String.init(format: "\t%@ = \"%@\",\n", key as! CVarArg, "\(value)")) 66 | } 67 | } 68 | str.append(contentsOf: "}") 69 | return str 70 | } 71 | 72 | public func myDescription(level: Int) -> String{ 73 | var str = "" 74 | var tab = "" 75 | for _ in 0.. { 86 | str.append(contentsOf: String.init(format: "%@\t%@ = %@,\n", tab, key as! CVarArg, (value as! Array).myDescription(level: level + 1))) 87 | }else { 88 | str.append(contentsOf: String.init(format: "%@\t%@ = %@,\n", tab, key as! CVarArg, "\(value)")) 89 | } 90 | } 91 | str.append(contentsOf: String.init(format: "%@}", tab)) 92 | return str 93 | } 94 | } 95 | 96 | extension Array: LogLevel { 97 | public func myDescription(level: Int) -> String { 98 | var str = "" 99 | var tab = "" 100 | str.append(contentsOf: "[\n") 101 | for _ in 0.. { 109 | str.append(contentsOf: String.init(format: "%@\t%@,\n", tab, (value as! Dictionary).myDescription(level: level + 1))) 110 | }else if value is Array { 111 | str.append(contentsOf: String.init(format: "%@\t%@,\n", tab, (value as! Array).myDescription(level: level + 1))) 112 | }else { 113 | str.append(contentsOf: String.init(format: "%@\t%@,\n", tab, "\(value)")) 114 | } 115 | } 116 | str.append(contentsOf: String.init(format: "%@]", tab)) 117 | return str 118 | } 119 | 120 | public var description: String { 121 | var str = "" 122 | str.append(contentsOf: "[\n") 123 | for (_, value) in self.enumerated() { 124 | if value is String { 125 | let s = value as! String 126 | str.append(contentsOf: String.init(format: "\t\"%@\",\n", s.unicodeStr)) 127 | }else if value is Dictionary { 128 | str.append(contentsOf: String.init(format: "\t%@,\n", (value as! Dictionary).description)) 129 | }else if value is Array { 130 | str.append(contentsOf: String.init(format: "\t%@,\n", (value as! Array).description)) 131 | }else { 132 | str.append(contentsOf: String.init(format: "\t%@,\n", "\(value)")) 133 | } 134 | } 135 | str.append(contentsOf: "]") 136 | return str 137 | } 138 | } 139 | 140 | // MARK: - unicode转码 141 | extension String { 142 | func unicodeStrWith(level: Int) -> String { 143 | let s = self 144 | let data = s.data(using: .utf8) 145 | if let data = data { 146 | if let id = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) { 147 | if id is Array { 148 | return (id as! Array).myDescription(level: level + 1) 149 | }else if id is Dictionary { 150 | return (id as! Dictionary).myDescription(level: level + 1) 151 | } 152 | } 153 | } 154 | let tempStr1 = self.replacingOccurrences(of: "\\u", with: "\\U") 155 | let tempStr2 = tempStr1.replacingOccurrences(of: "\"", with: "\\\"") 156 | let tempStr3 = "\"".appending(tempStr2).appending("\"") 157 | let tempData = tempStr3.data(using: String.Encoding.utf8) 158 | var returnStr:String = "" 159 | do { 160 | returnStr = try PropertyListSerialization.propertyList(from: tempData!, options: [.mutableContainers], format: nil) as! String 161 | } catch { 162 | print(error) 163 | } 164 | return returnStr.replacingOccurrences(of: "\\r\\n", with: "\n") 165 | } 166 | var unicodeStr:String { 167 | return self.unicodeStrWith(level: 1) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/BlurLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlurLayer.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2017/08/14. 6 | // Copyright © 2017年 kyohei_ito. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private extension CGRect { 12 | func rectangle(_ s: CGSize) -> CGRect { 13 | let x = origin.x / s.width 14 | let y = origin.y / s.height 15 | let width = size.width / s.width 16 | let height = size.height / s.height 17 | return CGRect(x: x, y: y, width: width, height: height) 18 | } 19 | } 20 | 21 | class BlurLayer: CALayer { 22 | private static let blurRadiusKey = "blurRadius" 23 | private static let blurLayoutKey = "blurLayout" 24 | @NSManaged var blurRadius: CGFloat 25 | @NSManaged private var blurLayout: CGFloat 26 | 27 | private var fromBlurRadius: CGFloat? 28 | var presentationRadius: CGFloat { 29 | if let radius = fromBlurRadius { 30 | if let layer = presentation() { 31 | return layer.blurRadius 32 | } else { 33 | return radius 34 | } 35 | } else { 36 | return blurRadius 37 | } 38 | } 39 | 40 | override class func needsDisplay(forKey key: String) -> Bool { 41 | if key == blurRadiusKey || key == blurLayoutKey { 42 | return true 43 | } 44 | return super.needsDisplay(forKey: key) 45 | } 46 | 47 | open override func action(forKey event: String) -> CAAction? { 48 | if event == BlurLayer.blurRadiusKey { 49 | fromBlurRadius = nil 50 | 51 | if let action = super.action(forKey: "opacity") as? CABasicAnimation { 52 | fromBlurRadius = (presentation() ?? self).blurRadius 53 | 54 | action.keyPath = event 55 | action.fromValue = fromBlurRadius 56 | return action 57 | } 58 | } 59 | 60 | if event == BlurLayer.blurLayoutKey, let action = super.action(forKey: "opacity") as? CABasicAnimation { 61 | action.keyPath = event 62 | action.fromValue = 0 63 | action.toValue = 1 64 | return action 65 | } 66 | 67 | return super.action(forKey: event) 68 | } 69 | } 70 | 71 | extension BlurLayer { 72 | func draw(_ image: UIImage, fixes isFixes: Bool, baseLayer: CALayer?) { 73 | contents = image.cgImage 74 | contentsScale = image.scale 75 | 76 | if isFixes, let blurLayer = presentation() { 77 | contentsRect = blurLayer.convert(blurLayer.bounds, to: baseLayer).rectangle(image.size) 78 | } 79 | } 80 | 81 | func refresh() { 82 | fromBlurRadius = nil 83 | } 84 | 85 | func animate() { 86 | UIView.performWithoutAnimation { 87 | blurLayout = 0 88 | } 89 | blurLayout = 1 90 | } 91 | 92 | func render(in context: CGContext, for layer: CALayer) { 93 | let layers = hideOverlappingLayers(layer.sublayers) 94 | layer.render(in: context) 95 | layers.forEach { 96 | $0.isHidden = false 97 | } 98 | } 99 | 100 | private func hideOverlappingLayers(_ layers: [CALayer]?) -> [CALayer] { 101 | var hiddenLayers: [CALayer] = [] 102 | guard let layers = layers else { 103 | return hiddenLayers 104 | } 105 | 106 | for layer in layers.reversed() { 107 | if isHang(to: layer) { 108 | return hiddenLayers + hideOverlappingLayers(layer.sublayers) 109 | } 110 | if layer.isHidden == false { 111 | layer.isHidden = true 112 | hiddenLayers.append(layer) 113 | } 114 | if layer == self { 115 | return hiddenLayers 116 | } 117 | } 118 | return hiddenLayers 119 | } 120 | 121 | private func isHang(to target: CALayer) -> Bool { 122 | var layer = superlayer 123 | while layer != nil { 124 | if layer == target { 125 | return true 126 | } 127 | layer = layer?.superlayer 128 | } 129 | return false 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/CGContext+CGImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGContext+CGImage.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2017/08/17. 6 | // Copyright © 2017年 kyohei_ito. All rights reserved. 7 | // 8 | import UIKit 9 | extension CGContext { 10 | static func imageContext(with quality: CaptureQuality, rect: CGRect, opaque: Bool) -> CGContext? { 11 | UIGraphicsBeginImageContextWithOptions(rect.size, opaque, quality.imageScale) 12 | guard let context = UIGraphicsGetCurrentContext() else { 13 | return nil 14 | } 15 | 16 | context.translateBy(x: -rect.origin.x, y: -rect.origin.y) 17 | context.interpolationQuality = quality.interpolationQuality 18 | 19 | return context 20 | } 21 | 22 | func makeImage(with blendColor: UIColor?, blendMode: CGBlendMode, size: CGSize) -> CGImage? { 23 | if let color = blendColor { 24 | setFillColor(color.cgColor) 25 | setBlendMode(blendMode) 26 | fill(CGRect(origin: .zero, size: size)) 27 | } 28 | 29 | return makeImage() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/CGImage+Accelerate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGImage+Accelerate.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2017/08/17. 6 | // Copyright © 2017年 kyohei_ito. All rights reserved. 7 | // 8 | 9 | import Accelerate 10 | import UIKit 11 | extension CGImage { 12 | var area: Int { 13 | return width * height 14 | } 15 | 16 | private var size: CGSize { 17 | return CGSize(width: width, height: height) 18 | } 19 | 20 | private var bytes: Int { 21 | return bytesPerRow * height 22 | } 23 | 24 | private func imageBuffer(from data: UnsafeMutableRawPointer!) -> vImage_Buffer { 25 | return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) 26 | } 27 | 28 | func blurred(with boxSize: UInt32, iterations: Int, blendColor: UIColor?, blendMode: CGBlendMode) -> CGImage? { 29 | guard let providerData = dataProvider?.data else { 30 | return nil 31 | } 32 | 33 | let inData = malloc(bytes) 34 | var inBuffer = imageBuffer(from: inData) 35 | 36 | let outData = malloc(bytes) 37 | var outBuffer = imageBuffer(from: outData) 38 | 39 | let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize)) 40 | let tempData = malloc(tempSize) 41 | 42 | defer { 43 | free(inData) 44 | free(outData) 45 | free(tempData) 46 | } 47 | 48 | let source = CFDataGetBytePtr(providerData) 49 | memcpy(inBuffer.data, source, bytes) 50 | 51 | for _ in 0.. 10 | 11 | //! Project version number for DynamicBlurView. 12 | FOUNDATION_EXPORT double DynamicBlurViewVersionNumber; 13 | 14 | //! Project version string for DynamicBlurView. 15 | FOUNDATION_EXPORT const unsigned char DynamicBlurViewVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/DynamicBlurView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicBlurView.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2015/04/08. 6 | // Copyright (c) 2015年 kyohei_ito. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class DynamicBlurView: UIView { 12 | open override class var layerClass : AnyClass { 13 | return BlurLayer.self 14 | } 15 | 16 | private var staticImage: UIImage? 17 | private var displayLink: CADisplayLink? 18 | private var blurLayer: BlurLayer { 19 | return layer as! BlurLayer 20 | } 21 | private let mainQueue = DispatchQueue.main 22 | private let globalQueue: DispatchQueue = { 23 | if #available (iOS 8.0, *) { 24 | return .global(qos: .userInteractive) 25 | } else { 26 | return .global(priority: .high) 27 | } 28 | }() 29 | private var renderingTarget: UIView? { 30 | if isDeepRendering { 31 | return window 32 | } else { 33 | return superview 34 | } 35 | } 36 | 37 | /// When true, it captures displays image and blur it asynchronously. Try to set true if needs more performance. 38 | /// Asynchronous drawing is possibly crash when needs to process on main thread that drawing with animation for example. 39 | open var drawsAsynchronously: Bool = false 40 | /// Radius of blur. 41 | open var blurRadius: CGFloat { 42 | set { blurLayer.blurRadius = newValue } 43 | get { return blurLayer.blurRadius } 44 | } 45 | /// Default is none. 46 | open var trackingMode: TrackingMode = .none { 47 | didSet { 48 | if trackingMode != oldValue { 49 | linkForDisplay() 50 | } 51 | } 52 | } 53 | /// Blend color. 54 | open var blendColor: UIColor? 55 | /// Blend mode. 56 | open var blendMode: CGBlendMode = .plusLighter 57 | /// Default is 3. 58 | open var iterations: Int = 3 59 | /// If the view want to render beyond the layer, should be true. 60 | open var isDeepRendering: Bool = false 61 | /// When none of tracking mode, it can change the radius of blur with the ratio. Should set from 0 to 1. 62 | open var blurRatio: CGFloat = 1 { 63 | didSet { 64 | if let image = staticImage, oldValue != blurRatio { 65 | draw(image, blurRadius: blurRadius, fixes: false, baseLayer: renderingTarget?.layer) 66 | } 67 | } 68 | } 69 | /// Quality of captured image. 70 | open var quality: CaptureQuality = .medium 71 | 72 | public override init(frame: CGRect) { 73 | super.init(frame: frame) 74 | isUserInteractionEnabled = false 75 | } 76 | 77 | public required init?(coder aDecoder: NSCoder) { 78 | super.init(coder: aDecoder) 79 | isUserInteractionEnabled = false 80 | } 81 | 82 | open override func didMoveToWindow() { 83 | super.didMoveToWindow() 84 | 85 | if let view = renderingTarget, window != nil && trackingMode == .none { 86 | staticImage = snapshotImage(for: view.layer, conversion: !isDeepRendering) 87 | } 88 | } 89 | 90 | open override func didMoveToSuperview() { 91 | super.didMoveToSuperview() 92 | 93 | if superview == nil { 94 | displayLink?.invalidate() 95 | displayLink = nil 96 | } else { 97 | linkForDisplay() 98 | } 99 | } 100 | 101 | private func async(on queue: DispatchQueue, actions: @escaping () -> Void) { 102 | if drawsAsynchronously { 103 | queue.async(execute: actions) 104 | } else { 105 | actions() 106 | } 107 | } 108 | 109 | private func sync(on queue: DispatchQueue, actions: () -> Void) { 110 | if drawsAsynchronously { 111 | queue.sync(execute: actions) 112 | } else { 113 | actions() 114 | } 115 | } 116 | 117 | private func draw(_ image: UIImage, blurRadius radius: CGFloat, fixes isFixes: Bool, baseLayer: CALayer?) { 118 | async(on: globalQueue) { [weak self] in 119 | if let me = self, let blurredImage = image.blurred(radius: radius, iterations: me.iterations, ratio: me.blurRatio, blendColor: me.blendColor, blendMode: me.blendMode) { 120 | me.sync(on: me.mainQueue) { 121 | me.blurLayer.draw(blurredImage, fixes: isFixes, baseLayer: baseLayer) 122 | } 123 | } 124 | } 125 | } 126 | 127 | private func blurLayerRect(to layer: CALayer, conversion: Bool) -> CGRect { 128 | if conversion { 129 | let presentationLayer = blurLayer.presentation() ?? blurLayer 130 | return presentationLayer.convert(presentationLayer.bounds, to: layer) 131 | } else { 132 | return layer.bounds 133 | } 134 | } 135 | 136 | private func snapshotImage(for layer: CALayer, conversion: Bool) -> UIImage? { 137 | let rect = blurLayerRect(to: layer, conversion: conversion) 138 | guard let context = CGContext.imageContext(with: quality, rect: rect, opaque: isOpaque) else { 139 | return nil 140 | } 141 | 142 | blurLayer.render(in: context, for: layer) 143 | 144 | defer { 145 | UIGraphicsEndImageContext() 146 | } 147 | 148 | return UIGraphicsGetImageFromCurrentImageContext() 149 | } 150 | } 151 | 152 | extension DynamicBlurView { 153 | open override func display(_ layer: CALayer) { 154 | let blurRadius = blurLayer.presentationRadius 155 | let isFixes = isDeepRendering && staticImage != nil 156 | if let view = renderingTarget, let image = staticImage ?? snapshotImage(for: view.layer, conversion: !isFixes) { 157 | draw(image, blurRadius: blurRadius, fixes: isFixes, baseLayer: view.layer) 158 | } 159 | } 160 | } 161 | 162 | extension DynamicBlurView { 163 | private func linkForDisplay() { 164 | displayLink?.invalidate() 165 | displayLink = UIScreen.main.displayLink(withTarget: self, selector: #selector(DynamicBlurView.displayDidRefresh(_:))) 166 | displayLink?.add(to: .main, forMode: RunLoop.Mode(rawValue: trackingMode.description)) 167 | } 168 | 169 | @objc private func displayDidRefresh(_ displayLink: CADisplayLink) { 170 | display(layer) 171 | } 172 | } 173 | 174 | extension DynamicBlurView { 175 | /// Remove cache of blur image then get it again. 176 | open func refresh() { 177 | blurLayer.refresh() 178 | staticImage = nil 179 | blurRatio = 1 180 | display(layer) 181 | } 182 | 183 | /// Remove cache of blur image. 184 | open func remove() { 185 | blurLayer.refresh() 186 | staticImage = nil 187 | blurRatio = 1 188 | layer.contents = nil 189 | } 190 | 191 | /// Should use when needs to change layout with animation when is set none of tracking mode. 192 | public func animate() { 193 | blurLayer.animate() 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/TrackingMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrackingMode.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2017/08/17. 6 | // Copyright © 2017年 kyohei_ito. All rights reserved. 7 | // 8 | 9 | public enum TrackingMode: CustomStringConvertible { 10 | case tracking 11 | case common 12 | case none 13 | 14 | public var description: String { 15 | switch self { 16 | case .tracking: 17 | return RunLoop.Mode.tracking.rawValue 18 | case .common: 19 | return RunLoop.Mode.common.rawValue 20 | case .none: 21 | return "" 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/DynamicBlurView/UIImage+Blur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Blur.swift 3 | // DynamicBlurView 4 | // 5 | // Created by Kyohei Ito on 2017/08/11. 6 | // Copyright © 2017年 kyohei_ito. All rights reserved. 7 | // 8 | import UIKit 9 | public extension UIImage { 10 | func blurred(radius: CGFloat, iterations: Int, ratio: CGFloat, blendColor color: UIColor?, blendMode mode: CGBlendMode) -> UIImage? { 11 | guard let cgImage = cgImage else { 12 | return nil 13 | } 14 | 15 | if cgImage.area <= 0 || radius <= 0 { 16 | return self 17 | } 18 | 19 | var boxSize = UInt32(radius * scale * ratio) 20 | if boxSize % 2 == 0 { 21 | boxSize += 1 22 | } 23 | 24 | return cgImage.blurred(with: boxSize, iterations: iterations, blendColor: color, blendMode: mode).map { 25 | UIImage(cgImage: $0, scale: scale, orientation: imageOrientation) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image0.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image1.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image2.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image3.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image4.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image5.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image6.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image7.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image8.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/image9.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/send0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/send0.jpeg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/send1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/send1.jpeg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/背景1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/背景1.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Images/背景2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongxiexidu/SPAlertController/1970af814cbbc30b23a982dfab0095bdbde7f366/Swift_SPAlertController/Swift_SPAlertController/Images/背景2.jpg -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/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 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/Nibloadable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nibloadable.swift 3 | // FashionMall 4 | // 5 | // Created by fashion on 2018/1/17. 6 | // Copyright © 2018年 shangZhu. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | protocol Nibloadable {} 11 | 12 | // 自定义View,遵守此协议,便可以用此方法加载Nib文件 13 | extension Nibloadable where Self : UIView{ 14 | static func loadFromNib() -> Self { 15 | return Bundle.main.loadNibNamed("\(self)", owner: nil, options: nil)?.first as! Self 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/ViewController+Alert.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+Alert.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/10. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension ViewController{ 12 | 13 | 14 | //示例9:alert 默认动画(收缩动画) 15 | func alertTest1() { 16 | 17 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .default) 18 | alert.needDialogBlur = lookBlur 19 | let action1 = SPAlertAction.action(withTitle: "确定", style: .default) { (action) in 20 | print("点击了确定") 21 | } 22 | let action2 = SPAlertAction.action(withTitle: "取消", style: .cancel) { (action) in 23 | print("点击了取消") 24 | } 25 | if customBlur { 26 | alert.customOverlayView = CustomOverlayView() 27 | } 28 | // 设置第2个action的颜色 29 | action2.titleColor = SYSTEM_COLOR 30 | alert.addAction(action: action1) 31 | alert.addAction(action: action2) 32 | self.present(alert, animated: true, completion: nil) 33 | } 34 | 35 | //示例10:alert 发散动画 36 | func alertTest2() { 37 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .expand) 38 | 39 | let action1 = SPAlertAction.action(withTitle: "第1个", style: .default) { (action) in 40 | print("点击了第1个") 41 | } 42 | 43 | let action2 = SPAlertAction.action(withTitle: "抖动动画", style: .destructive) { (action) in 44 | // 抖动动画 45 | alert.shake() 46 | } 47 | action2.dismissOnTap = false 48 | 49 | let action3 = SPAlertAction.action(withTitle: "第3个", style: .default) { (action) in 50 | print("点击了第3个") 51 | } 52 | let action4 = SPAlertAction.action(withTitle: "第4个", style: .default) { (action) in 53 | print("点击了第4个") 54 | } 55 | if customBlur { 56 | alert.customOverlayView = CustomOverlayView() 57 | } 58 | // 设置第2个action的颜色 59 | action1.titleColor = SYSTEM_COLOR 60 | alert.addAction(action: action1) 61 | alert.addAction(action: action2) 62 | alert.addAction(action: action3) 63 | alert.addAction(action: action4) 64 | alert.tapBackgroundViewDismiss = false 65 | self.present(alert, animated: true, completion: nil) 66 | } 67 | 68 | //示例11:alert 渐变动画 69 | func alertTest3() { 70 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .fade) 71 | alert.needDialogBlur = lookBlur 72 | let action1 = SPAlertAction.action(withTitle: "确定", style: .default) { (action) in 73 | print("点击了确定") 74 | } 75 | // 设置第1个action的颜色 76 | action1.titleColor = SYSTEM_COLOR 77 | let action2 = SPAlertAction.action(withTitle: "取消", style: .destructive) { (action) in 78 | print("点击了取消") 79 | } 80 | if customBlur { 81 | alert.customOverlayView = CustomOverlayView() 82 | } 83 | action2.titleColor = .red 84 | alert.addAction(action: action1) 85 | alert.addAction(action: action2) 86 | self.present(alert, animated: true, completion: nil) 87 | } 88 | 89 | //示例12:alert 垂直排列2个按钮 90 | func alertTest4() { 91 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .expand) 92 | // 2个按钮时默认是水平排列,这里强制垂直排列 93 | alert.actionAxis = .vertical 94 | let action1 = SPAlertAction.action(withTitle: "确定", style: .default) { (action) in 95 | print("点击了确定") 96 | } 97 | // 设置第1个action的颜色 98 | action1.titleColor = .red 99 | let action2 = SPAlertAction.action(withTitle: "取消", style: .destructive) { (action) in 100 | print("点击了取消") 101 | } 102 | if customBlur { 103 | alert.customOverlayView = CustomOverlayView() 104 | } 105 | action2.titleColor = SYSTEM_COLOR 106 | alert.addAction(action: action1) 107 | alert.addAction(action: action2) 108 | self.present(alert, animated: true, completion: nil) 109 | } 110 | 111 | //示例13:alert 水平排列2个以上的按钮(默认超过2个按钮是垂直排列) 112 | func alertTest5() { 113 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .expand) 114 | // 2个按钮时默认是水平排列,这里强制水平排列 115 | alert.actionAxis = .horizontal 116 | let action1 = SPAlertAction.action(withTitle: "第1个", style: .default) { (action) in 117 | print("点击了第1个") 118 | } 119 | // 设置第1个action的颜色 120 | action1.titleColor = SYSTEM_COLOR 121 | let action2 = SPAlertAction.action(withTitle: "第2个", style: .destructive) { (action) in 122 | print("点击了第2个") 123 | } 124 | action2.titleColor = .magenta 125 | let action3 = SPAlertAction.action(withTitle: "第3个", style: .destructive) { (action) in 126 | print("点击了第3个") 127 | } 128 | if customBlur { 129 | alert.customOverlayView = CustomOverlayView() 130 | } 131 | alert.addAction(action: action1) 132 | alert.addAction(action: action2) 133 | alert.addAction(action: action3) 134 | self.present(alert, animated: true, completion: nil) 135 | } 136 | 137 | 138 | //示例14:alert 设置头部图标 139 | func alertTest6() { 140 | let alert = SPAlertController.alertController(withTitle: "“支付宝”的触控 ID", message: "请验证已有指纹", preferredStyle: .alert, animationType: .shrink) 141 | alert.image = UIImage.init(named: "zhiwen") 142 | let action = SPAlertAction.action(withTitle: "取消", style: .cancel) { (action) in 143 | print("点击了取消") 144 | } 145 | if customBlur { 146 | alert.customOverlayView = CustomOverlayView() 147 | } 148 | action.titleColor = SYSTEM_COLOR 149 | alert.addAction(action: action) 150 | self.present(alert, animated: true, completion: nil) 151 | } 152 | 153 | //示例15:alert 含有文本输入框 154 | func alertTest7() { 155 | let alert = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .default) 156 | let action1 = SPAlertAction.action(withTitle: "确定", style: .default) { (action) in 157 | print("点击了确定") 158 | } 159 | action1.isEnabled = false 160 | self.sureAction = action1 161 | // 设置第1个action的颜色 162 | action1.titleColor = SYSTEM_COLOR 163 | let action2 = SPAlertAction.action(withTitle: "取消", style: .destructive) { (action) in 164 | print("点击了取消") 165 | } 166 | action2.titleColor = .red 167 | alert.addAction(action: action2) 168 | alert.addAction(action: action1) 169 | 170 | alert.addTextFieldWithConfigurationHandler { (textField) in 171 | DLog("第1个文本输入框回调") 172 | // 这个block只会回调一次,因此可以在这里自由定制textFiled,如设置textField的相关属性,设置代理,添加addTarget,监听通知等 173 | self.phoneNumberTextField = textField 174 | textField.placeholder = "请输入手机号码" 175 | textField.clearButtonMode = .always 176 | textField.addTarget(self, action: #selector(self.textFieldDidChanged(textField:)), for: .editingChanged) 177 | } 178 | alert.addTextFieldWithConfigurationHandler { (textField) in 179 | DLog("第2个文本输入框回调") 180 | self.passwordTextField = textField 181 | textField.placeholder = "请输入密码" 182 | textField.clearButtonMode = .always 183 | textField.addTarget(self, action: #selector(self.textFieldDidChanged(textField:)), for: .editingChanged) 184 | } 185 | if customBlur { 186 | alert.customOverlayView = CustomOverlayView() 187 | } 188 | self.present(alert, animated: true, completion: nil) 189 | } 190 | 191 | @objc func textFieldDidChanged(textField: UITextField) { 192 | self.sureAction.isEnabled = false 193 | guard let phoneNumber = phoneNumberTextField.text else { return } 194 | guard let password = passwordTextField.text else { return } 195 | if password.count > 0 && phoneNumber.count > 0 { 196 | self.sureAction.isEnabled = true 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/ViewController+Attributed.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+Attributed.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/10. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension ViewController { 12 | // 示例16:富文本(action设置富文本) 13 | func attributedStringTest1() { 14 | let alertController = SPAlertController.alertController(withTitle: nil, message: nil, preferredStyle: .actionSheet, animationType: .default) 15 | let action1 = SPAlertAction.action(withTitle: nil, style: .default) { (action) in 16 | print("点击了拍摄") 17 | } 18 | let mainTitle1 = "拍摄" 19 | let subTitle1 = "照片或视频" 20 | let totalTitle1 = mainTitle1+"\n"+subTitle1 21 | let attrTitle1 = NSMutableAttributedString.init(string: totalTitle1) 22 | let paragraphStyle1 = NSMutableParagraphStyle.init() 23 | paragraphStyle1.lineSpacing = 3 24 | paragraphStyle1.lineBreakMode = .byWordWrapping 25 | paragraphStyle1.alignment = .center 26 | // 段落样式 27 | attrTitle1.addAttribute(.paragraphStyle, value: paragraphStyle1, range: .init(location: 0, length: totalTitle1.count)) 28 | // 设置富文本子标题的字体 29 | attrTitle1.addAttribute(.font, value: UIFont.systemFont(ofSize: 12), range: NSRange.init(location: mainTitle1.count, length: subTitle1.count+1)) 30 | attrTitle1.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange.init(location: mainTitle1.count, length: subTitle1.count+1)) 31 | 32 | action1.attributedTitle = attrTitle1 33 | 34 | 35 | let action2 = SPAlertAction.action(withTitle: "从手机相册选择个", style: .default) { (action) in 36 | print("点击了`从手机相册选择`") 37 | } 38 | let action3 = SPAlertAction.action(withTitle: nil, style: .default) { (action) in 39 | print("点击了'用微视拍摄'") 40 | } 41 | 42 | let mainTitle3 = "用微视拍摄" 43 | let subTitle3 = "推广" 44 | let totalTitle3 = mainTitle3+"\n"+subTitle3 45 | let attrTitle3 = NSMutableAttributedString.init(string: totalTitle3) 46 | let paragraphStyle3 = NSMutableParagraphStyle.init() 47 | paragraphStyle3.lineSpacing = 3 48 | paragraphStyle3.lineBreakMode = .byWordWrapping 49 | paragraphStyle3.alignment = .center 50 | // 段落样式 51 | attrTitle1.addAttribute(.paragraphStyle, value: paragraphStyle3, range: .init(location: 0, length: totalTitle3.count)) 52 | // 设置富文本子标题的字体 53 | attrTitle3.addAttribute(.font, value: UIFont.systemFont(ofSize: 12), range: NSRange.init(location: mainTitle3.count, length: subTitle3.count+1)) 54 | attrTitle3.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange.init(location: mainTitle3.count, length: subTitle3.count+1)) 55 | 56 | action3.attributedTitle = attrTitle3 57 | 58 | let action4 = SPAlertAction.action(withTitle: "取消", style: .cancel) { (action) in 59 | print("点击了取消") 60 | } 61 | if customBlur { 62 | alertController.customOverlayView = CustomOverlayView() 63 | } 64 | alertController.addAction(action: action1) 65 | alertController.addAction(action: action2) 66 | alertController.addAction(action: action3) 67 | alertController.addAction(action: action4) 68 | self.present(alertController, animated: true, completion: nil) 69 | } 70 | 71 | 72 | // 示例17:富文本(头部设置富文本) 73 | func attributedStringTest2() { 74 | let alertController = SPAlertController.alertController(withTitle: "", message: "确定拨打吗?", preferredStyle: .alert, animationType: .default) 75 | let num = "15012345689" 76 | let desc = "可能是一个电话号码" 77 | let totalTitle = num+"\n"+desc 78 | let attrTitle = NSMutableAttributedString.init(string: totalTitle) 79 | 80 | // 设置富文本子标题的字体 81 | attrTitle.addAttribute(.foregroundColor, value: SYSTEM_COLOR, range: NSRange.init(location: 0, length: num.count)) 82 | alertController.attributedTitle = attrTitle 83 | 84 | if customBlur { 85 | alertController.customOverlayView = CustomOverlayView() 86 | } 87 | let action1 = SPAlertAction.action(withTitle: "取消", style: .destructive) { (action) in 88 | print("点击了`取消`") 89 | } 90 | let action2 = SPAlertAction.action(withTitle: "确定", style: .default) { (action) in 91 | print("点击了'确定'") 92 | } 93 | action2.titleColor = SYSTEM_COLOR 94 | alertController.addAction(action: action1) 95 | alertController.addAction(action: action2) 96 | self.present(alertController, animated: true, completion: nil) 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/ViewController+Custom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+Custom.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/11. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension ViewController { 12 | 13 | // 示例18:自定义头部(xib) 14 | func customTest1() { 15 | let sendAlertView = SendAlertView.loadFromNib() 16 | // sendAlertView.contentImage = UIImage.init(named: "send0.jpeg") 17 | let alertController = SPAlertController.alertController(withCustomHeaderView: sendAlertView, preferredStyle: .alert, animationType: .default) 18 | alertController.needDialogBlur = false 19 | // let fittingSize = sendAlertView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) 20 | // alertController.updateCustomViewSize(size: fittingSize) 21 | let action1 = SPAlertAction.action(withTitle: "发送", style: .default) { (action) in 22 | print("点击了发送") 23 | } 24 | let action2 = SPAlertAction.action(withTitle: "取消", style: .destructive) { (action) in 25 | print("点击了取消") 26 | } 27 | if customBlur { 28 | alertController.customOverlayView = CustomOverlayView() 29 | } 30 | alertController.addAction(action: action2) 31 | alertController.addAction(action: action1) 32 | self.present(alertController, animated: true, completion: nil) 33 | } 34 | // 示例19:自定义整个对话框(alert样式) 35 | func customTest2() { 36 | let myView = MyView.loadFromNib() 37 | myView.cancelButton.addTarget(self, action: #selector(cancelButtonInCustomHeaderViewClicked), for: .touchUpInside) 38 | let alertController = SPAlertController.alertController(withCustomAlertView: myView, preferredStyle: .alert, animationType: .default) 39 | alertController.offsetForAlert = CGPoint.init(x: 0, y: -100) 40 | if customBlur { 41 | alertController.customOverlayView = CustomOverlayView() 42 | } 43 | self.present(alertController, animated: true, completion: nil) 44 | } 45 | 46 | @objc func cancelButtonInCustomHeaderViewClicked() { 47 | self.dismiss(animated: true, completion: nil) 48 | } 49 | 50 | // 示例20:自定义整个对话框(actionSheet样式从底部弹出) 51 | func customTest3() { 52 | let shoppingCartView = ShoppingCartView() 53 | let alertController = SPAlertController.alertController(withCustomAlertView: shoppingCartView, preferredStyle: .actionSheet, animationType: .fromBottom) 54 | alertController.needDialogBlur = false 55 | alertController.updateCustomViewSize(size: CGSize.init(width: ScreenWidth, height: ScreenHeight*2/3)) 56 | if customBlur { 57 | alertController.customOverlayView = CustomOverlayView() 58 | } 59 | self.present(alertController, animated: true, completion: nil) 60 | } 61 | 62 | // 示例21:自定义整个对话框(actionSheet样式从右边弹出) 63 | func customTest4() { 64 | let shoppingCartView = ShoppingCartView.init(frame: CGRect.init(x: 0, y: 0, width: ScreenWidth-70, height: ScreenHeight)) 65 | shoppingCartView.backgroundColor = .white 66 | let alertController = SPAlertController.alertController(withCustomAlertView: shoppingCartView, preferredStyle: .actionSheet, animationType: .fromRight) 67 | if customBlur { 68 | alertController.customOverlayView = CustomOverlayView() 69 | } 70 | self.present(alertController, animated: true, completion: nil) 71 | } 72 | // 示例22:自定义整个对话框(actionSheet样式从左边弹出) 73 | func customTest5() { 74 | let shoppingCartView = ShoppingCartView.init(frame: CGRect.init(x: 0, y: 0, width: ScreenWidth-70, height: ScreenHeight)) 75 | shoppingCartView.backgroundColor = .white 76 | let alertController = SPAlertController.alertController(withCustomAlertView: shoppingCartView, preferredStyle: .actionSheet, animationType: .fromLeft) 77 | if customBlur { 78 | alertController.customOverlayView = CustomOverlayView() 79 | } 80 | self.present(alertController, animated: true, completion: nil) 81 | } 82 | 83 | // 示例23:自定义整个对话框(actionSheet样式从顶部弹出) 84 | func customTest6() { 85 | let shoppingCartView = CommodityListView.init(frame: CGRect.init(x: 0, y: 0, width: ScreenWidth, height: 200)) 86 | shoppingCartView.backgroundColor = .white 87 | let alertController = SPAlertController.alertController(withCustomAlertView: shoppingCartView, preferredStyle: .actionSheet, animationType: .fromTop) 88 | if customBlur { 89 | alertController.customOverlayView = CustomOverlayView() 90 | } 91 | self.present(alertController, animated: true, completion: nil) 92 | } 93 | 94 | // 示例24:自定义整个对话框(pickerView) 95 | func customTest7() { 96 | let pickerView = PickerView.loadFromNib() 97 | pickerView.backgroundColor = .white 98 | pickerView.cancelClickedClosure = { [weak self] in 99 | self?.presentedViewController?.dismiss(animated: true, completion: nil) 100 | } 101 | pickerView.doneClickedClosure = { [weak self] in 102 | self?.presentedViewController?.dismiss(animated: true, completion: nil) 103 | } 104 | let alertController = SPAlertController.alertController(withCustomAlertView: pickerView, preferredStyle: .actionSheet, animationType: .fromBottom) 105 | if customBlur { 106 | alertController.customOverlayView = CustomOverlayView() 107 | } 108 | self.present(alertController, animated: true, completion: nil) 109 | } 110 | // 示例25:自定义action部分 111 | func customTest8() { 112 | // scoreview的子控件采用的是自动布局,由于高度上能够由子控件撑起来,所以高度可以给0,如果宽度也能撑起,宽度也可以给0 113 | let scoreView = ScoreView.init(frame: CGRect.init(x: 0, y: 0, width: 275, height: 0)) 114 | scoreView.backgroundColor = .white 115 | scoreView.finishClickedClosure = { [weak self] in 116 | self?.presentedViewController?.dismiss(animated: true, completion: nil) 117 | } 118 | 119 | let alertController = SPAlertController.alertController(withCustomActionSequenceView: scoreView, title: "提示", message: "请给我们的app打分", preferredStyle: .alert, animationType: .default) 120 | alertController.needDialogBlur = false 121 | if customBlur { 122 | alertController.customOverlayView = CustomOverlayView() 123 | } 124 | self.present(alertController, animated: true, completion: nil) 125 | } 126 | // 示例25:插入一个组件 127 | func customTest9() { 128 | let centerView = MyCenterView.init(frame: CGRect.init(x: 0, y: 0, width: ScreenWidth-40, height: 200)) 129 | let alertController = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .alert, animationType: .default) 130 | // 插入一个view 131 | alertController.insertComponentView(centerView) 132 | 133 | let action1 = SPAlertAction.action(withTitle: "第1个", style: .default) { (action) in 134 | print("点击了第1个") 135 | } 136 | action1.titleColor = SYSTEM_COLOR 137 | let action2 = SPAlertAction.action(withTitle: "第2个", style: .destructive) { (action) in 138 | print("点击了第2个") 139 | } 140 | action2.titleColor = .red 141 | if customBlur { 142 | alertController.customOverlayView = CustomOverlayView() 143 | } 144 | alertController.addAction(action: action1) 145 | alertController.addAction(action: action2) 146 | self.present(alertController, animated: true, completion: nil) 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/ViewController+Special.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+Special.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/14. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension ViewController { 12 | 13 | // 示例26:当按钮过多时 14 | func specialtest1() { 15 | let alertController = SPAlertController.alertController(withTitle: "请滑动查看更多内容", message: "谢谢", preferredStyle: .actionSheet, animationType: .default) 16 | alertController.minDistanceToEdges = 100 17 | for i in 0..<15 { 18 | let action = SPAlertAction.action(withTitle: "第\(i)个", style: .default) { (action) in 19 | print("点击了第\(i)个") 20 | } 21 | alertController.addAction(action: action) 22 | } 23 | let cancelAction = SPAlertAction.action(withTitle: "取消", style: .cancel) { (action) in 24 | print("点击了cancel") 25 | } 26 | if customBlur { 27 | alertController.customOverlayView = CustomOverlayView() 28 | } 29 | alertController.addAction(action: cancelAction) 30 | self.present(alertController, animated: true, completion: nil) 31 | } 32 | 33 | // 示例27:当文字和按钮同时过多时,文字占据更多位置 34 | func specialtest2() { 35 | let alertController = SPAlertController.alertController(withTitle: "请滑动查看更多内容", message: "谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢", preferredStyle: .actionSheet, animationType: .default) 36 | // alertController.minDistanceToEdges = 100 37 | for i in 0..<5 { 38 | let action = SPAlertAction.action(withTitle: "第\(i)个", style: .default) { (action) in 39 | print("点击了第\(i)个") 40 | } 41 | alertController.addAction(action: action) 42 | } 43 | let cancelAction = SPAlertAction.action(withTitle: "取消", style: .cancel) { (action) in 44 | print("点击了cancel") 45 | } 46 | if customBlur { 47 | alertController.customOverlayView = CustomOverlayView() 48 | } 49 | alertController.addAction(action: cancelAction) 50 | self.present(alertController, animated: true, completion: nil) 51 | } 52 | 53 | // 示例28:action上的文字过长(垂直) 54 | func specialtest4() { 55 | let alertController = SPAlertController.alertController(withTitle: "提示", message: "SPAlertControllerStyleAlert样式下2个按钮默认是水平排列,如果存在按钮文字过长,则自动会切换为垂直排列,除非外界设置了'actionAxis'。如果垂直排列后文字依然过长,则会压缩字体适应宽度,压缩到0.5倍封顶", preferredStyle: .alert, animationType: .default) 56 | alertController.messageColor = .red 57 | let action1 = SPAlertAction.action(withTitle: "明白", style: .default) { (action) in 58 | print("点击了明白") 59 | } 60 | let action2 = SPAlertAction.action(withTitle: "我的文字太长了,所以垂直排列显示更多文字,垂直后依然显示不全则压缩字体,压缩到0.5倍封顶", style: .default) { (action) in 61 | print("点击了'上九天揽月,下五洋捉鳖") 62 | } 63 | if customBlur { 64 | alertController.customOverlayView = CustomOverlayView() 65 | } 66 | action2.titleColor = SYSTEM_COLOR 67 | alertController.addAction(action: action1) 68 | alertController.addAction(action: action2) 69 | self.present(alertController, animated: true, completion: nil) 70 | } 71 | // 示例29:action上的文字过长(水平) 72 | func specialtest5() { 73 | let alertController = SPAlertController.alertController(withTitle: "提示", message: "SPAlertControllerStyleAlert样式下2个按钮默认是水平排列,如果存在按钮文字过长,则自动会切换为垂直排列,本例之所以为水平排列,是因为外界设置了'actionAxis'为UILayoutConstraintAxisHorizontal", preferredStyle: .alert, animationType: .default) 74 | alertController.messageColor = .red 75 | alertController.actionAxis = .horizontal 76 | let action1 = SPAlertAction.action(withTitle: "明白", style: .default) { (action) in 77 | print("点击了明白") 78 | } 79 | let action2 = SPAlertAction.action(withTitle: "我的文字太长了,会压缩字体", style: .default) { (action) in 80 | print("点击了'我的文字太长了,会压缩字体") 81 | } 82 | if customBlur { 83 | alertController.customOverlayView = CustomOverlayView() 84 | } 85 | action2.titleColor = SYSTEM_COLOR 86 | alertController.addAction(action: action1) 87 | alertController.addAction(action: action2) 88 | self.present(alertController, animated: true, completion: nil) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Swift_SPAlertController/Swift_SPAlertController/ViewController+background.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+background.swift 3 | // Swift_SPAlertController 4 | // 5 | // Created by lidongxi on 2020/1/14. 6 | // Copyright © 2020 lidongxi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | extension ViewController { 11 | 12 | func background(appearanceStyle: SPBackgroundViewAppearanceStyle) { 13 | 14 | let alertController = SPAlertController.alertController(withTitle: "我是主标题", message: "我是副标题", preferredStyle: .actionSheet) 15 | alertController.needDialogBlur = lookBlur 16 | let action1 = SPAlertAction.action(withTitle: "Default", style: .default) { (action) in 17 | print("点击了Default") 18 | } 19 | let action2 = SPAlertAction.action(withTitle: "Destructive", style: .destructive) { (action) in 20 | print("点击了Destructive") 21 | } 22 | let action3 = SPAlertAction.action(withTitle: "Cancel", style: .cancel) { (action) in 23 | print("点击了Cancel------") 24 | } 25 | 26 | alertController.addAction(action: action1) 27 | alertController.addAction(action: action3) 28 | alertController.addAction(action: action2) 29 | if customBlur { 30 | alertController.customOverlayView = CustomOverlayView() 31 | } else { 32 | if appearanceStyle == .translucent { 33 | // 0.5是半透明(默认),设置1为不透明,0为全透明 34 | alertController.setBackgroundViewAppearanceStyle(appearanceStyle, alpha: 0.5) 35 | } else { 36 | alertController.setBackgroundViewAppearanceStyle(appearanceStyle, alpha: 1.0) 37 | } 38 | } 39 | self.present(alertController, animated: true, completion: nil) 40 | 41 | } 42 | } 43 | --------------------------------------------------------------------------------